From b7f4ba5cf3183623908b6d02b2e826e1910e8c35 Mon Sep 17 00:00:00 2001 From: Christoffer Nissen Date: Wed, 16 Oct 2024 12:27:30 +0200 Subject: [PATCH] Revert "[chore] Update output tables (#114)" This reverts commit fe0978aff692392306d827951c9f6cf810373e1c. --- go.mod | 2 +- go.sum | 4 +- internal/output/table.go | 98 +++------------------ internal/program.go | 166 ++++++++++++++++------------------- pkg/helm/chartOption.go | 32 ++----- pkg/registry/importOption.go | 6 +- pkg/registry/registry.go | 14 +-- 7 files changed, 106 insertions(+), 216 deletions(-) diff --git a/go.mod b/go.mod index babd72d..85634a4 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/docker/buildx v0.16.0 github.com/enescakir/emoji v1.0.0 github.com/hashicorp/go-retryablehttp v0.7.7 - github.com/jedib0t/go-pretty/v6 v6.6.0 + github.com/jedib0t/go-pretty v4.3.0+incompatible github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 github.com/moby/buildkit v0.15.1 github.com/project-copacetic/copacetic v0.7.1-0.20240723231147-beb8c86673a8 diff --git a/go.sum b/go.sum index ed952de..a32bfa6 100644 --- a/go.sum +++ b/go.sum @@ -1004,8 +1004,8 @@ github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jedib0t/go-pretty/v6 v6.6.0 h1:wmZVuAcEkZRT+Aq1xXpE8IGat4vE5WXOMmBpbQqERXw= -github.com/jedib0t/go-pretty/v6 v6.6.0/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= +github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= +github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc= diff --git a/internal/output/table.go b/internal/output/table.go index 9906ed3..f0d6e1e 100644 --- a/internal/output/table.go +++ b/internal/output/table.go @@ -2,7 +2,6 @@ package output import ( "context" - "fmt" "log/slog" "os" "strings" @@ -16,22 +15,21 @@ import ( "github.com/ChristofferNissen/helmper/pkg/util/file" "github.com/ChristofferNissen/helmper/pkg/util/state" "github.com/ChristofferNissen/helmper/pkg/util/terminal" - "github.com/jedib0t/go-pretty/v6/table" + "github.com/jedib0t/go-pretty/table" ) var sc counter.SafeCounter = counter.NewSafeCounter() // create a new table.writer with header and os.Stdout output mirror -func newTable(title string, header table.Row) table.Writer { +func newTable(row table.Row) table.Writer { t := table.NewWriter() - t.SetTitle(title) t.SetOutputMirror(os.Stdout) - t.AppendHeader(header) + t.AppendHeader(row) return t } func renderChartTable(rows []table.Row) { - t := newTable("Charts", table.Row{"#", "Type", "Chart", "Version", "Latest Version", "Latest", "Values", "SubChart", "Version", "Condition", "Enabled"}) + t := newTable(table.Row{"#", "Type", "Chart", "Version", "Latest Version", "Latest", "Values", "SubChart", "Version", "Condition", "Enabled"}) t.AppendRows(rows) t.SortBy([]table.SortBy{ {Number: 1, Mode: table.AscNumeric}, @@ -113,13 +111,13 @@ func RenderChartTable(charts *helm.ChartCollection, setters ...Option) { func RenderHelmValuePathToImageTable(chartImageHelmValuesMap map[helm.Chart]map[*registry.Image][]string) { // Print Helm values to be set for each chart - t := newTable("Helm Values Paths Per Image", table.Row{"#", "Helm Chart", "Chart Version", "Image", "Helm Value Path(s)"}) + t := newTable(table.Row{"#", "Helm Chart", "Chart Version", "Helm Value Path", "Image"}) id := 0 for c, v := range chartImageHelmValuesMap { for i, paths := range v { ref, _ := i.String() noSHA := strings.SplitN(ref, "@", 2)[0] - t.AppendRow(table.Row{id, c.Name, c.Version, noSHA, strings.Join(paths, "\n")}) + t.AppendRow(table.Row{id, c.Name, c.Version, strings.Join(paths, "\n"), noSHA}) id = id + 1 } } @@ -152,7 +150,7 @@ func getImportTableRows(ctx context.Context, viper *viper.Viper, registries []re // Create collection of registry names as keys for iterating registries keys := make([]string, 0) for _, r := range registries { - keys = append(keys, r.URL) + keys = append(keys, r.GetName()) } // Combine results @@ -165,12 +163,8 @@ func getImportTableRows(ctx context.Context, viper *viper.Viper, registries []re // make sure we don't parse again seenImages = append(seenImages, *i) - name, err := i.ImageName() - if err != nil { - return []table.Row{}, err - } // check if image exists in registry - m := registry.Exists(ctx, name, i.Tag, registries) + m := registry.Exists(ctx, i, registries) // add row to overview table ref, _ := i.String() @@ -184,6 +178,7 @@ func getImportTableRows(ctx context.Context, viper *viper.Viper, registries []re } func RenderImageOverviewTable(ctx context.Context, viper *viper.Viper, missing int, registries []registry.Registry, chartImageValuesMap map[helm.Chart]map[*registry.Image][]string) error { + rows, err := getImportTableRows(ctx, viper, registries, chartImageValuesMap) if err != nil { return err @@ -200,86 +195,19 @@ func RenderImageOverviewTable(ctx context.Context, viper *viper.Viper, missing i // dynamic number of registries for _, r := range registries { - header = append(header, r.GetName()) - footer = append(footer, "") - - if ic.Import.Enabled { - // second static part of header - header = append(header, "import") - footer = append(footer, sc.Value(r.URL)) - } - } - - // construct tab"test"le - t := newTable("Registry Overview For Charts", header) - t.AppendRows(rows) - t.AppendFooter(footer) - t.Render() - - return nil -} - -func RenderChartOverviewTable(ctx context.Context, viper *viper.Viper, missing int, registries []registry.Registry, charts helm.ChartCollection) error { - - // Create collection of registry names as keys for iterating registries - keys := make([]string, 0) - for _, r := range registries { - keys = append(keys, r.URL) - } - - // Combine results - rows := make([]table.Row, 0) - for _, c := range charts.Charts { - // check if image exists in registry - m := registry.Exists(ctx, fmt.Sprintf("charts/%s", c.Name), c.Version, registries) - - // add row to overview table - row := func() table.Row { - row := table.Row{} - row = append(row, sc.Value("index_import_charts"), c.Name, c.Version) - - for _, key := range keys { - row = append(row, terminal.StatusEmoji(m[key])) - ic := state.GetValue[bootstrap.ImportConfigSection](viper, "importConfig") - if ic.Import.Enabled { - b := state.GetValue[bool](viper, "all") || !m[key] - if b { - sc.Inc(key + "charts") - } - row = append(row, terminal.StatusEmoji(b)) - } - } - - sc.Inc("index_import_charts") - return row - }() - - rows = append(rows, row) - } - - header := table.Row{} - footer := table.Row{} - - // first static part of header - header = append(header, "#", "Helm Chart", "Chart Version") - footer = append(footer, "", "", "") - - ic := state.GetValue[bootstrap.ImportConfigSection](viper, "importConfig") - - // dynamic number of registries - for _, r := range registries { - header = append(header, r.GetName()) + name := r.GetName() + header = append(header, name) footer = append(footer, "") if ic.Import.Enabled { // second static part of header header = append(header, "import") - footer = append(footer, sc.Value(r.URL+"charts")) + footer = append(footer, sc.Value(r.GetName())) } } // construct table - t := newTable("Registry Overview For Images", header) + t := newTable(header) t.AppendRows(rows) t.AppendFooter(footer) t.Render() diff --git a/internal/program.go b/internal/program.go index a0ad853..211e5d0 100644 --- a/internal/program.go +++ b/internal/program.go @@ -28,78 +28,6 @@ var ( date = "unknown" ) -func modify(cm *helm.ChartData, mirrorConfig []bootstrap.MirrorConfigSection) error { - - // modify images according to user specification - for c, m := range *cm { - for i, vs := range m { - r, err := i.String() - if err != nil { - return err - } - - if c.Images != nil { - for _, e := range c.Images.Exclude { - if strings.HasPrefix(r, e.Ref) { - delete(m, i) - slog.Info("excluded image", slog.String("image", r)) - break - } - } - for _, ec := range c.Images.ExcludeCopacetic { - if strings.HasPrefix(r, ec.Ref) { - slog.Info("excluded image from copacetic patching", slog.String("image", r)) - f := false - i.Patch = &f - break - } - } - for _, modify := range c.Images.Modify { - if modify.From != "" { - - if strings.HasPrefix(r, modify.From) { - delete(m, i) - - img, err := registry.RefToImage( - strings.Replace(r, modify.From, modify.To, 1), - ) - if err != nil { - return err - } - - img.Digest = i.Digest - img.UseDigest = i.UseDigest - img.Tag = i.Tag - img.Patch = i.Patch - - m[&img] = vs - - newR, err := img.String() - if err != nil { - return err - } - slog.Info("modified image reference", slog.String("old_image", r), slog.String("new_image", newR)) - } - } - } - } - - // Replace mirrors - ms, err := slices.Filter(mirrorConfig, func(m bootstrap.MirrorConfigSection) (bool, error) { - return m.Registry == i.Registry, nil - }) - if err != nil { - return err - } - - if len(ms) > 0 { - i.Registry = ms[0].Mirror - } - } - } - return nil -} - func Program(args []string) error { ctx := context.TODO() @@ -153,7 +81,7 @@ func Program(args []string) error { return err } // Output overview table of charts and subcharts - go output.RenderChartTable( + output.RenderChartTable( &charts, output.Update(update), ) @@ -173,9 +101,72 @@ func Program(args []string) error { return err } - err = modify(&chartImageHelmValuesMap, mirrorConfig) - if err != nil { - return err + // modify images according to user specification + for c, m := range chartImageHelmValuesMap { + for i, vs := range m { + r, err := i.String() + if err != nil { + return err + } + + if c.Images != nil { + for _, e := range c.Images.Exclude { + if strings.HasPrefix(r, e.Ref) { + delete(m, i) + slog.Info("excluded image", slog.String("image", r)) + break + } + } + for _, ec := range c.Images.ExcludeCopacetic { + if strings.HasPrefix(r, ec.Ref) { + slog.Info("excluded image from copacetic patching", slog.String("image", r)) + f := false + i.Patch = &f + break + } + } + for _, modify := range c.Images.Modify { + if modify.From != "" { + + if strings.HasPrefix(r, modify.From) { + delete(m, i) + + img, err := registry.RefToImage( + strings.Replace(r, modify.From, modify.To, 1), + ) + if err != nil { + return err + } + + img.Digest = i.Digest + img.UseDigest = i.UseDigest + img.Tag = i.Tag + img.Patch = i.Patch + + m[&img] = vs + + newR, err := img.String() + if err != nil { + return err + } + slog.Info("modified image reference", slog.String("old_image", r), slog.String("new_image", newR)) + } + } + } + } + + // Replace mirrors + ms, err := slices.Filter(mirrorConfig, func(m bootstrap.MirrorConfigSection) (bool, error) { + return m.Registry == i.Registry, nil + }) + if err != nil { + return err + } + + if len(ms) > 0 { + i.Registry = ms[0].Mirror + } + } } // Add in images from config @@ -190,14 +181,12 @@ func Program(args []string) error { chartImageHelmValuesMap[placeHolder] = m // Output table of image to helm chart value path - go func() { - output.RenderHelmValuePathToImageTable(chartImageHelmValuesMap) - slog.Debug("Parsing of user specified chart(s) completed") - }() + output.RenderHelmValuePathToImageTable(chartImageHelmValuesMap) + slog.Debug("Parsing of user specified chart(s) completed") // STEP 3: Validate and correct image references from charts slog.Debug("Checking presence of images from chart(s) in registries...") - cs, imgs, err := helm.IdentifyImportCandidates( + imgs, err := helm.IdentifyImportCandidates( ctx, registries, chartImageHelmValuesMap, @@ -206,13 +195,6 @@ func Program(args []string) error { if err != nil { return err } - _ = output.RenderChartOverviewTable( - ctx, - viper, - len(charts.Charts), - registries, - charts, - ) // Output table of image status in registries _ = output.RenderImageOverviewTable( ctx, @@ -225,10 +207,10 @@ func Program(args []string) error { // Import charts to registries switch { - case importConfig.Import.Enabled && len(cs.Charts) > 0: + case importConfig.Import.Enabled && len(charts.Charts) > 0: err := helm.ChartImportOption{ Registries: registries, - ChartCollection: &cs, + ChartCollection: &charts, All: all, ModifyRegistry: importConfig.Import.ReplaceRegistryReferences, }.Run(ctx, opts...) @@ -239,7 +221,7 @@ func Program(args []string) error { if importConfig.Import.Cosign.Enabled { slog.Debug("Cosign enabled") signo := mySign.SignChartOption{ - ChartCollection: &cs, + ChartCollection: &charts, Registries: registries, KeyRef: importConfig.Import.Cosign.KeyRef, @@ -294,7 +276,7 @@ func Program(args []string) error { if err != nil { return err } - slog.Debug("image should not be patched", + slog.Debug("User defined image should not be patched", slog.String("image", ref)) push = append(push, &i) continue diff --git a/pkg/helm/chartOption.go b/pkg/helm/chartOption.go index 5e739df..adae394 100644 --- a/pkg/helm/chartOption.go +++ b/pkg/helm/chartOption.go @@ -23,30 +23,13 @@ import ( type ChartData map[Chart]map[*registry.Image][]string // Converts data structure to pipeline parameters -func IdentifyImportCandidates(ctx context.Context, registries []registry.Registry, chartImageValuesMap ChartData, all bool) (ChartCollection, []registry.Image, error) { +func IdentifyImportCandidates(ctx context.Context, registries []registry.Registry, chartImageValuesMap ChartData, all bool) ([]registry.Image, error) { // Combine results imgs := make([]registry.Image, 0) - cs := make([]Chart, 0) var seenImages []registry.Image = make([]registry.Image, 0) - for c, imageMap := range chartImageValuesMap { - - if all || func(rs []registry.Registry) bool { - importChart := false - registryChartStatusMap := registry.Exists(ctx, fmt.Sprintf("charts/%s", c.Name), c.Version, rs) - // loop over registries - for _, r := range rs { - existsInRegistry := registryChartStatusMap[r.URL] - importChart = importChart || !existsInRegistry - } - return importChart - }(registries) { - if c.Name != "images" { - cs = append(cs, c) - } - } - + for _, imageMap := range chartImageValuesMap { for i := range imageMap { if i.In(seenImages) { ref, _ := i.String() @@ -59,25 +42,22 @@ func IdentifyImportCandidates(ctx context.Context, registries []registry.Registr // decide if image should be imported if all || func(rs []registry.Registry) bool { importImage := false - name, err := i.ImageName() - if err != nil { - return false - } // check if image exists in registry - registryImageStatusMap := registry.Exists(ctx, name, i.Tag, rs) + registryImageStatusMap := registry.Exists(ctx, i, rs) // loop over registries for _, r := range rs { - imageExistsInRegistry := registryImageStatusMap[r.URL] + imageExistsInRegistry := registryImageStatusMap[r.GetName()] importImage = importImage || !imageExistsInRegistry } return importImage }(registries) { imgs = append(imgs, *i) } + } } - return ChartCollection{Charts: cs}, imgs, nil + return imgs, nil } // channels to share data between goroutines diff --git a/pkg/registry/importOption.go b/pkg/registry/importOption.go index c0253f0..3239e2a 100644 --- a/pkg/registry/importOption.go +++ b/pkg/registry/importOption.go @@ -42,11 +42,7 @@ func (io ImportOption) Run(ctx context.Context) error { eg, egCtx := errgroup.WithContext(ctx) for _, i := range io.Imgs { - name, err := i.ImageName() - if err != nil { - return err - } - status := Exists(ctx, name, i.Tag, io.Registries) + status := Exists(ctx, i, io.Registries) func(i *Image) { eg.Go(func() error { diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go index c23770e..17f6720 100644 --- a/pkg/registry/registry.go +++ b/pkg/registry/registry.go @@ -177,19 +177,23 @@ func (r Registry) Exist(ctx context.Context, name string, tag string) (bool, err return Exist(ctx, strings.Join([]string{r.URL, name}, "/"), tag, r.PlainHTTP) } -func Exists(ctx context.Context, ref string, tag string, registries []Registry) map[string]bool { +func Exists(ctx context.Context, img *Image, registries []Registry) map[string]bool { m := make(map[string]bool, len(registries)) for _, r := range registries { - exists := func(r Exister) bool { - exists, err := r.Exist(ctx, ref, tag) + exists := func(img *Image, r Exister) bool { + name, err := img.ImageName() + if err != nil { + return false + } + exists, err := r.Exist(ctx, name, img.Tag) if err != nil { return false } return exists - }(r) + }(img, r) - m[r.URL] = exists + m[r.GetName()] = exists } return m