Add `oci://` prefix

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
pull/2971/head
Stefan Prodan 3 years ago
parent adc7981f22
commit 8049634e4d
No known key found for this signature in database
GPG Key ID: 3299AEB0E4085BAF

@ -175,17 +175,17 @@ jobs:
/tmp/flux delete source git podinfo --silent
- name: flux oci artifacts
run: |
/tmp/flux push artifact localhost:5000/fluxcd/flux:${{ github.sha }} \
/tmp/flux push artifact oci://localhost:5000/fluxcd/flux:${{ github.sha }} \
--path="./manifests" \
--source="${{ github.repositoryUrl }}" \
--revision="${{ github.ref }}/${{ github.sha }}"
/tmp/flux tag artifact localhost:5000/fluxcd/flux:${{ github.sha }} \
/tmp/flux tag artifact oci://localhost:5000/fluxcd/flux:${{ github.sha }} \
--tag latest
/tmp/flux list artifacts localhost:5000/fluxcd/flux
/tmp/flux list artifacts oci://localhost:5000/fluxcd/flux
- name: flux oci repositories
run: |
/tmp/flux create source oci podinfo-oci \
--url ghcr.io/stefanprodan/manifests/podinfo \
--url oci://ghcr.io/stefanprodan/manifests/podinfo \
--tag-semver 6.1.x \
--interval 10m
/tmp/flux create kustomization podinfo-oci \

@ -42,7 +42,7 @@ var createSourceOCIRepositoryCmd = &cobra.Command{
Long: `The create source oci command generates an OCIRepository resource and waits for it to be ready.`,
Example: ` # Create an OCIRepository for a public container image
flux create source oci podinfo \
--url=ghcr.io/stefanprodan/manifests/podinfo \
--url=oci://ghcr.io/stefanprodan/manifests/podinfo \
--tag=6.1.6 \
--interval=10m
`,
@ -67,7 +67,7 @@ func init() {
createSourceOCIRepositoryCmd.Flags().StringVar(&sourceOCIRepositoryArgs.semver, "tag-semver", "", "the OCI artifact tag semver range")
createSourceOCIRepositoryCmd.Flags().StringVar(&sourceOCIRepositoryArgs.digest, "digest", "", "the OCI artifact digest")
createSourceOCIRepositoryCmd.Flags().StringVar(&sourceOCIRepositoryArgs.secretRef, "secret-ref", "", "the name of the Kubernetes image pull secret (type 'kubernetes.io/dockerconfigjson')")
createSourceOCIRepositoryCmd.Flags().StringVar(&sourceOCIRepositoryArgs.secretRef, "service-account", "", "the name of the Kubernetes service account that refers to an image pull secret")
createSourceOCIRepositoryCmd.Flags().StringVar(&sourceOCIRepositoryArgs.serviceAccount, "service-account", "", "the name of the Kubernetes service account that refers to an image pull secret")
createSourceOCIRepositoryCmd.Flags().StringSliceVar(&sourceOCIRepositoryArgs.ignorePaths, "ignore-paths", nil, "set paths to ignore resources (can specify multiple paths with commas: path1,path2)")
createSourceCmd.AddCommand(createSourceOCIRepositoryCmd)

@ -38,12 +38,12 @@ func TestCreateSourceOCI(t *testing.T) {
},
{
name: "export manifest",
args: "create source oci podinfo --url=ghcr.io/stefanprodan/manifests/podinfo --tag=6.1.6 --interval 10m --export",
args: "create source oci podinfo --url=oci://ghcr.io/stefanprodan/manifests/podinfo --tag=6.1.6 --interval 10m --export",
assertFunc: assertGoldenFile("./testdata/oci/export.golden"),
},
{
name: "export manifest with secret",
args: "create source oci podinfo --url=ghcr.io/stefanprodan/manifests/podinfo --tag=6.1.6 --interval 10m --secret-ref=creds --export",
args: "create source oci podinfo --url=oci://ghcr.io/stefanprodan/manifests/podinfo --tag=6.1.6 --interval 10m --secret-ref=creds --export",
assertFunc: assertGoldenFile("./testdata/oci/export_with_secret.golden"),
},
}

@ -30,7 +30,7 @@ var listArtifactsCmd = &cobra.Command{
Long: `The list command fetches the tags and their metadata from a remote OCI repository.
The list command uses the credentials from '~/.docker/config.json'.`,
Example: `# list the artifacts stored in an OCI repository
flux list artifact ghcr.io/org/manifests/app
flux list artifact oci://ghcr.io/org/manifests/app
`,
RunE: listArtifactsCmdRun,
}
@ -41,13 +41,18 @@ func init() {
func listArtifactsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("artifact repository is required")
return fmt.Errorf("artifact repository URL is required")
}
url := args[0]
ociURL := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
url, err := oci.ParseArtifactURL(ociURL)
if err != nil {
return err
}
metas, err := oci.List(ctx, url)
if err != nil {
return err

@ -387,6 +387,9 @@ func resetCmdArgs() {
createArgs = createFlags{}
getArgs = GetFlags{}
sourceHelmArgs = sourceHelmFlags{}
sourceOCIRepositoryArgs = sourceOCIRepositoryFlags{}
sourceGitArgs = sourceGitFlags{}
sourceBucketArgs = sourceBucketFlags{}
secretGitArgs = NewSecretGitFlags()
*kubeconfigArgs.Namespace = rootArgs.defaults.Namespace
}

@ -32,7 +32,7 @@ var pullArtifactCmd = &cobra.Command{
Long: `The pull artifact command downloads and extracts the OCI artifact content to the given path.
The pull command uses the credentials from '~/.docker/config.json'.`,
Example: `# Pull an OCI artifact created by flux from GHCR
flux pull artifact ghcr.io/org/manifests/app:v0.0.1 --output ./path/to/local/manifests
flux pull artifact oci://ghcr.io/org/manifests/app:v0.0.1 --output ./path/to/local/manifests
`,
RunE: pullArtifactCmdRun,
}
@ -50,9 +50,9 @@ func init() {
func pullArtifactCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("artifact name is required")
return fmt.Errorf("artifact URL is required")
}
url := args[0]
ociURL := args[0]
if pullArtifactArgs.output == "" {
return fmt.Errorf("invalid output path %s", pullArtifactArgs.output)
@ -62,6 +62,11 @@ func pullArtifactCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("invalid output path %s", pullArtifactArgs.output)
}
url, err := oci.ParseArtifactURL(ociURL)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()

@ -32,7 +32,7 @@ var pushArtifactCmd = &cobra.Command{
Long: `The push artifact command creates a tarball from the given directory and uploads the artifact to a OCI repository.
The push command uses the credentials from '~/.docker/config.json'.`,
Example: `# Push the local manifests to GHCR
flux push artifact ghcr.io/org/manifests/app:v0.0.1 \
flux push artifact oci://ghcr.io/org/manifests/app:v0.0.1 \
--path="./path/to/local/manifests" \
--source="$(git config --get remote.origin.url)" \
--revision="$(git branch --show-current)/$(git rev-parse HEAD)"
@ -57,9 +57,9 @@ func init() {
func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("artifact name is required")
return fmt.Errorf("artifact URL is required")
}
url := args[0]
ociURL := args[0]
if pushArtifactArgs.source == "" {
return fmt.Errorf("--source is required")
@ -73,6 +73,11 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("invalid path %q", pushArtifactArgs.path)
}
url, err := oci.ParseArtifactURL(ociURL)
if err != nil {
return err
}
if fs, err := os.Stat(pushArtifactArgs.path); err != nil || !fs.IsDir() {
return fmt.Errorf("invalid path %q", pushArtifactArgs.path)
}

@ -29,7 +29,7 @@ func TestSourceOCI(t *testing.T) {
goldenFile string
}{
{
"create source oci thrfg --url=ghcr.io/stefanprodan/manifests/podinfo --tag=6.1.6 --interval 10m",
"create source oci thrfg --url=oci://ghcr.io/stefanprodan/manifests/podinfo --tag=6.1.6 --interval 10m",
"testdata/oci/create_source_oci.golden",
},
{

@ -29,7 +29,7 @@ var tagArtifactCmd = &cobra.Command{
Long: `The tag artifact command creates tags for the given OCI artifact.
The tag command uses the credentials from '~/.docker/config.json'.`,
Example: `# Tag an artifact version as latest
flux tag artifact ghcr.io/org/manifests/app:v0.0.1 --tag latest
flux tag artifact oci://ghcr.io/org/manifests/app:v0.0.1 --tag latest
`,
RunE: tagArtifactCmdRun,
}
@ -49,12 +49,17 @@ func tagArtifactCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("artifact name is required")
}
url := args[0]
ociURL := args[0]
if len(tagArtifactArgs.tags) < 1 {
return fmt.Errorf("--tag is required")
}
url, err := oci.ParseArtifactURL(ociURL)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()

@ -8,5 +8,5 @@ spec:
interval: 10m0s
ref:
tag: 6.1.6
url: ghcr.io/stefanprodan/manifests/podinfo
url: oci://ghcr.io/stefanprodan/manifests/podinfo

@ -10,5 +10,5 @@ spec:
tag: 6.1.6
secretRef:
name: creds
url: ghcr.io/stefanprodan/manifests/podinfo
url: oci://ghcr.io/stefanprodan/manifests/podinfo

@ -0,0 +1,54 @@
/*
Copyright 2022 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package oci
import (
"fmt"
"strings"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/google/go-containerregistry/pkg/name"
)
// ParseArtifactURL validates the OCI URL and returns the address of the artifact.
func ParseArtifactURL(ociURL string) (string, error) {
if !strings.HasPrefix(ociURL, sourcev1.OCIRepositoryPrefix) {
return "", fmt.Errorf("URL must be in format 'oci://<domain>/<org>/<repo>'")
}
url := strings.TrimPrefix(ociURL, sourcev1.OCIRepositoryPrefix)
if _, err := name.ParseReference(url); err != nil {
return "", fmt.Errorf("'%s' invalid URL: %w", ociURL, err)
}
return url, nil
}
// ParseRepositoryURL validates the OCI URL and returns the address of the artifact repository.
func ParseRepositoryURL(ociURL string) (string, error) {
if !strings.HasPrefix(ociURL, sourcev1.OCIRepositoryPrefix) {
return "", fmt.Errorf("URL must be in format 'oci://<domain>/<org>/<repo>'")
}
url := strings.TrimPrefix(ociURL, sourcev1.OCIRepositoryPrefix)
ref, err := name.ParseReference(url)
if err != nil {
return "", fmt.Errorf("'%s' invalid URL: %w", ociURL, err)
}
return ref.Context().Name(), nil
}

@ -15,4 +15,4 @@ patchesJson6902:
# TODO: remove the hardcoded image when OCIRepository is released
images:
- name: fluxcd/source-controller
newTag: oci-8509ac03
newTag: oci-ba5f5353

Loading…
Cancel
Save