Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Commit

Permalink
adds replace-oci-ref flag (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
jschicktanz authored Oct 6, 2021
1 parent 4dd4a37 commit 9b30256
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ component-cli component-archive remote copy COMPONENT_NAME VERSION --from SOURCE
--recursive Recursively copy the component descriptor and its references. (default true)
--registry-config string path to the dockerconfig.json with the oci registry authentication information
--relative-urls converts all copied oci artifacts to relative urls
--replace-oci-ref strings list of replace expressions in the format left:right. For every resource with accessType == ociRegistry, all occurences of 'left' in the target ref are replaced with 'right' before the upload
--source-artifact-repository string source repository where realtiove oci artifacts are copied from. This is only relevant if artifacts are copied by value and it will be defaulted to the source component repository
--target-artifact-repository string target repository where the artifacts are copied to. This is only relevant if artifacts are copied by value and it will be defaulted to the target component repository
--to string target repository where the components are copied to.
Expand Down
21 changes: 21 additions & 0 deletions pkg/commands/componentarchive/remote/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ type CopyOptions struct {
// ConvertToRelativeOCIReferences configures the cli to write copied artifacts back with a relative reference
ConvertToRelativeOCIReferences bool

// ReplaceOCIRefs contains replace expressions for manipulating upload refs of resources with accessType == ociRegistry
ReplaceOCIRefs []string

// OciOptions contains all exposed options to configure the oci client.
OciOptions ociopts.Options
}
Expand Down Expand Up @@ -110,6 +113,15 @@ func (o *CopyOptions) Run(ctx context.Context, log logr.Logger, fs vfs.FileSyste
}
defer cache.Close()

replaceOCIRefs := map[string]string{}
for _, replace := range o.ReplaceOCIRefs {
splittedReplace := strings.Split(replace, ":")
if len(splittedReplace) != 2 {
return fmt.Errorf("invalid replace expression %s: must have the format left:right", replace)
}
replaceOCIRefs[splittedReplace[0]] = splittedReplace[1]
}

c := Copier{
SrcRepoCtx: cdv2.NewOCIRegistryRepository(o.SourceRepository, ""),
TargetRepoCtx: cdv2.NewOCIRegistryRepository(o.TargetRepository, ""),
Expand All @@ -123,6 +135,7 @@ func (o *CopyOptions) Run(ctx context.Context, log logr.Logger, fs vfs.FileSyste
SourceArtifactRepository: o.SourceArtifactRepository,
TargetArtifactRepository: o.TargetArtifactRepository,
ConvertToRelativeOCIReferences: o.ConvertToRelativeOCIReferences,
ReplaceOCIRefs: replaceOCIRefs,
}

if err := c.Copy(ctx, o.ComponentName, o.ComponentVersion); err != nil {
Expand Down Expand Up @@ -178,6 +191,7 @@ func (o *CopyOptions) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&o.SourceArtifactRepository, "source-artifact-repository", "",
"source repository where realtiove oci artifacts are copied from. This is only relevant if artifacts are copied by value and it will be defaulted to the source component repository")
fs.BoolVar(&o.ConvertToRelativeOCIReferences, "relative-urls", false, "converts all copied oci artifacts to relative urls")
fs.StringSliceVar(&o.ReplaceOCIRefs, "replace-oci-ref", []string{}, "list of replace expressions in the format left:right. For every resource with accessType == "+cdv2.OCIRegistryType+", all occurences of 'left' in the target ref are replaced with 'right' before the upload")
o.OciOptions.AddFlags(fs)
}

Expand Down Expand Up @@ -206,6 +220,8 @@ type Copier struct {
TargetArtifactRepository string
// ConvertToRelativeOCIReferences configures the cli to write copied artifacts back with a relative reference
ConvertToRelativeOCIReferences bool
// ReplaceOCIRefs contains replace expressions for manipulating upload refs of resources with accessType == ociRegistry
ReplaceOCIRefs map[string]string
}

func (c *Copier) Copy(ctx context.Context, name, version string) error {
Expand Down Expand Up @@ -281,6 +297,11 @@ func (c *Copier) Copy(ctx context.Context, name, version string) error {
if err != nil {
return fmt.Errorf("unable to create target oci artifact reference for resource %s: %w", res.Name, err)
}

for old, new := range c.ReplaceOCIRefs {
target = strings.ReplaceAll(target, old, new)
}

log.V(4).Info(fmt.Sprintf("copy oci artifact %s to %s", ociRegistryAcc.ImageReference, target))
if err := ociclient.Copy(ctx, c.OciClient, ociRegistryAcc.ImageReference, target); err != nil {
return fmt.Errorf("unable to copy oci artifact %s from %s to %s: %w", res.Name, ociRegistryAcc.ImageReference, target, err)
Expand Down
65 changes: 65 additions & 0 deletions pkg/commands/componentarchive/remote/remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,71 @@ var _ = Describe("Remote", func() {
Expect(acc.ImageReference).To(ContainSubstring("gardener-project/landscaper/charts/landscaper-controller:v0.11.0"))
})

It("should replace parts of the target ref of copied docker image resource", func() {
ctx := context.Background()
ociCache, err := cache.NewCache(logr.Discard())
Expect(err).ToNot(HaveOccurred())

cd := &cdv2.ComponentDescriptor{}
cd.Name = "example.com/my-test-component"
cd.Version = "v0.0.1"
cd.Provider = cdv2.InternalProvider
Expect(cdv2.InjectRepositoryContext(cd, cdv2.NewOCIRegistryRepository(srcRepoCtxURL, "")))

remoteOCIImage := cdv2.Resource{}
remoteOCIImage.Name = "component-cli-image"
remoteOCIImage.Version = "v0.28.0"
remoteOCIImage.Type = cdv2.OCIImageType
remoteOCIImage.Relation = cdv2.ExternalRelation
remoteOCIImageAcc, err := cdv2.NewUnstructured(cdv2.NewOCIRegistryAccess("eu.gcr.io/gardener-project/component/cli:v0.28.0"))
Expect(err).ToNot(HaveOccurred())
remoteOCIImage.Access = &remoteOCIImageAcc
cd.Resources = append(cd.Resources, remoteOCIImage)

manifest, err := cdoci.NewManifestBuilder(ociCache, ctf.NewComponentArchive(cd, memoryfs.New())).Build(ctx)
Expect(err).ToNot(HaveOccurred())
ref, err := components.OCIRef(cd.GetEffectiveRepositoryContext(), cd.Name, cd.Version)
Expect(err).ToNot(HaveOccurred())
Expect(client.PushManifest(ctx, ref, manifest, ociclient.WithStore(ociCache)))

baseFs, err := projectionfs.New(osfs.New(), "../")
Expect(err).ToNot(HaveOccurred())
testdataFs = layerfs.New(memoryfs.New(), baseFs)

cf, err := testenv.GetConfigFileBytes()
Expect(err).ToNot(HaveOccurred())
Expect(vfs.WriteFile(testdataFs, "/auth.json", cf, os.ModePerm))

copyOpts := &remote.CopyOptions{
OciOptions: options.Options{
AllowPlainHttp: false,
RegistryConfigPath: "/auth.json",
},
ComponentName: cd.Name,
ComponentVersion: cd.Version,
SourceRepository: srcRepoCtxURL,
TargetRepository: targetRepoCtxURL,
CopyByValue: true,
TargetArtifactRepository: targetRepoCtxURL,
ReplaceOCIRefs: []string{
"gardener-project:my-project",
"component/cli:component-cli",
},
}
Expect(copyOpts.Run(ctx, logr.Discard(), testdataFs)).To(Succeed())

compResolver := cdoci.NewResolver(client)
targetComp, err := compResolver.Resolve(ctx, cdv2.NewOCIRegistryRepository(targetRepoCtxURL, ""), cd.Name, cd.Version)
Expect(err).ToNot(HaveOccurred())

Expect(targetComp.Resources).To(HaveLen(1))

acc := &cdv2.OCIRegistryAccess{}
Expect(targetComp.Resources[0].Access.DecodeInto(acc)).To(Succeed())
Expect(acc.ImageReference).To(ContainSubstring(targetRepoCtxURL))
Expect(acc.ImageReference).To(ContainSubstring("my-project/component-cli:v0.28.0"))
})

It("should copy a component descriptor with a relative oci ref and convert it to a absolute path", func() {
ctx := context.Background()
ociCache, err := cache.NewCache(logr.Discard())
Expand Down

0 comments on commit 9b30256

Please sign in to comment.