Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement --push-repository flag #94

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 43 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,22 @@ Wrapping a chart consists of packaging the chart into a tar.gz, including all co
Even more exciting, we don't need to download the Helm chart for wrapping it. We can point the tool to any reachable Helm chart and the tool will take care of packaging and downloading everything for us. For example:

```console
$ helm dt wrap oci://docker.io/bitnamicharts/kibana
$ helm dt wrap oci://docker.io/bitnamicharts/kibana --version 11.2.23
» Wrapping Helm chart "oci://docker.io/bitnamicharts/kibana"
✔ Helm chart downloaded to "/var/folders/mn/j41xvgsx7l90_hn0hlwj9p180000gp/T/chart-1177363375/chart-1516625348/kibana"
✔ Images.lock file "/var/folders/mn/j41xvgsx7l90_hn0hlwj9p180000gp/T/chart-1177363375/chart-1516625348/kibana/Images.lock" does not exist
✔ Images.lock file written to "/var/folders/mn/j41xvgsx7l90_hn0hlwj9p180000gp/T/chart-1177363375/chart-1516625348/kibana/Images.lock"
» Pulling images into "/var/folders/mn/j41xvgsx7l90_hn0hlwj9p180000gp/T/chart-1177363375/chart-1516625348/kibana/images"
✔ All images pulled successfully
✔ Helm chart wrapped to "/tmp/workspace/kibana/kibana-10.4.8.wrap.tgz"
🎉 Helm chart wrapped into "/tmp/workspace/kibana/kibana-10.4.8.wrap.tgz"
✔ Helm chart wrapped to "/tmp/workspace/kibana/kibana-11.2.23.wrap.tgz"
🎉 Helm chart wrapped into "/tmp/workspace/kibana/kibana-11.2.23.wrap.tgz"
```

Note that depending on the number of images needed by the Helm chart (remember, a wrap has the full set of image dependencies, not only the ones set on _values.yaml_) the size of the generated wrap might be considerably large:

```console
$ ls -l kibana-10.4.8.wrap.tgz
-rw-r--r-- 1 martinpe staff 731200979 Aug 4 15:17 kibana-10.4.8.wrap.tgz
$ ls -l kibana-11.2.23.wrap.tgz
-rw-r--r-- 1 martinpe staff 731200979 Aug 4 15:17 kibana-11.2.23.wrap.tgz
```

If you want to make changes on the Helm chart, you can pass a directory to the wrap command. For example, if we wanted to wrap the previously pulled mariadb Helm chart, we could just do:
Expand All @@ -120,14 +120,14 @@ Currently, `dt` supports moving artifacts that follow certain conventions. That
For example:

```console
$ helm dt wrap --fetch-artifacts oci://docker.io/bitnamicharts/kibana
$ helm dt wrap --fetch-artifacts oci://docker.io/bitnamicharts/kibana --version 11.2.23
...
🎉 Helm chart wrapped into "/tmp/workspace/distribution-tooling-for-helm/kibana-10.4.8.wrap.tgz"
🎉 Helm chart wrapped into "/tmp/workspace/distribution-tooling-for-helm/kibana-11.2.23.wrap.tgz"

$ tar -tzf "/tmp/workspace/distribution-tooling-for-helm/kibana-10.4.8.wrap.tgz" | grep artifacts
kibana-10.4.8/artifacts/images/kibana/kibana/8.10.4-debian-11-r0.sig
kibana-10.4.8/artifacts/images/kibana/kibana/8.10.4-debian-11-r0.metadata
kibana-10.4.8/artifacts/images/kibana/kibana/8.10.4-debian-11-r0.metadata.sig
$ tar -tzf "/tmp/workspace/distribution-tooling-for-helm/kibana-11.2.23.wrap.tgz" | grep artifacts
kibana-11.2.23/artifacts/images/kibana/kibana/8.15.2-debian-12-r0.sig
kibana-11.2.23/artifacts/images/kibana/kibana/8.15.2-debian-12-r0.metadata
kibana-11.2.23/artifacts/images/kibana/kibana/8.15.2-debian-12-r0.metadata.sig
...
```

Expand Down Expand Up @@ -156,14 +156,14 @@ Unwrapping a Helm chart can be done either to a local folder or to a target OCI
At that moment your Helm chart will be ready to be used from the target registry without any dependencies to the source. By default, the tool will run in dry-run mode and require you to confirm actions but you can speed everything up with the `--yes` parameter.

```console
$ helm dt unwrap kibana-10.4.8.wrap.tgz demo.goharbor.io/helm-plugin/ --yes
» Unwrapping Helm chart "kibana-10.4.8.wrap.tgz"
$ helm dt unwrap kibana-11.2.23.wrap.tgz demo.goharbor.io/helm-plugin/ --yes --version 11.2.23
» Unwrapping Helm chart "kibana-11.2.23.wrap.tgz"
✔ Helm chart uncompressed to "/var/folders/mn/j41xvgsx7l90_hn0hlwj9p180000gp/T/chart-586072428/at-wrap2428431258"
✔ Helm chart relocated successfully
» The wrap includes the following 2 images:

demo.goharbor.io/helm-plugin/bitnami/kibana:8.9.0-debian-11-r9
demo.goharbor.io/helm-plugin/bitnami/os-shell:11-debian-11-r25
demo.goharbor.io/helm-plugin/bitnami/kibana:8.15.2-debian-12-r0
demo.goharbor.io/helm-plugin/bitnami/os-shell:12-debian-12-r30

» Pushing Images
✔ All images pushed successfully
Expand All @@ -176,6 +176,34 @@ $ helm dt unwrap kibana-10.4.8.wrap.tgz demo.goharbor.io/helm-plugin/ --yes

If your wrap includes bundled artifacts (if you wrapped it using the `--fetch-artifacts` flag), they will be also pushed to the remote registry.

Unwrapping a Helm chart to a different target than the original using `--push-repository` flag.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use a new header before explaining this new flag?

Also, I find this sentence confusing. What's "the original" here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I wanted to refer to helm dt unwrap oci://original_repo.
Perhaps unwrapping target ? Or what do you recommend?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like Unwrapping a Helm chart to a different registry than the one used on relocation or Using different registries for distribution and relocation?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would also be nice to add some context on why this is needed. Something like:

Sometimes you might need the content on the Helm chart pointing to a registry different than where the Helm chart needs to be pushed to. This is common for example on Airgap environments where a Helm chart might need to be pushed to an interim environment different from where it is meant to be consumed from, or for example in edge distribution channels where the Helm charts might need to be moved from an interim release registry into an edge registry for general public usage.

By unwrapping the Helm chart to a target OCI registry the `dt` tool will unwrap the wrapped file, proceed to push the container
images into the registry you have specified by `--push-repository`, relocate the references from the Helm chart and preserve the original target
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silly comment. For consistency it would be great if you can remove this line breaks on any single paragraph.

registry.
Finally will push the relocated Helm chart to the registry you have specified on `--push-repository` as well when `--push-chart-url` is not used.


```console
$ helm dt ./kibana-11.2.23.wrap.tgz demo.goharbor.io/read/helm-plugin --push-repository demo.goharbor.io/write/helm-plugin --push-chart-url demo.goharbor.io/write/helm-plugin/bitnami
» Unwrapping Helm chart "./kibana-11.2.23.wrap.tgz"
✔ Helm chart uncompressed to "/var/folders/s1/7qw_wynd0ljdwf9l51dbs2cm0000gq/T/chart-1986792895/dt-wrap174906721"
✔ Helm chart relocated successfully
» The wrap includes the following 2 images:

demo.goharbor.io/read/helm-plugin/bitnami/kibana:8.15.2-debian-12-r0q
demo.goharbor.io/read/helm-plugin/bitnami/os-shell:12-debian-12-r30

Do you want to push the wrapped images to the OCI registry? [y/N]: Yes
» Pushing Images
✔ All images pushed successfully
✔ Chart "/var/folders/s1/7qw_wynd0ljdwf9l51dbs2cm0000gq/T/chart-1986792895/dt-wrap174906721/chart" lock is valid

Do you want to push the Helm chart to the OCI registry? [y/N]: Yes
✔ Helm chart successfully pushed

🎉 Helm chart unwrapped successfully: You can use it now by running "helm install oci://demo.goharbor.io/read/helm-plugin/kibana --generate-name --version 11.2.23"
```

## Advanced Usage

That was all as per the basic most basic and powerful usage. If you're interested in some other additional goodies then we will dig next into some specific finer-grained commands.
Expand Down
2 changes: 1 addition & 1 deletion cmd/dt/annotate/annotate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

// NewCmd builds a new annotate command
func NewCmd(cfg *config.Config) *cobra.Command {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid this kind of changes (this applies to other files) so the PR only shows the code you actually changed

return &cobra.Command{
Use: "annotate CHART_PATH",
Short: "Annotates a Helm chart (Experimental)",
Expand All @@ -32,7 +33,6 @@ Use it cautiously. Very often the complete list of images cannot be guessed from
chartutils.WithAnnotationsKey(cfg.AnnotationsKey),
chartutils.WithLog(l),
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

})

if err != nil {
Expand Down
10 changes: 6 additions & 4 deletions cmd/dt/push/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ import (
)

// ChartImages pushes the images from the Images.lock
func ChartImages(wrap wrapping.Wrap, imagesDir string, opts ...chartutils.Option) error {
return pushImages(wrap, imagesDir, opts...)
func ChartImages(wrap wrapping.Wrap, imagesDir string, registryURL string, pushRepository string, opts ...chartutils.Option) error {
return pushImages(wrap, imagesDir, registryURL, pushRepository, opts...)
}

func pushImages(wrap wrapping.Wrap, imagesDir string, opts ...chartutils.Option) error {
func pushImages(wrap wrapping.Wrap, imagesDir string, registryURL string, pushRepository string, opts ...chartutils.Option) error {
lock, err := wrap.GetImagesLock()
if err != nil {
return fmt.Errorf("failed to load Images.lock: %v", err)
}

return chartutils.PushImages(lock, imagesDir, opts...)
return chartutils.PushImages(lock, imagesDir, registryURL, pushRepository, opts...)
}

// NewCmd builds a new push command
Expand Down Expand Up @@ -62,6 +62,8 @@ func NewCmd(cfg *config.Config) *cobra.Command {
if err := pushImages(
chart,
imagesDir,
"",
"",
chartutils.WithLog(silent.NewLogger()),
chartutils.WithContext(ctx),
chartutils.WithProgressBar(subLog.ProgressBar()),
Expand Down
1 change: 1 addition & 0 deletions cmd/dt/relocate/relocate.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

// NewCmd builds a new relocate command
func NewCmd(cfg *config.Config) *cobra.Command {

valuesFiles := []string{"values.yaml"}
skipImageRelocation := false
cmd := &cobra.Command{
Expand Down
66 changes: 43 additions & 23 deletions cmd/dt/unwrap/unwrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"regexp"
"strings"

"github.com/spf13/cobra"
"github.com/vmware-labs/distribution-tooling-for-helm/cmd/dt/config"
Expand All @@ -18,10 +19,8 @@ import (
"github.com/vmware-labs/distribution-tooling-for-helm/pkg/chartutils"
"github.com/vmware-labs/distribution-tooling-for-helm/pkg/imagelock"
"github.com/vmware-labs/distribution-tooling-for-helm/pkg/log"
"github.com/vmware-labs/distribution-tooling-for-helm/pkg/log/silent"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: undo reordering


"github.com/vmware-labs/distribution-tooling-for-helm/pkg/log/logrus"

"github.com/vmware-labs/distribution-tooling-for-helm/pkg/log/silent"
"github.com/vmware-labs/distribution-tooling-for-helm/pkg/relocator"
"github.com/vmware-labs/distribution-tooling-for-helm/pkg/utils"
"github.com/vmware-labs/distribution-tooling-for-helm/pkg/wrapping"
Expand Down Expand Up @@ -238,8 +237,8 @@ func NewConfig(opts ...Option) *Config {
}

// Chart unwraps a Helm chart
func Chart(inputChart, registryURL, pushChartURL string, opts ...Option) (string, error) {
return unwrapChart(inputChart, registryURL, pushChartURL, opts...)
func Chart(inputChart, registryURL, pushRepository string, pushChartURL string, opts ...Option) (string, *chartutils.Chart, error) {
return unwrapChart(inputChart, registryURL, pushRepository, pushChartURL, opts...)
}

func askYesNoQuestion(msg string, cfg *Config) bool {
Expand All @@ -252,19 +251,20 @@ func askYesNoQuestion(msg string, cfg *Config) bool {
return widgets.ShowYesNoQuestion(msg)
}

func unwrapChart(inputChart, registryURL, pushChartURL string, opts ...Option) (string, error) {
func unwrapChart(inputChart, registryURL, pushRepository string, pushChartURL string, opts ...Option) (string, *chartutils.Chart, error) {

cfg := NewConfig(opts...)

ctx := cfg.Context
parentLog := cfg.GetLogger()

if registryURL == "" {
return "", fmt.Errorf("the registry cannot be empty")
return "", nil, fmt.Errorf("the registry cannot be empty")
}

tempDir, err := cfg.GetTemporaryDirectory()
if err != nil {
return "", fmt.Errorf("failed to create temporary directory: %w", err)
return "", nil, fmt.Errorf("failed to create temporary directory: %w", err)
}

l := parentLog.StartSection(fmt.Sprintf("Unwrapping Helm chart %q", inputChart))
Expand All @@ -284,12 +284,12 @@ func unwrapChart(inputChart, registryURL, pushChartURL string, opts ...Option) (
),
)
if err != nil {
return "", err
return "", nil, err
}

wrap, err := wrapping.Load(chartPath)
if err != nil {
return "", err
return "", nil, err
}
if err := l.ExecuteStep(fmt.Sprintf("Relocating %q with prefix %q", wrap.ChartDir(), registryURL), func() error {
return relocator.RelocateChartDir(
Expand All @@ -298,7 +298,7 @@ func unwrapChart(inputChart, registryURL, pushChartURL string, opts ...Option) (
relocator.WithSkipImageRelocation(cfg.SkipImageRelocation),
)
}); err != nil {
return "", l.Failf("failed to relocate %q: %w", chartPath, err)
return "", nil, l.Failf("failed to relocate %q: %w", chartPath, err)
}
l.Infof("Helm chart relocated successfully")

Expand All @@ -311,23 +311,27 @@ func unwrapChart(inputChart, registryURL, pushChartURL string, opts ...Option) (
}
if askYesNoQuestion(l.PrefixText("Do you want to push the wrapped images to the OCI registry?"), cfg) {
if err := l.Section("Pushing Images", func(subLog log.SectionLogger) error {
return pushChartImagesAndVerify(ctx, wrap, NewConfig(append(opts, WithLogger(subLog))...))
return pushChartImagesAndVerify(ctx, wrap, registryURL, pushRepository, NewConfig(append(opts, WithLogger(subLog))...))
}); err != nil {
return "", l.Failf("Failed to push images: %w", err)
return "", nil, l.Failf("Failed to push images: %w", err)
}
l.Printf(widgets.TerminalSpacer)
}
}

if askYesNoQuestion(l.PrefixText("Do you want to push the Helm chart to the OCI registry?"), cfg) {

if pushChartURL == "" {
pushChartURL = registryURL
// we will push the chart to the same registry as the containers
if pushRepository == "" {
// we will push the chart to the same registry as the containers
pushChartURL = registryURL
} else {
// we will push the chart to the same registry as defined by pushRepository
pushChartURL = pushRepository
}
cfg.Auth = cfg.ContainerRegistryAuth
}
pushChartURL = normalizeOCIURL(pushChartURL)
fullChartURL := fmt.Sprintf("%s/%s", pushChartURL, wrap.Chart().Name())

if err := l.ExecuteStep(fmt.Sprintf("Pushing Helm chart to %q", pushChartURL), func() error {
return utils.ExecuteWithRetry(maxRetries, func(try int, prevErr error) error {
if try > 0 {
Expand All @@ -336,16 +340,24 @@ func unwrapChart(inputChart, registryURL, pushChartURL string, opts ...Option) (
return pushChart(ctx, wrap, pushChartURL, cfg)
})
}); err != nil {
return "", l.Failf("Failed to push Helm chart: %w", err)
return "", nil, l.Failf("Failed to push Helm chart: %w", err)
}

l.Infof("Helm chart successfully pushed")
return fullChartURL, nil

fullChartURL := fmt.Sprintf("%s/%s", pushChartURL, wrap.Chart().Name())

// point chart url to the registryURL if pushRepository is set
if pushRepository != "" && strings.Contains(pushChartURL, pushRepository) {
fullChartURL = strings.Replace(fullChartURL, pushRepository, registryURL, 1)
}

return fullChartURL, wrap.Chart(), nil
}
return "", nil
return "", wrap.Chart(), nil
}

func pushChartImagesAndVerify(ctx context.Context, wrap wrapping.Wrap, cfg *Config) error {
func pushChartImagesAndVerify(ctx context.Context, wrap wrapping.Wrap, registryURL string, pushRepository string, cfg *Config) error {
lockFile := wrap.LockFilePath()

l := cfg.GetLogger()
Expand All @@ -355,6 +367,8 @@ func pushChartImagesAndVerify(ctx context.Context, wrap wrapping.Wrap, cfg *Conf
if err := push.ChartImages(
wrap,
wrap.ImagesDir(),
registryURL,
pushRepository,
chartutils.WithLog(silent.NewLogger()),
chartutils.WithContext(ctx),
chartutils.WithArtifactsDir(wrap.ImageArtifactsDir()),
Expand Down Expand Up @@ -454,10 +468,12 @@ func NewCmd(cfg *config.Config) *cobra.Command {
var (
sayYes bool
pushChartURL string
pushRepository string
version string
skipImageRelocation bool
skipPullImages bool
)

valuesFiles := []string{"values.yaml"}
cmd := &cobra.Command{
Use: "unwrap FILE OCI_URI",
Expand All @@ -480,7 +496,8 @@ func NewCmd(cfg *config.Config) *cobra.Command {
if err != nil {
return fmt.Errorf("failed to create temporary directory: %v", err)
}
fullChartURL, err := unwrapChart(inputChart, registryURL, pushChartURL,

fullChartURL, chart, err := unwrapChart(inputChart, registryURL, pushRepository, pushChartURL,
WithLogger(l),
WithSayYes(sayYes),
WithContext(ctx),
Expand All @@ -496,9 +513,11 @@ func NewCmd(cfg *config.Config) *cobra.Command {
if err != nil {
return err
}

var successMessage = "Helm chart unwrapped successfully"
if fullChartURL != "" {
successMessage = fmt.Sprintf(`%s: You can use it now by running "helm install %s --generate-name"`, successMessage, fullChartURL)
//successMessage = fmt.Sprintf(`%s: You can use it now by running "helm install %s --generate-name"`, successMessage, fullChartURL)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow the index feature did not work in here as i was not able to pull chart without specifying the version

That's mainly the reason for this change. I am not sure why that

successMessage = fmt.Sprintf(`%s: "helm install %s --generate-name --version %s"`, successMessage, fullChartURL, chart.Version())
}
l.Printf(widgets.TerminalSpacer)
l.Successf(successMessage)
Expand All @@ -508,6 +527,7 @@ func NewCmd(cfg *config.Config) *cobra.Command {

cmd.PersistentFlags().StringVar(&version, "version", version, "when unwrapping remote Helm charts from OCI, version to request")
cmd.PersistentFlags().StringVar(&pushChartURL, "push-chart-url", pushChartURL, "push the unwrapped Helm chart to the given URL")
cmd.PersistentFlags().StringVar(&pushRepository, "push-repository", pushRepository, "the repository to be used instead for write operations e.g (demo.goharbor.io/write/test_repo)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess a better parameter name would be push-container-registry, right? I mean, in a given chart there are N potential repositories published in a single registry/namespace, see:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. Unclear to me as the current flag for helm chart is push-chart-url ....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@machecazzon machecazzon Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as oci repos are general purpose not specific to store binary images, charts, or just a file just registry might be a good option. Naming is the hardest in here. Let me know what you will like me to change and to what and I will update PR when that's defined. Thanks for having a look

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd go for sth like this:

	cmd.PersistentFlags().StringVar(&pushContainerRegistry, "push-container-registry", pushContainerRegistry, "push the container images included in the unwrapped Helm chart to the given container registry (including namespace)")

What do you think @mpermar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. I will attempt have this clean up tomorrow. Thanks

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I take it back @machecazzon @juan131. The value can be both a registry and a repository so probably would need some other name like push-uri.

But, actually, while looking in detail to the naming, and this is totally my bad as I am lost touch with this project and it has evolved quite a while since I left it, I can see there is a push-chart-url which I believe it might do exactly what this PR is trying to do.

Copy link
Contributor Author

@machecazzon machecazzon Oct 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have been thinking about this a bit more and I believe that having --values-registry could be more appropriate as is actually what I am looking for.

"Have the values of the chart to be relocated not to the unwrap target but instead the value provided by e.g --values-registry."

That's more like what I did on my first attempt to cover the use case.

Right now I have a custom build with what I need to have the desired outputs that includes this and some other changes and is not a big deal but I would prefer that this tool could support this behaviour.

Back into the naming, kaniko has this switch and it's format somehow make me think of this Thread.

https://github.com/GoogleContainerTools/kaniko?tab=readme-ov-file#flag---registry-map

Very likely I will abandon this PR and come back later with a better solution and better PR hopefully, but if wanted can still try to address this PR comments.

In regards the push-chart-url I am currently using that switch to tune the chart destination path as well as needing this same "feature". This is related to some other "issue" I have with current implementation and patched for good on my end :)

RelocateImageURL method seems that it might change the original path and have something else on the unwrap target depending on the input provided and what the image url is. This turns that image path not be the exactly the same on the destination (apart the registry bits) as the original source what I need to ensure preservation.

My current scenario: GAR Reader / GAR Writer

  • GAR Reader (Virtual Repo) is a able to pull from Gitlab registry
  • dev teams build their images and push to Gitlab registry
  • dt is used to build a wrap on ci ensuring images exist, are pinned (lock/verify) but skip save images that source from Gitlab while still have those on the Images.lock. Chart's are annotated on CI and then wrapped.

dt charts annotate
dt wrap

  • the unwrap target gitlab what relocates chart values to be GAR reader repo instead of the target (in this case) and basically only pushes images that exist on disk what skips the ones that exist on lock but not on disk.
  • then based on some release process a "golden" wrap is built eventually sourcing from gitlab (the result of some unwrap like described above.. ), this wrap will be published/unwrapped to GAR Write repo (configured to have immutable tags). In this case as the source is different than the target is does the usual dt dance (although thinking that can just avoid saving any images on disk and just do a crane copy based on the Images.lock 🤔 ).
  • When this wrap is published it takes over and is what's will be consumed from now on ( if that version is requested ) cutting the link with Gitlab.
  • The chart values are again preserved to be the GAR Reader repo and not the GAR Writer that is the unwrap target
  • The versions available and published on the GAR Writer are the ones that are available and can be consumed for non dev envs

For all the previous to work transparently It's crucial to guarantee images path preservation from Gitlab to GAR and or have controlled rewrite if desired as there are some variants and eventual some restrictions depending on the unwrap target ghcr.io | docker.io | registry.gitlab.com | ....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great context. And wow, you have built a thing there.

I'm approaching your PR here from a point of view of trying to keep the tool as simplest as possible. Ideally I'd like to have very simple building blocks even when that might come at the expense of having extra complexity in the client scripts. It makes this project more sustainable in the long run.

From that perspective I see that helm dt unwrap target-images-registry --push-chart-url=target-chart-registry is giving us two basic primitive arguments: one to set where images are going to be pushed, and a second one to set where the chart is going to be pushed. It can certainly be improved (e.g. kaniko for multi-registry images), but it feels effective enough.

But at the same time I have to be honest here, I'm humbled by your use case and what you are doing. So, I'm not sure if I'm missing anything obvious. Perhaps the right thing to do is as you say to abandon this one and then try to approach it with some simpler baby-step kind of change. Not sure, tbh.

Copy link
Contributor Author

@machecazzon machecazzon Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @mpermar

Sorry for delay getting back.

I ended with something like this

  • build a wrap (from local filesystem "helm chart") that does not pull images but just contain helm chart and Images.lock. Unwrap will basically just push the chart (source registry and target registry are the same) gitlab --> gitlab

  • with the previous wrap (no local images) be able to unwrap to destination registry but copy the referenced docker images as usual while source images instead of being local filesystem be a crane copy from registry source to target (source registry and target registry are not the same) .. in my case gitlab --> gar

  • still have the option to "--create-offline-bundle" where all images pulled/saved locally as usual and wrapped in the wrap

cmd.PersistentFlags().BoolVar(&sayYes, "yes", sayYes, "respond 'yes' to any yes/no question")
cmd.PersistentFlags().StringSliceVar(&valuesFiles, "values", valuesFiles, "values files to relocate images (can specify multiple)")
cmd.PersistentFlags().BoolVar(&skipImageRelocation, "skip-image-relocation", skipImageRelocation, "Skip relocating image references in the different files")
Expand Down
4 changes: 2 additions & 2 deletions cmd/dt/unwrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func testChartUnwrap(t *testing.T, sb *tu.Sandbox, inputChart string, targetRegi
unwrap.WithAuth(cfg.Auth.Username, cfg.Auth.Password),
unwrap.WithContainerRegistryAuth(cfg.ContainerRegistryAuth.Username, cfg.ContainerRegistryAuth.Password),
}
_, err := unwrap.Chart(inputChart, targetRegistry, chartTargetRegistry, opts...)
_, _, err := unwrap.Chart(inputChart, targetRegistry, "", chartTargetRegistry, opts...)
require.NoError(t, err)
} else {
dt(args...).AssertSuccessMatch(t, "")
Expand Down Expand Up @@ -257,7 +257,7 @@ func (suite *CmdSuite) TestUnwrapCommand() {
unwrap.WithSayYes(true),
unwrap.WithContainerRegistryAuth(username, password),
}
_, err := unwrap.Chart(wrapDir, targetRegistry, "", opts...)
_, _, err := unwrap.Chart(wrapDir, targetRegistry, "", "", opts...)
require.NoError(err)
} else {
dt(args...).AssertSuccessMatch(suite.T(), "")
Expand Down
2 changes: 2 additions & 0 deletions cmd/dt/wrap/wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,10 @@ func NewCmd(cfg *config.Config) *cobra.Command {
var platforms []string
var fetchArtifacts bool
var carvelize bool

var skipPullImages bool
var examples = ` # Wrap a Helm chart from a local folder

$ dt wrap examples/mariadb

# Wrap a Helm chart in an OCI registry
Expand Down
Loading