From a8db3be02b823f19179519393ae6f46df9f650e9 Mon Sep 17 00:00:00 2001 From: Igor Zibarev Date: Mon, 18 Jun 2018 15:23:29 +0300 Subject: [PATCH 01/29] ref(helm): expose Get for repository file Get method is a useful shortcut that can be used by other apps that use helm repo package. --- pkg/repo/repo.go | 14 +++++++++---- pkg/repo/repo_test.go | 47 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/pkg/repo/repo.go b/pkg/repo/repo.go index 194eace79..dfe2d9ed2 100644 --- a/pkg/repo/repo.go +++ b/pkg/repo/repo.go @@ -116,12 +116,18 @@ func (r *RepoFile) Update(re ...*Entry) { // Has returns true if the given name is already a repository name. func (r *RepoFile) Has(name string) bool { - for _, rf := range r.Repositories { - if rf.Name == name { - return true + _, ok := r.Get(name) + return ok +} + +// Get returns entry by the given name if it exists. +func (r *RepoFile) Get(name string) (*Entry, bool) { + for _, entry := range r.Repositories { + if entry.Name == name { + return entry, true } } - return false + return nil, false } // Remove removes the entry from the list of repositories. diff --git a/pkg/repo/repo_test.go b/pkg/repo/repo_test.go index 4b5bcdbf5..a7716102e 100644 --- a/pkg/repo/repo_test.go +++ b/pkg/repo/repo_test.go @@ -16,10 +16,12 @@ limitations under the License. package repo -import "testing" -import "io/ioutil" -import "os" -import "strings" +import ( + "io/ioutil" + "os" + "strings" + "testing" +) const testRepositoriesFile = "testdata/repositories.yaml" @@ -120,6 +122,43 @@ func TestNewPreV1RepositoriesFile(t *testing.T) { } } +func TestRepoFile_Get(t *testing.T) { + repo := NewRepoFile() + repo.Add( + &Entry{ + Name: "first", + URL: "https://example.com/first", + Cache: "first-index.yaml", + }, + &Entry{ + Name: "second", + URL: "https://example.com/second", + Cache: "second-index.yaml", + }, + &Entry{ + Name: "third", + URL: "https://example.com/third", + Cache: "third-index.yaml", + }, + &Entry{ + Name: "fourth", + URL: "https://example.com/fourth", + Cache: "fourth-index.yaml", + }, + ) + + name := "second" + + entry, ok := repo.Get(name) + if !ok { + t.Fatalf("Expected repo entry %q to be found", name) + } + + if entry.URL != "https://example.com/second" { + t.Fatalf("Expected repo URL to be %q but got %q", "https://example.com/second", entry.URL) + } +} + func TestRemoveRepository(t *testing.T) { sampleRepository := NewRepoFile() sampleRepository.Add( From d80a96cf77ce40283006d3b7bad0ec5400d83acd Mon Sep 17 00:00:00 2001 From: Christian Koeberl Date: Tue, 16 Oct 2018 13:41:36 +0200 Subject: [PATCH 02/29] fix(pkg/chartutil): conditions for alias and umrella charts (#3734) Enable to use charts with dependencies that have conditions (e.g. in umbrella charts). Allow aliases for dependencies that have dependencies with conditions. Closes #3734 Signed-off-by: Christian Koeberl --- docs/charts.md | 26 +++++++++++++++---- pkg/chartutil/requirements.go | 13 +++++++--- pkg/chartutil/requirements_test.go | 11 +++++++- .../subpop/charts/subchart1/requirements.yaml | 2 +- .../subpop/charts/subchart2/requirements.yaml | 2 +- .../testdata/subpop/requirements.yaml | 6 +++++ pkg/chartutil/testdata/subpop/values.yaml | 2 ++ 7 files changed, 50 insertions(+), 12 deletions(-) diff --git a/docs/charts.md b/docs/charts.md index 7bc4f0020..5870c6d64 100644 --- a/docs/charts.md +++ b/docs/charts.md @@ -258,9 +258,11 @@ All charts are loaded by default. If `tags` or `condition` fields are present, they will be evaluated and used to control loading for the chart(s) they are applied to. Condition - The condition field holds one or more YAML paths (delimited by commas). -If this path exists in the top parent's values and resolves to a boolean value, -the chart will be enabled or disabled based on that boolean value. Only the first -valid path found in the list is evaluated and if no paths exist then the condition has no effect. +If this path exists in the parent's values and resolves to a boolean value, +the chart will be enabled or disabled based on that boolean value. Only the first +valid path found in the list is evaluated and if no paths exist then the condition +has no effect. For multiple level dependencies the condition is prependend by the +path to the parent chart. Tags - The tags field is a YAML list of labels to associate with this chart. In the top parent's values, all charts with tags can be enabled or disabled by @@ -272,7 +274,7 @@ dependencies: - name: subchart1 repository: http://localhost:10191 version: 0.1.0 - condition: subchart1.enabled,global.subchart1.enabled + condition: subchart1.enabled tags: - front-end - subchart1 @@ -280,11 +282,19 @@ dependencies: - name: subchart2 repository: http://localhost:10191 version: 0.1.0 - condition: subchart2.enabled,global.subchart2.enabled + condition: subchart2.enabled tags: - back-end - subchart2 +``` +```yaml +# subchart2/requirements.yaml +dependencies: + - name: subsubchart + repository: http://localhost:10191 + version: 0.1.0 + condition: subsubchart.enabled ``` ```yaml @@ -292,6 +302,9 @@ dependencies: subchart1: enabled: true +subchart2: + subsubchart: + enabled: false tags: front-end: false back-end: true @@ -305,6 +318,9 @@ Since `subchart2` is tagged with `back-end` and that tag evaluates to `true`, `s enabled. Also notes that although `subchart2` has a condition specified in `requirements.yaml`, there is no corresponding path and value in the parent's values so that condition has no effect. +`subsubchart` is disabled by default but can be enabled by setting `subchart2.subsubchart.enabled=true`. +Hint: disabling `subchart2` via tag will also disable all sub-charts (even if overriding the value `subchart2.subsubchart.enabled=true`). + ##### Using the CLI with Tags and Conditions The `--set` parameter can be used as usual to alter tag and condition values. diff --git a/pkg/chartutil/requirements.go b/pkg/chartutil/requirements.go index 0f1128305..ff966111f 100644 --- a/pkg/chartutil/requirements.go +++ b/pkg/chartutil/requirements.go @@ -124,7 +124,7 @@ func LoadRequirementsLock(c *chart.Chart) (*RequirementsLock, error) { } // ProcessRequirementsConditions disables charts based on condition path value in values -func ProcessRequirementsConditions(reqs *Requirements, cvals Values) { +func ProcessRequirementsConditions(reqs *Requirements, cvals Values, cpath string) { var cond string var conds []string if reqs == nil || len(reqs.Dependencies) == 0 { @@ -143,7 +143,7 @@ func ProcessRequirementsConditions(reqs *Requirements, cvals Values) { for _, c := range conds { if len(c) > 0 { // retrieve value - vv, err := cvals.PathValue(c) + vv, err := cvals.PathValue(cpath + c) if err == nil { // if not bool, warn if bv, ok := vv.(bool); ok { @@ -247,6 +247,10 @@ func getAliasDependency(charts []*chart.Chart, aliasChart *Dependency) *chart.Ch // ProcessRequirementsEnabled removes disabled charts from dependencies func ProcessRequirementsEnabled(c *chart.Chart, v *chart.Config) error { + return doProcessRequirementsEnabled(c, v, "") +} + +func doProcessRequirementsEnabled(c *chart.Chart, v *chart.Config, path string) error { reqs, err := LoadRequirements(c) if err != nil { // if not just missing requirements file, return error @@ -303,7 +307,7 @@ func ProcessRequirementsEnabled(c *chart.Chart, v *chart.Config) error { cc := chart.Config{Raw: yvals} // flag dependencies as enabled/disabled ProcessRequirementsTags(reqs, cvals) - ProcessRequirementsConditions(reqs, cvals) + ProcessRequirementsConditions(reqs, cvals, path) // make a map of charts to remove rm := map[string]bool{} for _, r := range reqs.Dependencies { @@ -323,7 +327,8 @@ func ProcessRequirementsEnabled(c *chart.Chart, v *chart.Config) error { } // recursively call self to process sub dependencies for _, t := range cd { - err := ProcessRequirementsEnabled(t, &cc) + subpath := path + t.Metadata.Name + "." + err := doProcessRequirementsEnabled(t, &cc, subpath) // if its not just missing requirements file, return error if nerr, ok := err.(ErrNoRequirementsFile); !ok && err != nil { return nerr diff --git a/pkg/chartutil/requirements_test.go b/pkg/chartutil/requirements_test.go index e433f92ea..f1b0ebdb3 100644 --- a/pkg/chartutil/requirements_test.go +++ b/pkg/chartutil/requirements_test.go @@ -157,7 +157,7 @@ func TestRequirementsCombinedDisabledL2(t *testing.T) { t.Fatalf("Failed to load testdata: %s", err) } // tags enabling a parent/child group with condition disabling one child - v := &chart.Config{Raw: "subchartc:\n enabled: false\ntags:\n back-end: true\n"} + v := &chart.Config{Raw: "subchart2:\n subchartc:\n enabled: false\ntags:\n back-end: true\n"} // expected charts including duplicates in alphanumeric order e := []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb", "subchartb"} @@ -175,6 +175,15 @@ func TestRequirementsCombinedDisabledL1(t *testing.T) { verifyRequirementsEnabled(t, c, v, e) } +func TestRequirementsAliasCondition(t *testing.T) { + c, err := Load("testdata/subpop") + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + v := &chart.Config{Raw: "subchart1:\n enabled: false\nsubchart2alias:\n enabled: true\n subchartb:\n enabled: true\n"} + e := []string{"parentchart", "subchart2alias", "subchartb"} + verifyRequirementsEnabled(t, c, v, e) +} func verifyRequirementsEnabled(t *testing.T, c *chart.Chart, v *chart.Config, e []string) { out := []*chart.Chart{} diff --git a/pkg/chartutil/testdata/subpop/charts/subchart1/requirements.yaml b/pkg/chartutil/testdata/subpop/charts/subchart1/requirements.yaml index abfe85e76..d9383dc4f 100644 --- a/pkg/chartutil/testdata/subpop/charts/subchart1/requirements.yaml +++ b/pkg/chartutil/testdata/subpop/charts/subchart1/requirements.yaml @@ -2,7 +2,7 @@ dependencies: - name: subcharta repository: http://localhost:10191 version: 0.1.0 - condition: subcharta.enabled,subchart1.subcharta.enabled + condition: subcharta.enabled tags: - front-end - subcharta diff --git a/pkg/chartutil/testdata/subpop/charts/subchart2/requirements.yaml b/pkg/chartutil/testdata/subpop/charts/subchart2/requirements.yaml index 1f0023a08..d65d73dcd 100644 --- a/pkg/chartutil/testdata/subpop/charts/subchart2/requirements.yaml +++ b/pkg/chartutil/testdata/subpop/charts/subchart2/requirements.yaml @@ -2,7 +2,7 @@ dependencies: - name: subchartb repository: http://localhost:10191 version: 0.1.0 - condition: subchartb.enabled,subchart2.subchartb.enabled + condition: subchartb.enabled tags: - back-end - subchartb diff --git a/pkg/chartutil/testdata/subpop/requirements.yaml b/pkg/chartutil/testdata/subpop/requirements.yaml index a8eb0aace..a6ee20f07 100644 --- a/pkg/chartutil/testdata/subpop/requirements.yaml +++ b/pkg/chartutil/testdata/subpop/requirements.yaml @@ -29,3 +29,9 @@ dependencies: tags: - back-end - subchart2 + + - name: subchart2 + alias: subchart2alias + repository: http://localhost:10191 + version: 0.1.0 + condition: subchart2alias.enabled diff --git a/pkg/chartutil/testdata/subpop/values.yaml b/pkg/chartutil/testdata/subpop/values.yaml index 55e872d41..68eb1323c 100644 --- a/pkg/chartutil/testdata/subpop/values.yaml +++ b/pkg/chartutil/testdata/subpop/values.yaml @@ -39,3 +39,5 @@ tags: front-end: true back-end: false +subchart2alias: + enabled: false \ No newline at end of file From 9f4a9d206cd12b8ea57a59172dfa80a3b0c69586 Mon Sep 17 00:00:00 2001 From: Arash Deshmeh Date: Fri, 18 May 2018 05:46:55 -0400 Subject: [PATCH 03/29] fix(helm): fixed output leak from template command unit tests Signed-off-by: Arash Deshmeh --- cmd/helm/template.go | 11 ++++++----- cmd/helm/template_test.go | 15 +-------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 1838bb758..9f0687a7c 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -91,6 +91,7 @@ func newTemplateCmd(out io.Writer) *cobra.Command { RunE: t.run, } + cmd.SetOutput(out) f := cmd.Flags() f.BoolVar(&t.showNotes, "notes", false, "show the computed NOTES.txt file as well") f.StringVarP(&t.releaseName, "name", "n", "release-name", "release name") @@ -241,20 +242,20 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { if whitespaceRegex.MatchString(data) { continue } - err = writeToFile(t.outputDir, m.Name, data) + err = writeToFile(t.outputDir, m.Name, data, t.out) if err != nil { return err } continue } - fmt.Printf("---\n# Source: %s\n", m.Name) - fmt.Println(data) + fmt.Fprintf(t.out, "---\n# Source: %s\n", m.Name) + fmt.Fprintln(t.out, data) } return nil } // write the to / -func writeToFile(outputDir string, name string, data string) error { +func writeToFile(outputDir string, name string, data string, out io.Writer) error { outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator)) err := ensureDirectoryForFile(outfileName) @@ -275,7 +276,7 @@ func writeToFile(outputDir string, name string, data string) error { return err } - fmt.Printf("wrote %s\n", outfileName) + fmt.Fprintf(out, "wrote %s\n", outfileName) return nil } diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index 3c5026b08..1ecc2cf2f 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -20,7 +20,6 @@ import ( "bufio" "bytes" "fmt" - "io" "os" "path/filepath" "strings" @@ -178,14 +177,9 @@ func TestTemplateCmd(t *testing.T) { }, } - var buf bytes.Buffer for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - // capture stdout - old := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w // execute template command out := bytes.NewBuffer(nil) cmd := newTemplateCmd(out) @@ -206,14 +200,8 @@ func TestTemplateCmd(t *testing.T) { } else if err != nil { t.Errorf("expected no error, got %v", err) } - // restore stdout - w.Close() - os.Stdout = old - var b bytes.Buffer - io.Copy(&b, r) - r.Close() // scan yaml into map[]yaml - scanner := bufio.NewScanner(&b) + scanner := bufio.NewScanner(out) next := false lastKey := "" m := map[string]string{} @@ -239,7 +227,6 @@ func TestTemplateCmd(t *testing.T) { } else { t.Errorf("could not find key %s", tt.expectKey) } - buf.Reset() }) } } From fdbbcab3b381c029ff0d586f8deeb5bdf06a2fd0 Mon Sep 17 00:00:00 2001 From: Michel Belleau Date: Mon, 18 Feb 2019 16:08:46 -0500 Subject: [PATCH 04/29] Fix for missing $root $root is used in $root.Files.Get and needs to be defined Signed-off-by: Michel Belleau --- docs/chart_template_guide/accessing_files.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/chart_template_guide/accessing_files.md b/docs/chart_template_guide/accessing_files.md index 206ad0cec..9977aad8f 100644 --- a/docs/chart_template_guide/accessing_files.md +++ b/docs/chart_template_guide/accessing_files.md @@ -129,6 +129,7 @@ You have multiple options with Globs: Or ```yaml +{{ $root := . }} {{ range $path, $bytes := .Files.Glob "foo/*" }} {{ base $path }}: '{{ $root.Files.Get $path | b64enc }}' {{ end }} From 9af6187c9c439d9447894053fb1c1aa4bb3fb93a Mon Sep 17 00:00:00 2001 From: Kim Bao Long Date: Fri, 22 Feb 2019 14:28:01 +0700 Subject: [PATCH 05/29] Replacing 'HTTP' by 'HTTPS' for securing links Currently, when we access the modified pages with **HTTP**, it is redirected to **HTTPS** automatically. So this commit aims to replace **HTTP** to **HTTPs** for security. Co-Authored-By: Nguyen Phuong An Signed-off-by: Kim Bao Long --- .../repository/cache/stable-index.yaml | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/pkg/getter/testdata/repository/cache/stable-index.yaml b/pkg/getter/testdata/repository/cache/stable-index.yaml index d4f883a25..40d2d04b5 100644 --- a/pkg/getter/testdata/repository/cache/stable-index.yaml +++ b/pkg/getter/testdata/repository/cache/stable-index.yaml @@ -412,7 +412,7 @@ entries: companies. All data is stored in plain text files, so no database is required. digest: 5cfff9542341a391abf9029dd9b42e7c44813c520ef0301ce62e9c08586ceca2 engine: gotpl - home: http://www.dokuwiki.org/ + home: https://www.dokuwiki.org/ icon: https://bitnami.com/assets/stacks/dokuwiki/img/dokuwiki-stack-110x117.png keywords: - dokuwiki @@ -433,7 +433,7 @@ entries: companies. All data is stored in plain text files, so no database is required. digest: 3c46f9d9196bbf975711b2bb7c889fd3df1976cc57c3c120c7374d721da0e240 engine: gotpl - home: http://www.dokuwiki.org/ + home: https://www.dokuwiki.org/ icon: https://bitnami.com/assets/stacks/dokuwiki/img/dokuwiki-stack-110x117.png keywords: - dokuwiki @@ -454,7 +454,7 @@ entries: companies. All data is stored in plain text files, so no database is required. digest: f533bc20e08179a49cca77b175f897087dc3f2c57e6c89ecbd7264ab5975d66a engine: gotpl - home: http://www.dokuwiki.org/ + home: https://www.dokuwiki.org/ icon: https://bitnami.com/assets/stacks/dokuwiki/img/dokuwiki-stack-110x117.png keywords: - dokuwiki @@ -475,7 +475,7 @@ entries: companies. All data is stored in plain text files, so no database is required. digest: 34a926398cfafbf426ff468167ef49577252e260ebce5df33380e6e67b79fe59 engine: gotpl - home: http://www.dokuwiki.org/ + home: https://www.dokuwiki.org/ icon: https://bitnami.com/assets/stacks/dokuwiki/img/dokuwiki-stack-110x117.png keywords: - dokuwiki @@ -496,7 +496,7 @@ entries: companies. All data is stored in plain text files, so no database is required. digest: 6825fbacb709cf05901985561be10ba9473a379488d99b71d1590d33f5a81374 engine: gotpl - home: http://www.dokuwiki.org/ + home: https://www.dokuwiki.org/ icon: https://bitnami.com/assets/stacks/dokuwiki/img/dokuwiki-stack-110x117.png keywords: - dokuwiki @@ -516,7 +516,7 @@ entries: description: One of the most versatile open source content management systems. digest: db95c255b19164c5051eb75a6860f3775a1011399a62b27e474cd9ebee0cb578 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ icon: https://bitnami.com/assets/stacks/drupal/img/drupal-stack-220x234.png keywords: - drupal @@ -539,7 +539,7 @@ entries: description: One of the most versatile open source content management systems. digest: 84c13154a9aeb7215dc0d98e9825207207e69ca870f3d54b273bfc2d34699f61 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ icon: https://bitnami.com/assets/stacks/drupal/img/drupal-stack-220x234.png keywords: - drupal @@ -562,7 +562,7 @@ entries: description: One of the most versatile open source content management systems. digest: 17d0bfdcdf5a1a650941343c76b6b928d76d3332fece127c502e91f9597f419e engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ icon: https://bitnami.com/assets/stacks/drupal/img/drupal-stack-220x234.png keywords: - drupal @@ -585,7 +585,7 @@ entries: description: One of the most versatile open source content management systems. digest: 317674c89762e0b54156b734203ee93638dd7a25df35120c5cab45546814d89b engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ icon: https://bitnami.com/assets/stacks/drupal/img/drupal-stack-220x234.png keywords: - drupal @@ -608,7 +608,7 @@ entries: description: One of the most versatile open source content management systems. digest: 24c4f187b50c0e961cc2cacf6e6b2ce6d6b225c73637c578e001bebd9b3f5d48 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ icon: https://bitnami.com/assets/stacks/drupal/img/drupal-stack-220x234.png keywords: - drupal @@ -631,7 +631,7 @@ entries: description: One of the most versatile open source content management systems. digest: 7fcea4684a3d520454aeaa10beb9f9b1789c09c097680fc484954084f283feb3 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ icon: https://bitnami.com/assets/stacks/drupal/img/drupal-stack-220x234.png keywords: - drupal @@ -654,7 +654,7 @@ entries: description: One of the most versatile open source content management systems. digest: adb23bc71125b9691b407a47dadf4298de3516805218813b56067967e39db7d8 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ icon: https://bitnami.com/assets/stacks/drupal/img/drupal-stack-220x234.png keywords: - drupal @@ -677,7 +677,7 @@ entries: description: One of the most versatile open source content management systems. digest: 5de529e25767e8a37b8d6f413daa0fe99f5c304e48ddcfa8adb4d8c7a0496aa7 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -699,7 +699,7 @@ entries: description: One of the most versatile open source content management systems. digest: a35dbf9d470972cc2461de3e0a8fcf2fec8d0adc04f5a0f1e924505f22c714d7 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -721,7 +721,7 @@ entries: description: One of the most versatile open source content management systems. digest: a62d686d6bd47643dfa489e395dda89286954f785123a43a88db7ef34f3ea48d engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -743,7 +743,7 @@ entries: description: One of the most versatile open source content management systems. digest: 2c189424bda94eeebb7e6370e96884f09bdfa81498cb93ac4723d24c92a3938e engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -765,7 +765,7 @@ entries: description: One of the most versatile open source content management systems. digest: 3596f47c5dcaa7a975d1c4cb7bf7ef6790c9ad8dda41a5a329e30c1ea8a40d11 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -787,7 +787,7 @@ entries: description: One of the most versatile open source content management systems. digest: 78b2bb3717be63dccb02ea06b711ca7cf7869848b296b880099c6264e86d86d3 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -809,7 +809,7 @@ entries: description: One of the most versatile open source content management systems. digest: 5508b29e20a5d609f76319869774f008dcc4bed13bbbc7ed40546bc9af8c7cd7 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -831,7 +831,7 @@ entries: description: One of the most versatile open source content management systems. digest: 023a282c93f8411fb81bb4fff7820c1337aad0586ccf7dae55bdbed515ad8b05 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -853,7 +853,7 @@ entries: description: One of the most versatile open source content management systems. digest: 9bdaa53f7a9e82c9b32c7ac9b34b84fd142671732a54423a2dcdc893c4162801 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -875,7 +875,7 @@ entries: description: One of the most versatile open source content management systems. digest: 25650526abc1036398dbb314d77a0062cbb644b2c5791a258fb863fdaad5093d engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -897,7 +897,7 @@ entries: description: One of the most versatile open source content management systems. digest: 13d5d32d316c08359221d230004dd2adc0152362e87abcc0d61ea191241fa69f engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -919,7 +919,7 @@ entries: description: One of the most versatile open source content management systems. digest: b3f09ecd191f8c06275c96d9af4d77a97c94355525864201e9baf151b17bd5a7 engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -941,7 +941,7 @@ entries: description: One of the most versatile open source content management systems. digest: c56fc55b93b0dead65af7b81bbd54befd5115860698ca475baa5acb178a12e5a engine: gotpl - home: http://www.drupal.org/ + home: https://www.drupal.org/ keywords: - drupal - cms @@ -1154,7 +1154,7 @@ entries: stories with the world digest: 91d195c99e00b2801eafef5c23fcf9ced218bb29c7097f08139e2bdc80e38a0f engine: gotpl - home: http://www.ghost.org/ + home: https://www.ghost.org/ icon: https://bitnami.com/assets/stacks/ghost/img/ghost-stack-220x234.png keywords: - ghost @@ -1178,7 +1178,7 @@ entries: stories with the world digest: 6342a95aeef40690430c2e80b167fbb116a632746cdca49cfac4cbd535eadb22 engine: gotpl - home: http://www.ghost.org/ + home: https://www.ghost.org/ icon: https://bitnami.com/assets/stacks/ghost/img/ghost-stack-220x234.png keywords: - ghost @@ -1202,7 +1202,7 @@ entries: stories with the world digest: 8998a9a4e75e777edb6f06c05b45d461daebba09021161af3bef523efd193b15 engine: gotpl - home: http://www.ghost.org/ + home: https://www.ghost.org/ icon: https://bitnami.com/assets/stacks/ghost/img/ghost-stack-220x234.png keywords: - ghost @@ -1226,7 +1226,7 @@ entries: stories with the world digest: e44c9a53355086ded1832f769dca515b863337ad118ba618ef97f37b3ef84030 engine: gotpl - home: http://www.ghost.org/ + home: https://www.ghost.org/ icon: https://bitnami.com/assets/stacks/ghost/img/ghost-stack-220x234.png keywords: - ghost @@ -1250,7 +1250,7 @@ entries: stories with the world digest: b0c94a93c88fde68bb4fc78e92691d46cd2eb4d32cbac011e034565fbd35d46b engine: gotpl - home: http://www.ghost.org/ + home: https://www.ghost.org/ keywords: - ghost - blog @@ -1273,7 +1273,7 @@ entries: stories with the world digest: 791ccb42b62d56d50c72b37db3282eb3f2af75d667a25542d76c7991004eb822 engine: gotpl - home: http://www.ghost.org/ + home: https://www.ghost.org/ keywords: - ghost - blog @@ -1296,7 +1296,7 @@ entries: stories with the world digest: 331a2b145bfdb39b626313cda7dc539f32dbda5149893957589c5406317fca53 engine: gotpl - home: http://www.ghost.org/ + home: https://www.ghost.org/ keywords: - ghost - blog @@ -1319,7 +1319,7 @@ entries: stories with the world digest: 804227af037082a0f5c3c579feb9e24eb3682449e78876971c93a109bc716f40 engine: gotpl - home: http://www.ghost.org/ + home: https://www.ghost.org/ keywords: - ghost - blog @@ -1758,7 +1758,7 @@ entries: visualization, and a dashboard feature for compiling multiple custom views digest: 8a649026f55b2fa1e743c93fd331e127e66b49c4d7f20116a2bb06e5937f4828 engine: gotpl - home: http://community.jaspersoft.com/project/jasperreports-server + home: https://community.jaspersoft.com/project/jasperreports-server icon: https://bitnami.com/assets/stacks/jasperserver/img/jasperserver-stack-110x117.png keywords: - business intelligence @@ -1782,7 +1782,7 @@ entries: visualization, and a dashboard feature for compiling multiple custom views digest: d4a62f7ace55256852e5c650a56ccf671633c4f223180d304cfb03b9cd7993aa engine: gotpl - home: http://community.jaspersoft.com/project/jasperreports-server + home: https://community.jaspersoft.com/project/jasperreports-server icon: https://bitnami.com/assets/stacks/jasperserver/img/jasperserver-stack-110x117.png keywords: - business intelligence @@ -1806,7 +1806,7 @@ entries: visualization, and a dashboard feature for compiling multiple custom views digest: 99af0fca7ef1c475b239f2c8fc2dee6b040ea76b3c30bba1431f358df873aa49 engine: gotpl - home: http://community.jaspersoft.com/project/jasperreports-server + home: https://community.jaspersoft.com/project/jasperreports-server icon: https://bitnami.com/assets/stacks/jasperserver/img/jasperserver-stack-110x117.png keywords: - business intelligence @@ -1830,7 +1830,7 @@ entries: visualization, and a dashboard feature for compiling multiple custom views digest: f01e53d1b89c4fb1fcd9702cd5f4e48d77607aed65f249e1f94b8b21f7eef3f4 engine: gotpl - home: http://community.jaspersoft.com/project/jasperreports-server + home: https://community.jaspersoft.com/project/jasperreports-server icon: https://bitnami.com/assets/stacks/jasperserver/img/jasperserver-stack-110x117.png keywords: - business intelligence @@ -1854,7 +1854,7 @@ entries: visualization, and a dashboard feature for compiling multiple custom views digest: 5cc4af8c88691d7030602c97be2ccbc125ef11129b361da0aa236a127c31b965 engine: gotpl - home: http://community.jaspersoft.com/project/jasperreports-server + home: https://community.jaspersoft.com/project/jasperreports-server icon: https://bitnami.com/assets/stacks/jasperserver/img/jasperserver-stack-110x117.png keywords: - business intelligence @@ -2265,7 +2265,7 @@ entries: description: PHP content management system (CMS) for publishing web content digest: 6f9934487533f325515f4877b3af1306c87d64bf3ece9d4bd875289cd73b340d engine: gotpl - home: http://www.joomla.org/ + home: https://www.joomla.org/ icon: https://bitnami.com/assets/stacks/joomla/img/joomla-stack-220x234.png keywords: - joomla @@ -2286,7 +2286,7 @@ entries: description: PHP content management system (CMS) for publishing web content digest: f9dedab2fc2dbf170cf45b2c230baa6d20aad9a6f8ccfcb09c459602fc5213dc engine: gotpl - home: http://www.joomla.org/ + home: https://www.joomla.org/ icon: https://bitnami.com/assets/stacks/joomla/img/joomla-stack-220x234.png keywords: - joomla @@ -2307,7 +2307,7 @@ entries: description: PHP content management system (CMS) for publishing web content digest: 1e067e459873ae832d54ff516a3420f7f0e16ecd8f72f4c4f02be22e47702077 engine: gotpl - home: http://www.joomla.org/ + home: https://www.joomla.org/ icon: https://bitnami.com/assets/stacks/joomla/img/joomla-stack-220x234.png keywords: - joomla @@ -2328,7 +2328,7 @@ entries: description: PHP content management system (CMS) for publishing web content digest: 9a99b15e83e18955eb364985cd545659f1176ef203ac730876dfe39499edfb18 engine: gotpl - home: http://www.joomla.org/ + home: https://www.joomla.org/ icon: https://bitnami.com/assets/stacks/joomla/img/joomla-stack-220x234.png keywords: - joomla @@ -2349,7 +2349,7 @@ entries: description: PHP content management system (CMS) for publishing web content digest: 07c3a16eb674ffc74fe5b2b16191b8bb24c63bdae9bce9710bda1999920c46fc engine: gotpl - home: http://www.joomla.org/ + home: https://www.joomla.org/ keywords: - joomla - cms @@ -2369,7 +2369,7 @@ entries: description: PHP content management system (CMS) for publishing web content digest: 95fbe272015941544609eee90b3bffd5172bfdec10be13636510caa8478a879e engine: gotpl - home: http://www.joomla.org/ + home: https://www.joomla.org/ keywords: - joomla - cms @@ -2389,7 +2389,7 @@ entries: description: PHP content management system (CMS) for publishing web content digest: 0a01ea051ec15274932c8d82076c1a9fd62584b0fb916a81372319bef223c20e engine: gotpl - home: http://www.joomla.org/ + home: https://www.joomla.org/ keywords: - joomla - cms @@ -2771,7 +2771,7 @@ entries: - created: 2017-04-28T00:18:30.087097677Z description: A modern load testing framework digest: eb91b0e3c0b618cf5ad0f24d2685fe4086bc6f497685e58ad8a64032c4e82b7a - home: http://locust.io + home: https://locust.io icon: https://pbs.twimg.com/profile_images/1867636195/locust-logo-orignal.png maintainers: - email: vincent.drl@gmail.com @@ -3351,7 +3351,7 @@ entries: that uses PHP to process and display data stored in a database. digest: 0e51822c5547895109a5b41ce426c77f62d0434b40f3021afee8471ab976a6f5 engine: gotpl - home: http://www.mediawiki.org/ + home: https://www.mediawiki.org/ icon: https://bitnami.com/assets/stacks/mediawiki/img/mediawiki-stack-220x234.png keywords: - mediawiki @@ -3372,7 +3372,7 @@ entries: that uses PHP to process and display data stored in a database. digest: 0e419c2c5d87997f94a32da6597af3f3b52120dc1ec682dcbb6b238fb4825e06 engine: gotpl - home: http://www.mediawiki.org/ + home: https://www.mediawiki.org/ icon: https://bitnami.com/assets/stacks/mediawiki/img/mediawiki-stack-220x234.png keywords: - mediawiki @@ -3393,7 +3393,7 @@ entries: that uses PHP to process and display data stored in a database. digest: 6f4dde26737f7f1aa63ffda6c259ce388e3a3509225f90f334bfc3f0f7617bc1 engine: gotpl - home: http://www.mediawiki.org/ + home: https://www.mediawiki.org/ icon: https://bitnami.com/assets/stacks/mediawiki/img/mediawiki-stack-220x234.png keywords: - mediawiki @@ -3414,7 +3414,7 @@ entries: that uses PHP to process and display data stored in a database. digest: 0ba52b8c4c9e0bee3eb76fe625d2dc88729a1cdf41ace9d13cd4abc5b477cfb8 engine: gotpl - home: http://www.mediawiki.org/ + home: https://www.mediawiki.org/ keywords: - mediawiki - wiki @@ -3434,7 +3434,7 @@ entries: that uses PHP to process and display data stored in a database. digest: f49df3e17f97b238743aad0376eb9db7e4a9bca3829a3a65d7bbb349344a73be engine: gotpl - home: http://www.mediawiki.org/ + home: https://www.mediawiki.org/ keywords: - mediawiki - wiki @@ -3454,7 +3454,7 @@ entries: that uses PHP to process and display data stored in a database. digest: 339a90050d5cf4216140409349a356aa7cd8dc95e2cbdca06e4fdd11e87aa963 engine: gotpl - home: http://www.mediawiki.org/ + home: https://www.mediawiki.org/ keywords: - mediawiki - wiki @@ -3474,7 +3474,7 @@ entries: that uses PHP to process and display data stored in a database. digest: 9617f13f51f5bb016a072f2a026c627420721a1c5b7cd22f32d6cd0c90f34eda engine: gotpl - home: http://www.mediawiki.org/ + home: https://www.mediawiki.org/ keywords: - mediawiki - wiki @@ -3495,7 +3495,7 @@ entries: system. digest: 36ceb2767094598171b2851ecda54bd43d862b9b81aa4b294f3d8c8d59ddd79c engine: gotpl - home: http://memcached.org/ + home: https://memcached.org/ icon: https://upload.wikimedia.org/wikipedia/en/thumb/2/27/Memcached.svg/1024px-Memcached.svg.png keywords: - memcached @@ -3513,7 +3513,7 @@ entries: description: Chart for Memcached digest: 2b918dd8129a9d706e58b3de459004e3367c05a162d3e3cdb031cb6818d5f820 engine: gotpl - home: http://memcached.org/ + home: https://memcached.org/ keywords: - memcached - cache @@ -3911,7 +3911,7 @@ entries: learning environments digest: 386bff8ce61cf61961daf8ed6d68a76cd3a360560a08c1fca80bcbd897f11270 engine: gotpl - home: http://www.moodle.org/ + home: https://www.moodle.org/ icon: https://bitnami.com/assets/stacks/moodle/img/moodle-stack-110x117.png keywords: - moodle @@ -3932,7 +3932,7 @@ entries: learning environments digest: bd85420a7cefd82e9d96088591601f832ecc60016d6389dbcde51a2050327a66 engine: gotpl - home: http://www.moodle.org/ + home: https://www.moodle.org/ icon: https://bitnami.com/assets/stacks/moodle/img/moodle-stack-110x117.png keywords: - moodle @@ -3953,7 +3953,7 @@ entries: learning environments digest: 8656c544a71fa8cc4ac23380e999e072740ec8e481a22aff86517d8362e70121 engine: gotpl - home: http://www.moodle.org/ + home: https://www.moodle.org/ icon: https://bitnami.com/assets/stacks/moodle/img/moodle-stack-110x117.png keywords: - moodle From 3e1ca6fe6e3e2add0518925c5273b650fcb64280 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Mon, 6 May 2019 21:14:01 -0400 Subject: [PATCH 06/29] fix(completion): --flag=val breaks zsh completion This is a bug I ran into when working on Helm completion. I was surprised that it didn't happen when I was using kubectl, so I investigated and found a PR that fixed this bug in kubectl: https://github.com/kubernetes/kubernetes/pull/48553 I duplicated the code in this commit which: Removes __helm_declare, which is safe to do since `declare -F` is already replaced to `whence -w` by __helm_convert_bash_to_zsh(). The problem was that calling "declare" from inside a function scopes the declaration to that function only. So "declare" should not be called through __helm_declare() but instead directly. To reproduce: 1- setup helm completion in zsh 2- helm --kubeconfig=$HOME/.kube/config statu you will get the error: __helm_handle_flag:27: bad math expression: operand expected at end of string Co-authored-by: Kazuki Suda Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index 039dcbe5f..051f946fd 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -126,13 +126,6 @@ __helm_compgen() { __helm_compopt() { true # don't do anything. Not supported by bashcompinit in zsh } -__helm_declare() { - if [ "$1" == "-F" ]; then - whence -w "$@" - else - builtin declare "$@" - fi -} __helm_ltrim_colon_completions() { if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then @@ -210,7 +203,7 @@ __helm_convert_bash_to_zsh() { -e "s/${LWORD}__ltrim_colon_completions${RWORD}/__helm_ltrim_colon_completions/g" \ -e "s/${LWORD}compgen${RWORD}/__helm_compgen/g" \ -e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \ - -e "s/${LWORD}declare${RWORD}/__helm_declare/g" \ + -e "s/${LWORD}declare${RWORD}/builtin declare/g" \ -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ -e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \ -e 's/FUNCNAME/funcstack/g' \ From 0239cc4457463cfd6af1f61ec26aa35845dcb1c5 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Mon, 20 May 2019 12:56:22 -0400 Subject: [PATCH 07/29] (helm): Proper fix for #5046 PR #5072 followed by #5406 tweaked the handling of the associative array 'aliashash' when in zsh. However, upon further investigation the root of the problem was the 'aliashash' was not being declared properly as it was declared within a method and therefore not accessible to the rest of the completion script. The previous commit of this PR makes the necessary change to properly declare 'aliashash' which makes the previous tweak unecessary. This commit removes the tweak. Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index 051f946fd..f0345d32a 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -205,7 +205,6 @@ __helm_convert_bash_to_zsh() { -e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \ -e "s/${LWORD}declare${RWORD}/builtin declare/g" \ -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ - -e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \ -e 's/FUNCNAME/funcstack/g' \ <<'BASH_COMPLETION_EOF' ` From b0e7b8c9d98cbed46f3e4ae1e6060a979ab2d940 Mon Sep 17 00:00:00 2001 From: Per Hermansson Date: Mon, 20 May 2019 21:43:09 +0200 Subject: [PATCH 08/29] Skip waiting for paused deployments Signed-off-by: Per Hermansson --- pkg/kube/wait.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index 105d79b93..ad779bcc8 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -71,6 +71,10 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { if err != nil { return false, err } + // If paused deployment will never be ready + if currentDeployment.Spec.Paused { + continue + } // Find RS associated with deployment newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) if err != nil || newReplicaSet == nil { @@ -86,6 +90,10 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { if err != nil { return false, err } + // If paused deployment will never be ready + if currentDeployment.Spec.Paused { + continue + } // Find RS associated with deployment newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) if err != nil || newReplicaSet == nil { @@ -101,6 +109,10 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { if err != nil { return false, err } + // If paused deployment will never be ready + if currentDeployment.Spec.Paused { + continue + } // Find RS associated with deployment newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) if err != nil || newReplicaSet == nil { @@ -116,6 +128,10 @@ func (c *Client) waitForResources(timeout time.Duration, created Result) error { if err != nil { return false, err } + // If paused deployment will never be ready + if currentDeployment.Spec.Paused { + continue + } // Find RS associated with deployment newReplicaSet, err := deploymentutil.GetNewReplicaSet(currentDeployment, kcs.AppsV1()) if err != nil || newReplicaSet == nil { From 48f0e3101d49a3de1466ff75fc786ce012f369cc Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Wed, 5 Jun 2019 22:09:15 -0400 Subject: [PATCH 09/29] Allow for completion of aliases Turns out that removing the quotes from the associate array 'aliashash' is still required, but because it is needed for completion of alias commands. For example helm dep does not complete as expected (as if it was 'helm dependency') if the quotes are not removed. This is because although bash ignores quotes when using associative arrays, zsh does not. So when looking for an alias aliashash[dep] will not match the entry aliashash["dep"] in zsh but will for bash. Therefore, removing the quotes fixes things. Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index f0345d32a..051f946fd 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -205,6 +205,7 @@ __helm_convert_bash_to_zsh() { -e "s/${LWORD}compopt${RWORD}/__helm_compopt/g" \ -e "s/${LWORD}declare${RWORD}/builtin declare/g" \ -e "s/\\\$(type${RWORD}/\$(__helm_type/g" \ + -e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \ -e 's/FUNCNAME/funcstack/g' \ <<'BASH_COMPLETION_EOF' ` From 95ec21339549e2242ff2fa9a0940ca0527bcbe83 Mon Sep 17 00:00:00 2001 From: yuxiaobo Date: Fri, 30 Aug 2019 13:10:06 +0800 Subject: [PATCH 10/29] delete extra space Signed-off-by: yuxiaobo --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 996f6d224..aee515e37 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -199,7 +199,7 @@ $ git pull upstream master ```sh $ git checkout -b new-feature ``` -6. Make any change on the branch `new-feature` then build and test your codes. +6. Make any change on the branch `new-feature` then build and test your codes. 7. Include in what will be committed. ```sh $ git add From a584ee9a00a73bd5cd8684efd2ebd84d3bf02def Mon Sep 17 00:00:00 2001 From: ammarn911 <49419471+ammarn911@users.noreply.github.com> Date: Fri, 30 Aug 2019 11:44:02 -0500 Subject: [PATCH 11/29] Adding MicroK8s to kubernetes_distros.md Signed-off-by: ammarn911 <49419471+ammarn911@users.noreply.github.com> --- docs/kubernetes_distros.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/kubernetes_distros.md b/docs/kubernetes_distros.md index 52a5e1acc..1efe3807b 100644 --- a/docs/kubernetes_distros.md +++ b/docs/kubernetes_distros.md @@ -6,6 +6,10 @@ environments. We are trying to add more details to this document. Please contribute via Pull Requests if you can. +## MicroK8s + +Helm can be enabled in [MicroK8s](https://microk8s.io) using the command: `microk8s.enable helm` + ## MiniKube Helm is tested and known to work with [minikube](https://github.com/kubernetes/minikube). From 540fe23b692ab22b04e4718644cc654d694abc04 Mon Sep 17 00:00:00 2001 From: Anton Date: Mon, 2 Sep 2019 19:20:36 +0200 Subject: [PATCH 12/29] fix BusyBox sed (#6327) BusyBox sed works the same way as GNU sed Signed-off-by: tipok --- cmd/helm/completion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index 039dcbe5f..e6ca1c6ac 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -194,7 +194,7 @@ autoload -U +X bashcompinit && bashcompinit # use word boundary patterns for BSD or GNU sed LWORD='[[:<:]]' RWORD='[[:>:]]' -if sed --help 2>&1 | grep -q GNU; then +if sed --help 2>&1 | grep -q 'GNU\|BusyBox'; then LWORD='\<' RWORD='\>' fi From 3ed073b2e0c37dd5c994562d6fe8e04b5f3609eb Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Tue, 3 Sep 2019 10:01:47 -0400 Subject: [PATCH 13/29] v2: Dynamic completion for "helm repo" and "helm plugin" (#6265) * feat(helm): Completion for helm repo remove Signed-off-by: Marc Khouzam * feat(helm): Complete for helm plugin remove/update helm repo remove (will select from the names of configured repos) helm plugin remove (will select from names of installed plugins) helm plugin update (will select from names of installed plugins) Signed-off-by: Marc Khouzam * feat(helm): Completion for helm repo update Signed-off-by: Marc Khouzam --- cmd/helm/helm.go | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 2f394968f..20742836d 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -41,7 +41,7 @@ import ( const ( bashCompletionFunc = ` -__helm_override_flag_list=(--kubeconfig --kube-context --host --tiller-namespace) +__helm_override_flag_list=(--kubeconfig --kube-context --host --tiller-namespace --home) __helm_override_flags() { local ${__helm_override_flag_list[*]##*-} two_word_of of var @@ -80,6 +80,28 @@ __helm_list_releases() fi } +__helm_list_repos() +{ + __helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + local out oflags + oflags=$(__helm_override_flags) + __helm_debug "${FUNCNAME[0]}: __helm_override_flags are ${oflags}" + if out=$(helm repo list ${oflags} | tail +2 | cut -f1 2>/dev/null); then + COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) + fi +} + +__helm_list_plugins() +{ + __helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + local out oflags + oflags=$(__helm_override_flags) + __helm_debug "${FUNCNAME[0]}: __helm_override_flags are ${oflags}" + if out=$(helm plugin list ${oflags} | tail +2 | cut -f1 2>/dev/null); then + COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) + fi +} + __helm_custom_func() { __helm_debug "${FUNCNAME[0]}: c is $c words[@] is ${words[@]}" @@ -89,6 +111,14 @@ __helm_custom_func() __helm_list_releases return ;; + helm_repo_remove | helm_repo_update) + __helm_list_repos + return + ;; + helm_plugin_remove | helm_plugin_update) + __helm_list_plugins + return + ;; *) ;; esac From eeff9079b84eeb67a0f0f7652c644c480aa2d045 Mon Sep 17 00:00:00 2001 From: Steven Cipriano Date: Thu, 5 Sep 2019 13:41:41 -0700 Subject: [PATCH 14/29] In get script, use specified path to helm binary for helm version check Signed-off-by: Steven Cipriano --- scripts/get | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/get b/scripts/get index ea2056ca6..3f645f807 100755 --- a/scripts/get +++ b/scripts/get @@ -94,7 +94,7 @@ checkDesiredVersion() { # if it needs to be changed. checkHelmInstalledVersion() { if [[ -f "${HELM_INSTALL_DIR}/${PROJECT_NAME}" ]]; then - local version=$(helm version -c | grep '^Client' | cut -d'"' -f2) + local version=$("${HELM_INSTALL_DIR}/${PROJECT_NAME}" version -c | grep '^Client' | cut -d'"' -f2) if [[ "$version" == "$TAG" ]]; then echo "Helm ${version} is already ${DESIRED_VERSION:-latest}" return 0 From b49f4269c5bdfee920b0d5fd7954513f5e17dad6 Mon Sep 17 00:00:00 2001 From: Xiang Dai <764524258@qq.com> Date: Wed, 21 Aug 2019 10:36:42 +0800 Subject: [PATCH 15/29] fix issue when dependency is URL Signed-off-by: Xiang Dai <764524258@qq.com> --- pkg/downloader/chart_downloader.go | 5 +++++ pkg/downloader/manager.go | 19 ++++++++++++++++--- pkg/downloader/manager_test.go | 16 ++++++++-------- pkg/resolver/resolver.go | 13 ++++++++++++- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 563188ec3..c2e9f6dc1 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -205,6 +205,11 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, ge } c.setCredentials(r) + // Skip if dependency not contain name + if len(r.Config.Name) == 0 { + return u, r.Client, nil + } + // Next, we need to load the index, and actually look up the chart. i, err := repo.LoadIndexFile(c.HelmHome.CacheIndex(r.Config.Name)) if err != nil { diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index cca198916..6c6886e8a 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -233,7 +233,7 @@ func (m *Manager) downloadAll(deps []*chartutil.Dependency) error { // Any failure to resolve/download a chart should fail: // https://github.com/kubernetes/helm/issues/1439 - churl, username, password, err := findChartURL(dep.Name, dep.Version, dep.Repository, repos) + churl, username, password, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos) if err != nil { saveError = fmt.Errorf("could not find %s: %s", churl, err) break @@ -403,9 +403,17 @@ func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string, } } if !found { - missing = append(missing, dd.Repository) + repository := dd.Repository + // Add if URL + _, err := url.ParseRequestURI(repository) + if err == nil { + reposMap[repository] = repository + continue + } + missing = append(missing, repository) } } + if len(missing) > 0 { errorMessage := fmt.Sprintf("no repository definition for %s. Please add them via 'helm repo add'", strings.Join(missing, ", ")) // It is common for people to try to enter "stable" as a repository instead of the actual URL. @@ -424,6 +432,7 @@ repository, use "https://kubernetes-charts.storage.googleapis.com/" or "@stable" } return nil, errors.New(errorMessage) } + return reposMap, nil } @@ -475,7 +484,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error { // repoURL is the repository to search // // If it finds a URL that is "relative", it will prepend the repoURL. -func findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, err error) { +func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, err error) { for _, cr := range repos { if urlutil.Equal(repoURL, cr.Config.URL) { var entry repo.ChartVersions @@ -497,6 +506,10 @@ func findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRep return } } + url, err = repo.FindChartInRepoURL(repoURL, name, version, "", "", "", m.Getters) + if err == nil { + return + } err = fmt.Errorf("chart %s not found in %s", name, repoURL) return } diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index cb588394a..ef8b95071 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -78,7 +78,7 @@ func TestFindChartURL(t *testing.T) { version := "0.1.0" repoURL := "http://example.com/charts" - churl, username, password, err := findChartURL(name, version, repoURL, repos) + churl, username, password, err := m.findChartURL(name, version, repoURL, repos) if err != nil { t.Fatal(err) } @@ -106,13 +106,6 @@ func TestGetRepoNames(t *testing.T) { err bool expectedErr string }{ - { - name: "no repo definition failure", - req: []*chartutil.Dependency{ - {Name: "oedipus-rex", Repository: "http://example.com/test"}, - }, - err: true, - }, { name: "no repo definition failure -- stable repo", req: []*chartutil.Dependency{ @@ -128,6 +121,13 @@ func TestGetRepoNames(t *testing.T) { err: true, expectedErr: "no 'repository' field specified for dependency: \"dependency-missing-repository-field\"", }, + { + name: "dependency repository is url but not exist in repos", + req: []*chartutil.Dependency{ + {Name: "oedipus-rex", Repository: "http://example.com/test"}, + }, + expect: map[string]string{"http://example.com/test": "http://example.com/test"}, + }, { name: "no repo definition failure", req: []*chartutil.Dependency{ diff --git a/pkg/resolver/resolver.go b/pkg/resolver/resolver.go index 8177df2d3..516e9260f 100644 --- a/pkg/resolver/resolver.go +++ b/pkg/resolver/resolver.go @@ -71,7 +71,18 @@ func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]st return nil, fmt.Errorf("dependency %q has an invalid version/constraint format: %s", d.Name, err) } - repoIndex, err := repo.LoadIndexFile(r.helmhome.CacheIndex(repoNames[d.Name])) + // repo does not exist in cache but has url info + cacheRepoName := repoNames[d.Name] + if cacheRepoName == "" && d.Repository != "" { + locked[i] = &chartutil.Dependency{ + Name: d.Name, + Repository: d.Repository, + Version: d.Version, + } + continue + } + + repoIndex, err := repo.LoadIndexFile(r.helmhome.CacheIndex(cacheRepoName)) if err != nil { return nil, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err) } From 8d8eceec92217a0eb3ad06a3e2b82e92f22b3c37 Mon Sep 17 00:00:00 2001 From: yuxiaobo Date: Tue, 10 Sep 2019 17:47:52 +0800 Subject: [PATCH 16/29] Grammar tweak Signed-off-by: yuxiaobo --- docs/chart_repository_sync_example.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chart_repository_sync_example.md b/docs/chart_repository_sync_example.md index 931275431..91215cb25 100644 --- a/docs/chart_repository_sync_example.md +++ b/docs/chart_repository_sync_example.md @@ -38,7 +38,7 @@ Building synchronization state... Starting synchronization Would copy file://fantastic-charts/alpine-0.1.0.tgz to gs://fantastic-charts/alpine-0.1.0.tgz Would copy file://fantastic-charts/index.yaml to gs://fantastic-charts/index.yaml -Are you sure you would like to continue with these changes?? [y/N]} y +Are you sure you would like to continue with these changes? [y/N]} y Building synchronization state... Starting synchronization Copying file://fantastic-charts/alpine-0.1.0.tgz [Content-Type=application/x-tar]... From 05d5ff4747cb810e61f88685285bcd8e73f073aa Mon Sep 17 00:00:00 2001 From: Xiang Dai <764524258@qq.com> Date: Tue, 10 Sep 2019 10:05:58 +0800 Subject: [PATCH 17/29] update test Signed-off-by: Xiang Dai <764524258@qq.com> --- pkg/resolver/resolver_test.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pkg/resolver/resolver_test.go b/pkg/resolver/resolver_test.go index 689ffbc32..f35e051fa 100644 --- a/pkg/resolver/resolver_test.go +++ b/pkg/resolver/resolver_test.go @@ -37,15 +37,6 @@ func TestResolve(t *testing.T) { }, err: true, }, - { - name: "cache index failure", - req: &chartutil.Requirements{ - Dependencies: []*chartutil.Dependency{ - {Name: "oedipus-rex", Repository: "http://example.com", Version: "1.0.0"}, - }, - }, - err: true, - }, { name: "chart not found failure", req: &chartutil.Requirements{ From aa4dae05359cf5db77a8502f814e3fa1f412df42 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Wed, 18 Sep 2019 12:49:06 -0400 Subject: [PATCH 18/29] Updating to newer versions of dependencies * This was initiated by new versions from Masterminds * Linting was set to check for the same chart version as the other checks of this were. >0.0.0-0. The -0 is important to pull in prereleases. The latest version of semver Validate now finds errors here properly where some were missed before * 0.0.0 is a valid semantic version. Instead of expecting it to be invalid in the tests to check validation now using an invalid semantic version Signed-off-by: Matt Farina --- glide.lock | 14 +++++++------- glide.yaml | 3 ++- pkg/lint/lint_test.go | 2 +- pkg/lint/rules/chartfile.go | 2 +- pkg/lint/rules/chartfile_test.go | 4 ++-- pkg/lint/rules/testdata/badchartfile/Chart.yaml | 2 +- pkg/tiller/release_install_test.go | 2 +- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/glide.lock b/glide.lock index 92e7c50dd..d81ca12ca 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 277f7be1b21149bc06b361fa61c0a2ff81a7f00c59a6e35c21b6516f6ddfd9f7 -updated: 2019-07-03T21:59:06.87934+02:00 +hash: 13c07a8e64f0777d08cd03d5edba6f254621ec1ee8e3c7b3ef26efc682b643ce +updated: 2019-09-18T12:07:21.888497-04:00 imports: - name: cloud.google.com/go version: 0ebda48a7f143b1cce9eb37a8c1106ac762a3430 @@ -121,7 +121,7 @@ imports: - name: github.com/google/gofuzz version: 24818f796faf91cd76ec7bddd72458fbced7a6c1 - name: github.com/google/uuid - version: 064e2069ce9c359c118179501254f67d7d37ba24 + version: 0cd6bf5da1e1c83f8b45653022c74f71af0538a4 - name: github.com/googleapis/gnostic version: 0c5108395e2debce0d731cf0287ddf7242066aba subpackages: @@ -183,11 +183,11 @@ imports: - name: github.com/Masterminds/goutils version: 41ac8693c5c10a92ea1ff5ac3a7f95646f6123b0 - name: github.com/Masterminds/semver - version: c7af12943936e8c39859482e61f0574c2fd7fc75 + version: 805c489aa98f412e79eb308a37996bf9d8b1c91e - name: github.com/Masterminds/sprig - version: 258b00ffa7318e8b109a141349980ffbd30a35db + version: 2691a9cba2adee8d9a60100a1bc49e770f97b7db - name: github.com/Masterminds/vcs - version: 3084677c2c188840777bff30054f2b553729d329 + version: f94282d8632a0620f79f0c6ff0e82604e8c5c85b - name: github.com/mattn/go-runewidth version: d6bea18f789704b5f83375793155289da36a3c7f - name: github.com/matttproud/golang_protobuf_extensions @@ -247,7 +247,7 @@ imports: subpackages: - doc - name: github.com/spf13/pflag - version: 298182f68c66c05229eb03ac171abe6e309ee79a + version: e8f29969b682c41a730f8f08b76033b120498464 - name: github.com/technosophos/moniker version: a5dbd03a2245d554160e3ae6bfdcf969fe58b431 - name: golang.org/x/crypto diff --git a/glide.yaml b/glide.yaml index 96401aa8c..565682dad 100644 --- a/glide.yaml +++ b/glide.yaml @@ -21,8 +21,9 @@ import: - package: github.com/Masterminds/sprig version: ^2.20.0 - package: github.com/ghodss/yaml + version: c7ce16629ff4cd059ed96ed06419dd3856fd3577 - package: github.com/Masterminds/semver - version: ~1.4.2 + version: ^1.4.2 - package: github.com/technosophos/moniker version: ~0.2 - package: github.com/golang/protobuf diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index 7204f36b9..0514f7f6d 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -55,7 +55,7 @@ func TestBadChart(t *testing.T) { } } if msg.Severity == support.ErrorSev { - if strings.Contains(msg.Err.Error(), "version 0.0.0 is less than or equal to 0") { + if strings.Contains(msg.Err.Error(), "version '0.0.0.0' is not a valid SemVer") { e = true } if strings.Contains(msg.Err.Error(), "name is required") { diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index 8f6c16d94..d851e73ab 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -120,7 +120,7 @@ func validateChartVersion(cf *chart.Metadata) error { return fmt.Errorf("version '%s' is not a valid SemVer", cf.Version) } - c, err := semver.NewConstraint("> 0") + c, err := semver.NewConstraint(">0.0.0-0") if err != nil { return err } diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index a44129acf..4ec091fa7 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -106,7 +106,7 @@ func TestValidateChartVersion(t *testing.T) { ErrorMsg string }{ {"", "version is required"}, - {"0", "0 is less than or equal to 0"}, + {"1.2.3.4", "version '1.2.3.4' is not a valid SemVer"}, {"waps", "'waps' is not a valid SemVer"}, {"-3", "'-3' is not a valid SemVer"}, } @@ -252,7 +252,7 @@ func TestChartfile(t *testing.T) { t.Errorf("Unexpected message 2: %s", msgs[2].Err) } - if !strings.Contains(msgs[3].Err.Error(), "version 0.0.0 is less than or equal to 0") { + if !strings.Contains(msgs[3].Err.Error(), "version '0.0.0.0' is not a valid SemVer") { t.Errorf("Unexpected message 3: %s", msgs[2].Err) } diff --git a/pkg/lint/rules/testdata/badchartfile/Chart.yaml b/pkg/lint/rules/testdata/badchartfile/Chart.yaml index dbb4a1501..c14ed7763 100644 --- a/pkg/lint/rules/testdata/badchartfile/Chart.yaml +++ b/pkg/lint/rules/testdata/badchartfile/Chart.yaml @@ -1,3 +1,3 @@ description: A Helm chart for Kubernetes -version: 0.0.0 +version: 0.0.0.0 home: "" diff --git a/pkg/tiller/release_install_test.go b/pkg/tiller/release_install_test.go index 78d00ce66..0d985b2e5 100644 --- a/pkg/tiller/release_install_test.go +++ b/pkg/tiller/release_install_test.go @@ -502,7 +502,7 @@ func TestInstallRelease_KubeVersion(t *testing.T) { rs := rsFixture() req := installRequest( - withChart(withKube(">=0.0.0")), + withChart(withKube(">=0.0.0-0")), ) _, err := rs.InstallRelease(c, req) if err != nil { From f127b7d73e0905ec06efc816127c8baf77d36cc0 Mon Sep 17 00:00:00 2001 From: Jerome Brette Date: Thu, 19 Sep 2019 18:19:38 +0000 Subject: [PATCH 19/29] Kubernetes 1.16: Migrate Tiller deployment to apps/v1 - Convert Tiller Deployment from extensions/v1betax to apps/v1 - Update installation unit tests - Add support for helm init --upgrade Signed-off-by: Jerome Brette --- cmd/helm/init_test.go | 4 +-- cmd/helm/installer/install.go | 58 +++++++++++++++++++++++------- cmd/helm/installer/install_test.go | 22 ++++++------ 3 files changed, 59 insertions(+), 25 deletions(-) diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index b58303f42..f9b3fcd48 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -28,8 +28,8 @@ import ( "github.com/ghodss/yaml" + appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" - "k8s.io/api/extensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -83,7 +83,7 @@ func TestInitCmd_exists(t *testing.T) { defer os.RemoveAll(home) var buf bytes.Buffer - fc := fake.NewSimpleClientset(&v1beta1.Deployment{ + fc := fake.NewSimpleClientset(&appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: v1.NamespaceDefault, Name: "tiller-deploy", diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index 42c7132db..6cf0cb165 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -24,15 +24,16 @@ import ( "github.com/Masterminds/semver" "github.com/ghodss/yaml" + appsv1 "k8s.io/api/apps/v1" "k8s.io/api/core/v1" - "k8s.io/api/extensions/v1beta1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/kubernetes" + appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1" corev1 "k8s.io/client-go/kubernetes/typed/core/v1" - extensionsclient "k8s.io/client-go/kubernetes/typed/extensions/v1beta1" "k8s.io/helm/pkg/version" "k8s.io/helm/pkg/chartutil" @@ -43,7 +44,7 @@ import ( // // Returns an error if the command failed. func Install(client kubernetes.Interface, opts *Options) error { - if err := createDeployment(client.ExtensionsV1beta1(), opts); err != nil { + if err := createDeployment(client.AppsV1(), opts); err != nil { return err } if err := createService(client.CoreV1(), opts.Namespace); err != nil { @@ -61,10 +62,40 @@ func Install(client kubernetes.Interface, opts *Options) error { // // Returns an error if the command failed. func Upgrade(client kubernetes.Interface, opts *Options) error { - obj, err := client.ExtensionsV1beta1().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{}) - if err != nil { + appsobj, err := client.AppsV1().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{}) + if err == nil { + return upgradeAppsTillerDeployment(client, opts, appsobj) + } + + extensionsobj, err := client.ExtensionsV1beta1().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{}) + if err == nil { + return upgradeExtensionsTillerDeployment(client, opts, extensionsobj) + } + + return err +} + +func upgradeAppsTillerDeployment(client kubernetes.Interface, opts *Options, obj *appsv1.Deployment) error { + tillerImage := obj.Spec.Template.Spec.Containers[0].Image + if semverCompare(tillerImage) == -1 && !opts.ForceUpgrade { + return errors.New("current Tiller version is newer, use --force-upgrade to downgrade") + } + obj.Spec.Template.Spec.Containers[0].Image = opts.SelectImage() + obj.Spec.Template.Spec.Containers[0].ImagePullPolicy = opts.pullPolicy() + obj.Spec.Template.Spec.ServiceAccountName = opts.ServiceAccount + if _, err := client.AppsV1().Deployments(opts.Namespace).Update(obj); err != nil { return err } + // If the service does not exist that would mean we are upgrading from a Tiller version + // that didn't deploy the service, so install it. + _, err := client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return createService(client.CoreV1(), opts.Namespace) + } + return err +} + +func upgradeExtensionsTillerDeployment(client kubernetes.Interface, opts *Options, obj *extensionsv1beta1.Deployment) error { tillerImage := obj.Spec.Template.Spec.Containers[0].Image if semverCompare(tillerImage) == -1 && !opts.ForceUpgrade { return errors.New("current Tiller version is newer, use --force-upgrade to downgrade") @@ -77,7 +108,7 @@ func Upgrade(client kubernetes.Interface, opts *Options) error { } // If the service does not exist that would mean we are upgrading from a Tiller version // that didn't deploy the service, so install it. - _, err = client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) + _, err := client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) if apierrors.IsNotFound(err) { return createService(client.CoreV1(), opts.Namespace) } @@ -105,7 +136,7 @@ func semverCompare(image string) int { } // createDeployment creates the Tiller Deployment resource. -func createDeployment(client extensionsclient.DeploymentsGetter, opts *Options) error { +func createDeployment(client appsv1client.DeploymentsGetter, opts *Options) error { obj, err := generateDeployment(opts) if err != nil { return err @@ -118,7 +149,7 @@ func createDeployment(client extensionsclient.DeploymentsGetter, opts *Options) // Deployment gets a deployment object that can be used to generate a manifest // as a string. This object should not be submitted directly to the Kubernetes // api -func Deployment(opts *Options) (*v1beta1.Deployment, error) { +func Deployment(opts *Options) (*appsv1.Deployment, error) { dep, err := generateDeployment(opts) if err != nil { return nil, err @@ -197,7 +228,7 @@ func parseNodeSelectorsInto(labels string, m map[string]string) error { } return nil } -func generateDeployment(opts *Options) (*v1beta1.Deployment, error) { +func generateDeployment(opts *Options) (*appsv1.Deployment, error) { labels := generateLabels(map[string]string{"name": "tiller"}) nodeSelectors := map[string]string{} if len(opts.NodeSelectors) > 0 { @@ -206,14 +237,17 @@ func generateDeployment(opts *Options) (*v1beta1.Deployment, error) { return nil, err } } - d := &v1beta1.Deployment{ + d := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: opts.Namespace, Name: deploymentName, Labels: labels, }, - Spec: v1beta1.DeploymentSpec{ + Spec: appsv1.DeploymentSpec{ Replicas: opts.getReplicas(), + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, Template: v1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: labels, @@ -297,7 +331,7 @@ func generateDeployment(opts *Options) (*v1beta1.Deployment, error) { // merge them and convert back to Deployment if len(opts.Values) > 0 { // base deployment struct - var dd v1beta1.Deployment + var dd appsv1.Deployment // get YAML from original deployment dy, err := yaml.Marshal(d) if err != nil { diff --git a/cmd/helm/installer/install_test.go b/cmd/helm/installer/install_test.go index 1c7063450..3673712b2 100644 --- a/cmd/helm/installer/install_test.go +++ b/cmd/helm/installer/install_test.go @@ -24,8 +24,8 @@ import ( "testing" "github.com/ghodss/yaml" + appsv1 "k8s.io/api/apps/v1" "k8s.io/api/core/v1" - "k8s.io/api/extensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/fake" @@ -192,7 +192,7 @@ func TestInstall(t *testing.T) { fc := &fake.Clientset{} fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment) l := obj.GetLabels() if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { t.Errorf("expected labels = '', got '%s'", l) @@ -239,7 +239,7 @@ func TestInstallHA(t *testing.T) { fc := &fake.Clientset{} fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment) replicas := obj.Spec.Replicas if int(*replicas) != 2 { t.Errorf("expected replicas = 2, got '%d'", replicas) @@ -263,7 +263,7 @@ func TestInstall_WithTLS(t *testing.T) { fc := &fake.Clientset{} fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment) l := obj.GetLabels() if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { t.Errorf("expected labels = '', got '%s'", l) @@ -331,7 +331,7 @@ func TestInstall_WithTLS(t *testing.T) { func TestInstall_canary(t *testing.T) { fc := &fake.Clientset{} fc.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.CreateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.CreateAction).GetObject().(*appsv1.Deployment) i := obj.Spec.Template.Spec.Containers[0].Image if i != "gcr.io/kubernetes-helm/tiller:canary" { t.Errorf("expected canary image, got '%s'", i) @@ -369,7 +369,7 @@ func TestUpgrade(t *testing.T) { return true, existingDeployment, nil }) fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment) i := obj.Spec.Template.Spec.Containers[0].Image if i != image { t.Errorf("expected image = '%s', got '%s'", image, i) @@ -408,7 +408,7 @@ func TestUpgrade_serviceNotFound(t *testing.T) { return true, existingDeployment, nil }) fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment) i := obj.Spec.Template.Spec.Containers[0].Image if i != image { t.Errorf("expected image = '%s', got '%s'", image, i) @@ -453,7 +453,7 @@ func TestUgrade_newerVersion(t *testing.T) { return true, existingDeployment, nil }) fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment) i := obj.Spec.Template.Spec.Containers[0].Image if i != image { t.Errorf("expected image = '%s', got '%s'", image, i) @@ -513,7 +513,7 @@ func TestUpgrade_identical(t *testing.T) { return true, existingDeployment, nil }) fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment) i := obj.Spec.Template.Spec.Containers[0].Image if i != image { t.Errorf("expected image = '%s', got '%s'", image, i) @@ -554,7 +554,7 @@ func TestUpgrade_canaryClient(t *testing.T) { return true, existingDeployment, nil }) fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment) i := obj.Spec.Template.Spec.Containers[0].Image if i != image { t.Errorf("expected image = '%s', got '%s'", image, i) @@ -595,7 +595,7 @@ func TestUpgrade_canaryServer(t *testing.T) { return true, existingDeployment, nil }) fc.AddReactor("update", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { - obj := action.(testcore.UpdateAction).GetObject().(*v1beta1.Deployment) + obj := action.(testcore.UpdateAction).GetObject().(*appsv1.Deployment) i := obj.Spec.Template.Spec.Containers[0].Image if i != image { t.Errorf("expected image = '%s', got '%s'", image, i) From 16cfe346a358d6edc66c248b76c62a22757d0a90 Mon Sep 17 00:00:00 2001 From: Jerome Brette Date: Thu, 19 Sep 2019 20:13:46 +0000 Subject: [PATCH 20/29] Kubernetes 1.16: Improve upgrade support Tested with versions: - kubernetes v1.16.0 - kubernetes v1.15.4 - kubernetes v1.14.7 - kubernetes v1.13.11 - kubernetes v1.12.10 Signed-off-by: Jerome Brette --- cmd/helm/init.go | 2 +- cmd/helm/installer/install.go | 69 ++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/cmd/helm/init.go b/cmd/helm/init.go index f02700508..4dcb434f3 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -282,7 +282,7 @@ func (i *initCmd) run() error { if err := i.ping(i.opts.SelectImage()); err != nil { return err } - fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been upgraded to the current version.") + fmt.Fprintln(i.out, "\nTiller (the Helm server-side component) has been updated to", i.opts.SelectImage(), ".") } else { debug("The error received while trying to init: %s", err) fmt.Fprintln(i.out, "Warning: Tiller is already installed in the cluster.\n"+ diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index 6cf0cb165..504b0183d 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -17,7 +17,6 @@ limitations under the License. package installer // import "k8s.io/helm/cmd/helm/installer" import ( - "errors" "fmt" "io/ioutil" "strings" @@ -34,7 +33,6 @@ import ( "k8s.io/client-go/kubernetes" appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1" corev1 "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/helm/pkg/version" "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/tiller/environment" @@ -64,11 +62,17 @@ func Install(client kubernetes.Interface, opts *Options) error { func Upgrade(client kubernetes.Interface, opts *Options) error { appsobj, err := client.AppsV1().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{}) if err == nil { + // Can happen in two cases: + // 1. helm init inserted an apps/v1 Deployment up front in Kubernetes + // 2. helm init inserted an extensions/v1beta1 Deployment against a K8s cluster already + // supporting apps/v1 Deployment. In such a case K8s is returning the apps/v1 object anyway.` + // (for the same reason "kubectl convert" is being deprecated) return upgradeAppsTillerDeployment(client, opts, appsobj) } extensionsobj, err := client.ExtensionsV1beta1().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{}) if err == nil { + // User performed helm init against older version of kubernetes (Previous to 1.9) return upgradeExtensionsTillerDeployment(client, opts, extensionsobj) } @@ -76,65 +80,86 @@ func Upgrade(client kubernetes.Interface, opts *Options) error { } func upgradeAppsTillerDeployment(client kubernetes.Interface, opts *Options, obj *appsv1.Deployment) error { - tillerImage := obj.Spec.Template.Spec.Containers[0].Image - if semverCompare(tillerImage) == -1 && !opts.ForceUpgrade { - return errors.New("current Tiller version is newer, use --force-upgrade to downgrade") + // Update the PodTemplateSpec section of the deployment + if err := updatePodTemplate(&obj.Spec.Template.Spec, opts); err != nil { + return err } - obj.Spec.Template.Spec.Containers[0].Image = opts.SelectImage() - obj.Spec.Template.Spec.Containers[0].ImagePullPolicy = opts.pullPolicy() - obj.Spec.Template.Spec.ServiceAccountName = opts.ServiceAccount + if _, err := client.AppsV1().Deployments(opts.Namespace).Update(obj); err != nil { return err } + // If the service does not exist that would mean we are upgrading from a Tiller version // that didn't deploy the service, so install it. _, err := client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) if apierrors.IsNotFound(err) { return createService(client.CoreV1(), opts.Namespace) } + return err } func upgradeExtensionsTillerDeployment(client kubernetes.Interface, opts *Options, obj *extensionsv1beta1.Deployment) error { - tillerImage := obj.Spec.Template.Spec.Containers[0].Image - if semverCompare(tillerImage) == -1 && !opts.ForceUpgrade { - return errors.New("current Tiller version is newer, use --force-upgrade to downgrade") + // Update the PodTemplateSpec section of the deployment + if err := updatePodTemplate(&obj.Spec.Template.Spec, opts); err != nil { + return err } - obj.Spec.Template.Spec.Containers[0].Image = opts.SelectImage() - obj.Spec.Template.Spec.Containers[0].ImagePullPolicy = opts.pullPolicy() - obj.Spec.Template.Spec.ServiceAccountName = opts.ServiceAccount + if _, err := client.ExtensionsV1beta1().Deployments(opts.Namespace).Update(obj); err != nil { return err } + // If the service does not exist that would mean we are upgrading from a Tiller version // that didn't deploy the service, so install it. _, err := client.CoreV1().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) if apierrors.IsNotFound(err) { return createService(client.CoreV1(), opts.Namespace) } + return err } -// semverCompare returns whether the client's version is older, equal or newer than the given image's version. -func semverCompare(image string) int { - split := strings.Split(image, ":") - if len(split) < 2 { - // If we don't know the version, we consider the client version newer. - return 1 +func updatePodTemplate(podSpec *v1.PodSpec, opts *Options) error { + tillerImage := podSpec.Containers[0].Image + clientImage := opts.SelectImage() + + if semverCompare(tillerImage, clientImage) == -1 && !opts.ForceUpgrade { + return fmt.Errorf("current Tiller version %s is newer than client version %s, use --force-upgrade to downgrade", tillerImage, clientImage) } - tillerVersion, err := semver.NewVersion(split[1]) + podSpec.Containers[0].Image = clientImage + podSpec.Containers[0].ImagePullPolicy = opts.pullPolicy() + podSpec.ServiceAccountName = opts.ServiceAccount + + return nil +} + +// semverCompare returns whether the client's version is older, equal or newer than the given image's version. +func semverCompare(tillerImage, clientImage string) int { + tillerVersion, err := string2semver(tillerImage) if err != nil { // same thing with unparsable tiller versions (e.g. canary releases). return 1 } - clientVersion, err := semver.NewVersion(version.Version) + + // clientVersion, err := semver.NewVersion(currentVersion) + clientVersion, err := string2semver(clientImage) if err != nil { // aaaaaand same thing with unparsable helm versions (e.g. canary releases). return 1 } + return clientVersion.Compare(tillerVersion) } +func string2semver(image string) (*semver.Version, error) { + split := strings.Split(image, ":") + if len(split) < 2 { + // If we don't know the version, we consider the client version newer. + return nil, fmt.Errorf("no repository in image %s", image) + } + return semver.NewVersion(split[1]) +} + // createDeployment creates the Tiller Deployment resource. func createDeployment(client appsv1client.DeploymentsGetter, opts *Options) error { obj, err := generateDeployment(opts) From a52d6de9e17fc4dda4928f0029362e9be075aa24 Mon Sep 17 00:00:00 2001 From: Michael Schaefer Date: Fri, 12 Apr 2019 07:49:12 +0200 Subject: [PATCH 21/29] flag for output json or yaml added in install.go, repo_list.go, search.go, status.go and upgrade.go. unit test adapted for output json or yaml in install_test.go and search_test.go. docs modified for new flag helm_install.md, helm_repo_list.md, helm_search.md and helm_upgrade.md Signed-off-by: Michael Schaefer --- cmd/helm/install.go | 17 +++++++- cmd/helm/install_test.go | 16 +++++++ cmd/helm/repo_list.go | 84 +++++++++++++++++++++++++++++++------ cmd/helm/search.go | 72 +++++++++++++++++++++++++++---- cmd/helm/search_test.go | 26 ++++++++++++ cmd/helm/status.go | 83 +++++++++++++++++++++++------------- cmd/helm/upgrade.go | 16 +++++-- docs/helm/helm_install.md | 3 +- docs/helm/helm_repo_list.md | 5 ++- docs/helm/helm_search.md | 3 +- docs/helm/helm_status.md | 4 +- docs/helm/helm_upgrade.md | 3 +- 12 files changed, 272 insertions(+), 60 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 23f307564..a0fa6edfb 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -143,6 +143,7 @@ type installCmd struct { certFile string keyFile string caFile string + output string } type valueFiles []string @@ -226,6 +227,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&inst.depUp, "dep-up", false, "Run helm dependency update before installing the chart") f.BoolVar(&inst.subNotes, "render-subchart-notes", false, "Render subchart notes along with the parent") f.StringVar(&inst.description, "description", "", "Specify a description for the release") + f.StringVarP(&inst.output, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") // set defaults from environment settings.InitTLS(f) @@ -335,7 +337,10 @@ func (i *installCmd) run() error { if rel == nil { return nil } - i.printRelease(rel) + + if i.output == "table" { + i.printRelease(rel) + } // If this is a dry run, we can't display status. if i.dryRun { @@ -351,7 +356,15 @@ func (i *installCmd) run() error { if err != nil { return prettyError(err) } - PrintStatus(i.out, status) + + output, err := PrintStatusFormated(i.output, status) + + if err != nil { + return err + } + + fmt.Fprintf(i.out, output) + return nil } diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index 24a5abe68..e00c33a81 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -191,6 +191,22 @@ func TestInstall(t *testing.T) { flags: []string{"--name-template", "{{UPPER \"foobar\"}}"}, err: true, }, + // Install, using --output json + { + name: "install using output json", + args: []string{"testdata/testcharts/alpine"}, + flags: strings.Split("--name virgil --output json", " "), + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), + expected: regexp.QuoteMeta(`{"name":"virgil","info":{"status":{"code":1},"first_deployed":{"seconds":242085845},"last_deployed":{"seconds":242085845},"Description":"Release mock"},"namespace":"default"}`), + }, + // Install, using --output yaml + { + name: "install using output yaml", + args: []string{"testdata/testcharts/alpine"}, + flags: strings.Split("--name virgil --output yaml", " "), + resp: helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}), + expected: "info:\n Description: Release mock\n first_deployed:\n seconds: 242085845\n last_deployed:\n seconds: 242085845\n status:\n code: 1\nname: virgil\nnamespace: default\n", + }, } runReleaseCases(t, tests, func(c *helm.FakeClient, out io.Writer) *cobra.Command { diff --git a/cmd/helm/repo_list.go b/cmd/helm/repo_list.go index 5983bca97..633bb7a75 100644 --- a/cmd/helm/repo_list.go +++ b/cmd/helm/repo_list.go @@ -17,10 +17,12 @@ limitations under the License. package main import ( - "errors" + "encoding/json" "fmt" "io" + "strings" + "github.com/ghodss/yaml" "github.com/gosuri/uitable" "github.com/spf13/cobra" @@ -29,8 +31,18 @@ import ( ) type repoListCmd struct { - out io.Writer - home helmpath.Home + out io.Writer + home helmpath.Home + output string +} + +type repositoryElement struct { + Name string + URL string +} + +type repositories struct { + Repositories []*repositoryElement } func newRepoListCmd(out io.Writer) *cobra.Command { @@ -45,22 +57,70 @@ func newRepoListCmd(out io.Writer) *cobra.Command { }, } + f := cmd.Flags() + f.StringVarP(&list.output, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") return cmd } func (a *repoListCmd) run() error { - f, err := repo.LoadRepositoriesFile(a.home.RepositoryFile()) + repoFile, err := repo.LoadRepositoriesFile(a.home.RepositoryFile()) if err != nil { return err } - if len(f.Repositories) == 0 { - return errors.New("no repositories to show") - } - table := uitable.New() - table.AddRow("NAME", "URL") - for _, re := range f.Repositories { - table.AddRow(re.Name, re.URL) + + output, err := formatRepoListResult(a.output, repoFile) + + if err != nil { + return err } - fmt.Fprintln(a.out, table) + fmt.Fprintln(a.out, output) + return nil } + +func formatRepoListResult(format string, repoFile *repo.RepoFile) (string, error) { + var output string + var err error + + if len(repoFile.Repositories) == 0 { + err = fmt.Errorf("no repositories to show") + return output, err + } + + switch format { + case "table": + table := uitable.New() + table.AddRow("NAME", "URL") + for _, re := range repoFile.Repositories { + table.AddRow(re.Name, re.URL) + } + output = table.String() + + case "json": + output, err = printFormatedRepoFile(format, repoFile, json.Marshal) + + case "yaml": + output, err = printFormatedRepoFile(format, repoFile, yaml.Marshal) + } + + return output, err +} + +func printFormatedRepoFile(format string, repoFile *repo.RepoFile, obj func(v interface{}) ([]byte, error)) (string, error) { + var output string + var err error + var repolist repositories + + for _, re := range repoFile.Repositories { + repolist.Repositories = append(repolist.Repositories, &repositoryElement{Name: re.Name, URL: re.URL}) + } + + o, e := obj(repolist) + if e != nil { + err = fmt.Errorf("Failed to Marshal %s output: %s", strings.ToUpper(format), e) + } else { + output = string(o) + } + + return output, err +} diff --git a/cmd/helm/search.go b/cmd/helm/search.go index 99ffafbd3..92e842823 100644 --- a/cmd/helm/search.go +++ b/cmd/helm/search.go @@ -17,11 +17,13 @@ limitations under the License. package main import ( + "encoding/json" "fmt" "io" "strings" "github.com/Masterminds/semver" + "github.com/ghodss/yaml" "github.com/gosuri/uitable" "github.com/spf13/cobra" @@ -48,6 +50,18 @@ type searchCmd struct { regexp bool version string colWidth uint + output string +} + +type chartElement struct { + Name string + Version string + AppVersion string + Description string +} + +type searchResult struct { + Charts []*chartElement } func newSearchCmd(out io.Writer) *cobra.Command { @@ -68,6 +82,7 @@ func newSearchCmd(out io.Writer) *cobra.Command { f.BoolVarP(&sc.versions, "versions", "l", false, "Show the long listing, with each version of each chart on its own line") f.StringVarP(&sc.version, "version", "v", "", "Search using semantic versioning constraints") f.UintVar(&sc.colWidth, "col-width", 60, "Specifies the max column width of output") + f.StringVarP(&sc.output, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") return cmd } @@ -95,7 +110,12 @@ func (s *searchCmd) run(args []string) error { return err } - fmt.Fprintln(s.out, s.formatSearchResults(data, s.colWidth)) + o, err := s.formatSearchResults(s.output, data, s.colWidth) + if err != nil { + return err + } + + fmt.Fprintln(s.out, o) return nil } @@ -128,17 +148,53 @@ func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, err return data, nil } -func (s *searchCmd) formatSearchResults(res []*search.Result, colWidth uint) string { +func (s *searchCmd) formatSearchResults(format string, res []*search.Result, colWidth uint) (string, error) { + var output string + var err error + + switch format { + case "table": + if len(res) == 0 { + return "No results found", nil + } + table := uitable.New() + table.MaxColWidth = colWidth + table.AddRow("NAME", "CHART VERSION", "APP VERSION", "DESCRIPTION") + for _, r := range res { + table.AddRow(r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description) + } + output = table.String() + + case "json": + output, err = s.printFormated(format, res, json.Marshal) + + case "yaml": + output, err = s.printFormated(format, res, yaml.Marshal) + } + + return output, err +} + +func (s *searchCmd) printFormated(format string, res []*search.Result, obj func(v interface{}) ([]byte, error)) (string, error) { + var sResult searchResult + var output string + var err error + if len(res) == 0 { - return "No results found" + return "[]", nil } - table := uitable.New() - table.MaxColWidth = colWidth - table.AddRow("NAME", "CHART VERSION", "APP VERSION", "DESCRIPTION") + for _, r := range res { - table.AddRow(r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description) + sResult.Charts = append(sResult.Charts, &chartElement{r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description}) + } + + o, e := obj(sResult) + if e != nil { + err = fmt.Errorf("Failed to Marshal %s output: %s", strings.ToUpper(format), e) + } else { + output = string(o) } - return table.String() + return output, err } func (s *searchCmd) buildIndex() (*search.Index, error) { diff --git a/cmd/helm/search_test.go b/cmd/helm/search_test.go index 233f94572..35a72260e 100644 --- a/cmd/helm/search_test.go +++ b/cmd/helm/search_test.go @@ -18,6 +18,8 @@ package main import ( "io" + "regexp" + "strings" "testing" "github.com/spf13/cobra" @@ -84,6 +86,30 @@ func TestSearchCmd(t *testing.T) { flags: []string{"--regexp"}, err: true, }, + { + name: "search for 'maria', expect one match output json", + args: []string{"maria"}, + flags: strings.Split("--output json", " "), + expected: regexp.QuoteMeta(`{"Charts":[{"Name":"testing/mariadb","Version":"0.3.0","AppVersion":"","Description":"Chart for MariaDB"}]}`), + }, + { + name: "search for 'alpine', expect two matches output json", + args: []string{"alpine"}, + flags: strings.Split("--output json", " "), + expected: regexp.QuoteMeta(`{"Charts":[{"Name":"testing/alpine","Version":"0.2.0","AppVersion":"2.3.4","Description":"Deploy a basic Alpine Linux pod"}]}`), + }, + { + name: "search for 'maria', expect one match output yaml", + args: []string{"maria"}, + flags: strings.Split("--output yaml", " "), + expected: "Charts:\n- AppVersion: \"\"\n Description: Chart for MariaDB\n Name: testing/mariadb\n Version: 0.3.0\n\n", + }, + { + name: "search for 'alpine', expect two matches output yaml", + args: []string{"alpine"}, + flags: strings.Split("--output yaml", " "), + expected: "Charts:\n- AppVersion: 2.3.4\n Description: Deploy a basic Alpine Linux pod\n Name: testing/alpine\n Version: 0.2.0\n\n", + }, } cleanup := resetEnv() diff --git a/cmd/helm/status.go b/cmd/helm/status.go index dac91916b..65025c8cc 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "regexp" + "strings" "text/tabwriter" "github.com/ghodss/yaml" @@ -79,7 +80,7 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command { f := cmd.Flags() settings.AddFlagsTLS(f) f.Int32Var(&status.version, "revision", 0, "If set, display the status of the named release with revision") - f.StringVarP(&status.outfmt, "output", "o", "", "Output the status in the specified format (json or yaml)") + f.StringVarP(&status.outfmt, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") // set defaults from environment settings.InitTLS(f) @@ -93,56 +94,82 @@ func (s *statusCmd) run() error { return prettyError(err) } - switch s.outfmt { - case "": - PrintStatus(s.out, res) - return nil + output, err := PrintStatusFormated(s.outfmt, res) + + if err != nil { + return err + } + + fmt.Fprintf(s.out, output) + + return nil +} + +// PrintStatusFormated prints out the status of a release. Shared because also used by +// install / upgrade +func PrintStatusFormated(format string, res *services.GetReleaseStatusResponse) (string, error) { + var output string + var err error + + switch format { + case "table": + output = printStatus(res) + case "json": - data, err := json.Marshal(res) - if err != nil { - return fmt.Errorf("Failed to Marshal JSON output: %s", err) - } - s.out.Write(data) - return nil + output, err = printFormatedReleaseStatus(format, res, json.Marshal) + case "yaml": - data, err := yaml.Marshal(res) - if err != nil { - return fmt.Errorf("Failed to Marshal YAML output: %s", err) - } - s.out.Write(data) - return nil + output, err = printFormatedReleaseStatus(format, res, yaml.Marshal) + + default: + err = fmt.Errorf("Unknown output format %q", err) } - return fmt.Errorf("Unknown output format %q", s.outfmt) + return output, err } -// PrintStatus prints out the status of a release. Shared because also used by -// install / upgrade -func PrintStatus(out io.Writer, res *services.GetReleaseStatusResponse) { +func printFormatedReleaseStatus(format string, res *services.GetReleaseStatusResponse, obj func(v interface{}) ([]byte, error)) (string, error) { + var output string + var err error + + o, err := obj(res) + if err != nil { + return "", fmt.Errorf("Failed to Marshal %s output: %s", strings.ToUpper(format), err) + } + output = string(o) + + return output, err +} + +func printStatus(res *services.GetReleaseStatusResponse) string { + var out strings.Builder + if res.Info.LastDeployed != nil { - fmt.Fprintf(out, "LAST DEPLOYED: %s\n", timeconv.String(res.Info.LastDeployed)) + fmt.Fprintf(&out, "LAST DEPLOYED: %s\n", timeconv.String(res.Info.LastDeployed)) } - fmt.Fprintf(out, "NAMESPACE: %s\n", res.Namespace) - fmt.Fprintf(out, "STATUS: %s\n", res.Info.Status.Code) - fmt.Fprintf(out, "\n") + fmt.Fprintf(&out, "NAMESPACE: %s\n", res.Namespace) + fmt.Fprintf(&out, "STATUS: %s\n", res.Info.Status.Code) + fmt.Fprintf(&out, "\n") if len(res.Info.Status.Resources) > 0 { re := regexp.MustCompile(" +") - w := tabwriter.NewWriter(out, 0, 0, 2, ' ', tabwriter.TabIndent) + w := tabwriter.NewWriter(&out, 0, 0, 2, ' ', tabwriter.TabIndent) fmt.Fprintf(w, "RESOURCES:\n%s\n", re.ReplaceAllString(res.Info.Status.Resources, "\t")) w.Flush() } if res.Info.Status.LastTestSuiteRun != nil { lastRun := res.Info.Status.LastTestSuiteRun - fmt.Fprintf(out, "TEST SUITE:\n%s\n%s\n\n%s\n", + fmt.Fprintf(&out, "TEST SUITE:\n%s\n%s\n\n%s\n", fmt.Sprintf("Last Started: %s", timeconv.String(lastRun.StartedAt)), fmt.Sprintf("Last Completed: %s", timeconv.String(lastRun.CompletedAt)), formatTestResults(lastRun.Results)) } if len(res.Info.Status.Notes) > 0 { - fmt.Fprintf(out, "NOTES:\n%s\n", res.Info.Status.Notes) + fmt.Fprintf(&out, "NOTES:\n%s\n", res.Info.Status.Notes) } + + return out.String() } func formatTestResults(results []*release.TestRun) string { diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index aa4bebeef..5c5af66cc 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -117,6 +117,7 @@ type upgradeCmd struct { certFile string keyFile string caFile string + output string } func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { @@ -181,6 +182,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&upgrade.subNotes, "render-subchart-notes", false, "Render subchart notes along with parent") f.StringVar(&upgrade.description, "description", "", "Specify the description to use for the upgrade, rather than the default") f.BoolVar(&upgrade.cleanupOnFail, "cleanup-on-fail", false, "Allow deletion of new resources created in this upgrade when upgrade failed") + f.StringVarP(&upgrade.output, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") f.MarkDeprecated("disable-hooks", "Use --no-hooks instead") @@ -307,14 +309,22 @@ func (u *upgradeCmd) run() error { printRelease(u.out, resp.Release) } - fmt.Fprintf(u.out, "Release %q has been upgraded.\n", u.release) - + if u.output == "table" { + fmt.Fprintf(u.out, "Release %q has been upgraded.\n", u.release) + } // Print the status like status command does status, err := u.client.ReleaseStatus(u.release) if err != nil { return prettyError(err) } - PrintStatus(u.out, status) + + output, err := PrintStatusFormated(u.output, status) + + if err != nil { + return err + } + + fmt.Fprintf(u.out, output) return nil } diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index d988dfcdd..dc0591f6a 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -93,6 +93,7 @@ helm install [CHART] [flags] --namespace string Namespace to install the release into. Defaults to the current kube config namespace. --no-crd-hook Prevent CRD hooks from running, but run other hooks --no-hooks Prevent hooks from running during install + -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") --password string Chart repository password where to locate the requested chart --render-subchart-notes Render subchart notes along with the parent --replace Re-use the given name, even if that name is already used. This is unsafe in production @@ -130,4 +131,4 @@ helm install [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 16-May-2019 +###### Auto generated by spf13/cobra on 24-Sep-2019 diff --git a/docs/helm/helm_repo_list.md b/docs/helm/helm_repo_list.md index 9a544a6ba..5f13c8c2d 100644 --- a/docs/helm/helm_repo_list.md +++ b/docs/helm/helm_repo_list.md @@ -13,7 +13,8 @@ helm repo list [flags] ### Options ``` - -h, --help help for list + -h, --help help for list + -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") ``` ### Options inherited from parent commands @@ -32,4 +33,4 @@ helm repo list [flags] * [helm repo](helm_repo.md) - Add, list, remove, update, and index chart repositories -###### Auto generated by spf13/cobra on 16-May-2019 +###### Auto generated by spf13/cobra on 24-Sep-2019 diff --git a/docs/helm/helm_search.md b/docs/helm/helm_search.md index b1a89c4f9..e040b738f 100644 --- a/docs/helm/helm_search.md +++ b/docs/helm/helm_search.md @@ -20,6 +20,7 @@ helm search [keyword] [flags] ``` --col-width uint Specifies the max column width of output (default 60) -h, --help help for search + -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") -r, --regexp Use regular expressions for searching -v, --version string Search using semantic versioning constraints -l, --versions Show the long listing, with each version of each chart on its own line @@ -41,4 +42,4 @@ helm search [keyword] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 16-May-2019 +###### Auto generated by spf13/cobra on 24-Sep-2019 diff --git a/docs/helm/helm_status.md b/docs/helm/helm_status.md index 38e774b8f..2c75ce21a 100644 --- a/docs/helm/helm_status.md +++ b/docs/helm/helm_status.md @@ -23,7 +23,7 @@ helm status [flags] RELEASE_NAME ``` -h, --help help for status - -o, --output string Output the status in the specified format (json or yaml) + -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") --revision int32 If set, display the status of the named release with revision --tls Enable TLS for request --tls-ca-cert string Path to TLS CA certificate file (default "$HELM_HOME/ca.pem") @@ -49,4 +49,4 @@ helm status [flags] RELEASE_NAME * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 16-May-2019 +###### Auto generated by spf13/cobra on 6-Sep-2019 diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index 0aa52565b..effb505f9 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -79,6 +79,7 @@ helm upgrade [RELEASE] [CHART] [flags] --keyring string Path to the keyring that contains public signing keys (default "~/.gnupg/pubring.gpg") --namespace string Namespace to install the release into (only used if --install is set). Defaults to the current kube config namespace --no-hooks Disable pre/post upgrade hooks + -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") --password string Chart repository password where to locate the requested chart --recreate-pods Performs pods restart for the resource if applicable --render-subchart-notes Render subchart notes along with parent @@ -118,4 +119,4 @@ helm upgrade [RELEASE] [CHART] [flags] * [helm](helm.md) - The Helm package manager for Kubernetes. -###### Auto generated by spf13/cobra on 16-May-2019 +###### Auto generated by spf13/cobra on 24-Sep-2019 From 3e5b181a300bcfbdf2abff990904e4f5f3e8fc35 Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Fri, 6 Sep 2019 15:34:24 -0600 Subject: [PATCH 22/29] ref(cmd): Refactors output flag to reuse more code This cuts down on the number of duplicate json/yaml marshaling blocks and simplifies how to add printing to a function by using simple "container" structs that know how to massage the data Signed-off-by: Taylor Thomas --- cmd/helm/install.go | 14 +---- cmd/helm/printer.go | 78 ++++++++++++++++++++++++ cmd/helm/repo_list.go | 82 ++++++++++--------------- cmd/helm/search.go | 116 ++++++++++++++++-------------------- cmd/helm/search_test.go | 9 ++- cmd/helm/status.go | 78 ++++++++---------------- cmd/helm/upgrade.go | 14 +---- docs/helm/helm_install.md | 2 +- docs/helm/helm_repo_list.md | 2 +- docs/helm/helm_search.md | 2 +- docs/helm/helm_status.md | 2 +- docs/helm/helm_upgrade.md | 2 +- 12 files changed, 199 insertions(+), 202 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index a0fa6edfb..117c7ba5b 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -227,7 +227,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&inst.depUp, "dep-up", false, "Run helm dependency update before installing the chart") f.BoolVar(&inst.subNotes, "render-subchart-notes", false, "Render subchart notes along with the parent") f.StringVar(&inst.description, "description", "", "Specify a description for the release") - f.StringVarP(&inst.output, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") + bindOutputFlag(cmd, &inst.output) // set defaults from environment settings.InitTLS(f) @@ -338,7 +338,7 @@ func (i *installCmd) run() error { return nil } - if i.output == "table" { + if outputFormat(i.output) == outputTable { i.printRelease(rel) } @@ -357,15 +357,7 @@ func (i *installCmd) run() error { return prettyError(err) } - output, err := PrintStatusFormated(i.output, status) - - if err != nil { - return err - } - - fmt.Fprintf(i.out, output) - - return nil + return write(i.out, &statusWriter{status}, outputFormat(i.output)) } // Merges source and destination map, preferring values from the source map diff --git a/cmd/helm/printer.go b/cmd/helm/printer.go index 2f42bdab0..1c89c04ef 100644 --- a/cmd/helm/printer.go +++ b/cmd/helm/printer.go @@ -17,16 +17,31 @@ limitations under the License. package main import ( + "encoding/json" "fmt" "io" "text/template" "time" + "github.com/ghodss/yaml" + "github.com/gosuri/uitable" + "github.com/spf13/cobra" + "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/timeconv" ) +type outputFormat string + +const ( + outputFlag = "output" + + outputTable outputFormat = "table" + outputJSON outputFormat = "json" + outputYAML outputFormat = "yaml" +) + var printReleaseTemplate = `REVISION: {{.Release.Version}} RELEASED: {{.ReleaseDate}} CHART: {{.Release.Chart.Metadata.Name}}-{{.Release.Chart.Metadata.Version}} @@ -80,3 +95,66 @@ func debug(format string, args ...interface{}) { fmt.Printf(format, args...) } } + +// bindOutputFlag will add the output flag to the given command and bind the +// value to the given string pointer +func bindOutputFlag(cmd *cobra.Command, varRef *string) { + cmd.Flags().StringVarP(varRef, outputFlag, "o", string(outputTable), fmt.Sprintf("Prints the output in the specified format. Allowed values: %s, %s, %s", outputTable, outputJSON, outputYAML)) +} + +type outputWriter interface { + WriteTable(out io.Writer) error + WriteJSON(out io.Writer) error + WriteYAML(out io.Writer) error +} + +func write(out io.Writer, ow outputWriter, format outputFormat) error { + switch format { + case outputTable: + return ow.WriteTable(out) + case outputJSON: + return ow.WriteJSON(out) + case outputYAML: + return ow.WriteYAML(out) + } + return fmt.Errorf("unsupported format %s", format) +} + +// encodeJSON is a helper function to decorate any error message with a bit more +// context and avoid writing the same code over and over for printers +func encodeJSON(out io.Writer, obj interface{}) error { + enc := json.NewEncoder(out) + err := enc.Encode(obj) + if err != nil { + return fmt.Errorf("unable to write JSON output: %s", err) + } + return nil +} + +// encodeYAML is a helper function to decorate any error message with a bit more +// context and avoid writing the same code over and over for printers +func encodeYAML(out io.Writer, obj interface{}) error { + raw, err := yaml.Marshal(obj) + if err != nil { + return fmt.Errorf("unable to write YAML output: %s", err) + } + // Append a newline, as with a JSON encoder + raw = append(raw, []byte("\n")...) + _, err = out.Write(raw) + if err != nil { + return fmt.Errorf("unable to write YAML output: %s", err) + } + return nil +} + +// encodeTable is a helper function to decorate any error message with a bit +// more context and avoid writing the same code over and over for printers +func encodeTable(out io.Writer, table *uitable.Table) error { + raw := table.Bytes() + raw = append(raw, []byte("\n")...) + _, err := out.Write(raw) + if err != nil { + return fmt.Errorf("unable to write table output: %s", err) + } + return nil +} diff --git a/cmd/helm/repo_list.go b/cmd/helm/repo_list.go index 633bb7a75..a65b81908 100644 --- a/cmd/helm/repo_list.go +++ b/cmd/helm/repo_list.go @@ -17,12 +17,8 @@ limitations under the License. package main import ( - "encoding/json" - "fmt" "io" - "strings" - "github.com/ghodss/yaml" "github.com/gosuri/uitable" "github.com/spf13/cobra" @@ -41,10 +37,6 @@ type repositoryElement struct { URL string } -type repositories struct { - Repositories []*repositoryElement -} - func newRepoListCmd(out io.Writer) *cobra.Command { list := &repoListCmd{out: out} @@ -57,8 +49,7 @@ func newRepoListCmd(out io.Writer) *cobra.Command { }, } - f := cmd.Flags() - f.StringVarP(&list.output, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") + bindOutputFlag(cmd, &list.output) return cmd } @@ -68,59 +59,46 @@ func (a *repoListCmd) run() error { return err } - output, err := formatRepoListResult(a.output, repoFile) - - if err != nil { - return err - } - fmt.Fprintln(a.out, output) - - return nil + return write(a.out, &repoListWriter{repoFile.Repositories}, outputFormat(a.output)) } -func formatRepoListResult(format string, repoFile *repo.RepoFile) (string, error) { - var output string - var err error +//////////// Printer implementation below here +type repoListWriter struct { + repos []*repo.Entry +} - if len(repoFile.Repositories) == 0 { - err = fmt.Errorf("no repositories to show") - return output, err +func (r *repoListWriter) WriteTable(out io.Writer) error { + table := uitable.New() + table.AddRow("NAME", "URL") + for _, re := range r.repos { + table.AddRow(re.Name, re.URL) } + return encodeTable(out, table) +} - switch format { - case "table": - table := uitable.New() - table.AddRow("NAME", "URL") - for _, re := range repoFile.Repositories { - table.AddRow(re.Name, re.URL) - } - output = table.String() - - case "json": - output, err = printFormatedRepoFile(format, repoFile, json.Marshal) - - case "yaml": - output, err = printFormatedRepoFile(format, repoFile, yaml.Marshal) - } +func (r *repoListWriter) WriteJSON(out io.Writer) error { + return r.encodeByFormat(out, outputJSON) +} - return output, err +func (r *repoListWriter) WriteYAML(out io.Writer) error { + return r.encodeByFormat(out, outputYAML) } -func printFormatedRepoFile(format string, repoFile *repo.RepoFile, obj func(v interface{}) ([]byte, error)) (string, error) { - var output string - var err error - var repolist repositories +func (r *repoListWriter) encodeByFormat(out io.Writer, format outputFormat) error { + var repolist []repositoryElement - for _, re := range repoFile.Repositories { - repolist.Repositories = append(repolist.Repositories, &repositoryElement{Name: re.Name, URL: re.URL}) + for _, re := range r.repos { + repolist = append(repolist, repositoryElement{Name: re.Name, URL: re.URL}) } - o, e := obj(repolist) - if e != nil { - err = fmt.Errorf("Failed to Marshal %s output: %s", strings.ToUpper(format), e) - } else { - output = string(o) + switch format { + case outputJSON: + return encodeJSON(out, repolist) + case outputYAML: + return encodeYAML(out, repolist) } - return output, err + // Because this is a non-exported function and only called internally by + // WriteJSON and WriteYAML, we shouldn't get invalid types + return nil } diff --git a/cmd/helm/search.go b/cmd/helm/search.go index 92e842823..b55997ec8 100644 --- a/cmd/helm/search.go +++ b/cmd/helm/search.go @@ -17,13 +17,11 @@ limitations under the License. package main import ( - "encoding/json" "fmt" "io" "strings" "github.com/Masterminds/semver" - "github.com/ghodss/yaml" "github.com/gosuri/uitable" "github.com/spf13/cobra" @@ -60,10 +58,6 @@ type chartElement struct { Description string } -type searchResult struct { - Charts []*chartElement -} - func newSearchCmd(out io.Writer) *cobra.Command { sc := &searchCmd{out: out} @@ -82,7 +76,7 @@ func newSearchCmd(out io.Writer) *cobra.Command { f.BoolVarP(&sc.versions, "versions", "l", false, "Show the long listing, with each version of each chart on its own line") f.StringVarP(&sc.version, "version", "v", "", "Search using semantic versioning constraints") f.UintVar(&sc.colWidth, "col-width", 60, "Specifies the max column width of output") - f.StringVarP(&sc.output, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") + bindOutputFlag(cmd, &sc.output) return cmd } @@ -110,14 +104,7 @@ func (s *searchCmd) run(args []string) error { return err } - o, err := s.formatSearchResults(s.output, data, s.colWidth) - if err != nil { - return err - } - - fmt.Fprintln(s.out, o) - - return nil + return write(s.out, &searchWriter{data, s.colWidth}, outputFormat(s.output)) } func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, error) { @@ -148,55 +135,6 @@ func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, err return data, nil } -func (s *searchCmd) formatSearchResults(format string, res []*search.Result, colWidth uint) (string, error) { - var output string - var err error - - switch format { - case "table": - if len(res) == 0 { - return "No results found", nil - } - table := uitable.New() - table.MaxColWidth = colWidth - table.AddRow("NAME", "CHART VERSION", "APP VERSION", "DESCRIPTION") - for _, r := range res { - table.AddRow(r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description) - } - output = table.String() - - case "json": - output, err = s.printFormated(format, res, json.Marshal) - - case "yaml": - output, err = s.printFormated(format, res, yaml.Marshal) - } - - return output, err -} - -func (s *searchCmd) printFormated(format string, res []*search.Result, obj func(v interface{}) ([]byte, error)) (string, error) { - var sResult searchResult - var output string - var err error - - if len(res) == 0 { - return "[]", nil - } - - for _, r := range res { - sResult.Charts = append(sResult.Charts, &chartElement{r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description}) - } - - o, e := obj(sResult) - if e != nil { - err = fmt.Errorf("Failed to Marshal %s output: %s", strings.ToUpper(format), e) - } else { - output = string(o) - } - return output, err -} - func (s *searchCmd) buildIndex() (*search.Index, error) { // Load the repositories.yaml rf, err := repo.LoadRepositoriesFile(s.helmhome.RepositoryFile()) @@ -218,3 +156,53 @@ func (s *searchCmd) buildIndex() (*search.Index, error) { } return i, nil } + +//////////// Printer implementation below here +type searchWriter struct { + results []*search.Result + columnWidth uint +} + +func (r *searchWriter) WriteTable(out io.Writer) error { + if len(r.results) == 0 { + _, err := out.Write([]byte("No results found\n")) + if err != nil { + return fmt.Errorf("unable to write results: %s", err) + } + return nil + } + table := uitable.New() + table.MaxColWidth = r.columnWidth + table.AddRow("NAME", "CHART VERSION", "APP VERSION", "DESCRIPTION") + for _, r := range r.results { + table.AddRow(r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description) + } + return encodeTable(out, table) +} + +func (r *searchWriter) WriteJSON(out io.Writer) error { + return r.encodeByFormat(out, outputJSON) +} + +func (r *searchWriter) WriteYAML(out io.Writer) error { + return r.encodeByFormat(out, outputYAML) +} + +func (r *searchWriter) encodeByFormat(out io.Writer, format outputFormat) error { + var chartList []chartElement + + for _, r := range r.results { + chartList = append(chartList, chartElement{r.Name, r.Chart.Version, r.Chart.AppVersion, r.Chart.Description}) + } + + switch format { + case outputJSON: + return encodeJSON(out, chartList) + case outputYAML: + return encodeYAML(out, chartList) + } + + // Because this is a non-exported function and only called internally by + // WriteJSON and WriteYAML, we shouldn't get invalid types + return nil +} diff --git a/cmd/helm/search_test.go b/cmd/helm/search_test.go index 35a72260e..12824407c 100644 --- a/cmd/helm/search_test.go +++ b/cmd/helm/search_test.go @@ -18,7 +18,6 @@ package main import ( "io" - "regexp" "strings" "testing" @@ -90,25 +89,25 @@ func TestSearchCmd(t *testing.T) { name: "search for 'maria', expect one match output json", args: []string{"maria"}, flags: strings.Split("--output json", " "), - expected: regexp.QuoteMeta(`{"Charts":[{"Name":"testing/mariadb","Version":"0.3.0","AppVersion":"","Description":"Chart for MariaDB"}]}`), + expected: `[{"Name":"testing/mariadb","Version":"0.3.0","Appversion":"","Description":"Chart for MariaDB"}]`, }, { name: "search for 'alpine', expect two matches output json", args: []string{"alpine"}, flags: strings.Split("--output json", " "), - expected: regexp.QuoteMeta(`{"Charts":[{"Name":"testing/alpine","Version":"0.2.0","AppVersion":"2.3.4","Description":"Deploy a basic Alpine Linux pod"}]}`), + expected: `[{"Name":"testing/alpine","Version":"0.2.0","Appversion":"2.3.4","Description":"Deploy a basic Alpine Linux pod"}]`, }, { name: "search for 'maria', expect one match output yaml", args: []string{"maria"}, flags: strings.Split("--output yaml", " "), - expected: "Charts:\n- AppVersion: \"\"\n Description: Chart for MariaDB\n Name: testing/mariadb\n Version: 0.3.0\n\n", + expected: "- AppVersion: \"\"\n Description: Chart for MariaDB\n Name: testing/mariadb\n Version: 0.3.0\n\n", }, { name: "search for 'alpine', expect two matches output yaml", args: []string{"alpine"}, flags: strings.Split("--output yaml", " "), - expected: "Charts:\n- AppVersion: 2.3.4\n Description: Deploy a basic Alpine Linux pod\n Name: testing/alpine\n Version: 0.2.0\n\n", + expected: "- AppVersion: 2.3.4\n Description: Deploy a basic Alpine Linux pod\n Name: testing/alpine\n Version: 0.2.0\n\n", }, } diff --git a/cmd/helm/status.go b/cmd/helm/status.go index 65025c8cc..23120980a 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -17,14 +17,11 @@ limitations under the License. package main import ( - "encoding/json" "fmt" "io" "regexp" - "strings" "text/tabwriter" - "github.com/ghodss/yaml" "github.com/gosuri/uitable" "github.com/gosuri/uitable/util/strutil" "github.com/spf13/cobra" @@ -80,7 +77,7 @@ func newStatusCmd(client helm.Interface, out io.Writer) *cobra.Command { f := cmd.Flags() settings.AddFlagsTLS(f) f.Int32Var(&status.version, "revision", 0, "If set, display the status of the named release with revision") - f.StringVarP(&status.outfmt, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") + bindOutputFlag(cmd, &status.outfmt) // set defaults from environment settings.InitTLS(f) @@ -94,82 +91,55 @@ func (s *statusCmd) run() error { return prettyError(err) } - output, err := PrintStatusFormated(s.outfmt, res) - - if err != nil { - return err - } + return write(s.out, &statusWriter{res}, outputFormat(s.outfmt)) +} - fmt.Fprintf(s.out, output) +type statusWriter struct { + status *services.GetReleaseStatusResponse +} +func (s *statusWriter) WriteTable(out io.Writer) error { + PrintStatus(out, s.status) + // There is no error handling here due to backwards compatibility with + // PrintStatus return nil } -// PrintStatusFormated prints out the status of a release. Shared because also used by -// install / upgrade -func PrintStatusFormated(format string, res *services.GetReleaseStatusResponse) (string, error) { - var output string - var err error - - switch format { - case "table": - output = printStatus(res) - - case "json": - output, err = printFormatedReleaseStatus(format, res, json.Marshal) - - case "yaml": - output, err = printFormatedReleaseStatus(format, res, yaml.Marshal) - - default: - err = fmt.Errorf("Unknown output format %q", err) - } - - return output, err +func (s *statusWriter) WriteJSON(out io.Writer) error { + return encodeJSON(out, s.status) } -func printFormatedReleaseStatus(format string, res *services.GetReleaseStatusResponse, obj func(v interface{}) ([]byte, error)) (string, error) { - var output string - var err error - - o, err := obj(res) - if err != nil { - return "", fmt.Errorf("Failed to Marshal %s output: %s", strings.ToUpper(format), err) - } - output = string(o) - - return output, err +func (s *statusWriter) WriteYAML(out io.Writer) error { + return encodeYAML(out, s.status) } -func printStatus(res *services.GetReleaseStatusResponse) string { - var out strings.Builder - +// PrintStatus prints out the status of a release. Shared because also used by +// install / upgrade +func PrintStatus(out io.Writer, res *services.GetReleaseStatusResponse) { if res.Info.LastDeployed != nil { - fmt.Fprintf(&out, "LAST DEPLOYED: %s\n", timeconv.String(res.Info.LastDeployed)) + fmt.Fprintf(out, "LAST DEPLOYED: %s\n", timeconv.String(res.Info.LastDeployed)) } - fmt.Fprintf(&out, "NAMESPACE: %s\n", res.Namespace) - fmt.Fprintf(&out, "STATUS: %s\n", res.Info.Status.Code) - fmt.Fprintf(&out, "\n") + fmt.Fprintf(out, "NAMESPACE: %s\n", res.Namespace) + fmt.Fprintf(out, "STATUS: %s\n", res.Info.Status.Code) + fmt.Fprintf(out, "\n") if len(res.Info.Status.Resources) > 0 { re := regexp.MustCompile(" +") - w := tabwriter.NewWriter(&out, 0, 0, 2, ' ', tabwriter.TabIndent) + w := tabwriter.NewWriter(out, 0, 0, 2, ' ', tabwriter.TabIndent) fmt.Fprintf(w, "RESOURCES:\n%s\n", re.ReplaceAllString(res.Info.Status.Resources, "\t")) w.Flush() } if res.Info.Status.LastTestSuiteRun != nil { lastRun := res.Info.Status.LastTestSuiteRun - fmt.Fprintf(&out, "TEST SUITE:\n%s\n%s\n\n%s\n", + fmt.Fprintf(out, "TEST SUITE:\n%s\n%s\n\n%s\n", fmt.Sprintf("Last Started: %s", timeconv.String(lastRun.StartedAt)), fmt.Sprintf("Last Completed: %s", timeconv.String(lastRun.CompletedAt)), formatTestResults(lastRun.Results)) } if len(res.Info.Status.Notes) > 0 { - fmt.Fprintf(&out, "NOTES:\n%s\n", res.Info.Status.Notes) + fmt.Fprintf(out, "NOTES:\n%s\n", res.Info.Status.Notes) } - - return out.String() } func formatTestResults(results []*release.TestRun) string { diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 5c5af66cc..a105820a6 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -182,7 +182,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { f.BoolVar(&upgrade.subNotes, "render-subchart-notes", false, "Render subchart notes along with parent") f.StringVar(&upgrade.description, "description", "", "Specify the description to use for the upgrade, rather than the default") f.BoolVar(&upgrade.cleanupOnFail, "cleanup-on-fail", false, "Allow deletion of new resources created in this upgrade when upgrade failed") - f.StringVarP(&upgrade.output, "output", "o", "table", "Prints the output in the specified format (json|table|yaml)") + bindOutputFlag(cmd, &upgrade.output) f.MarkDeprecated("disable-hooks", "Use --no-hooks instead") @@ -309,7 +309,7 @@ func (u *upgradeCmd) run() error { printRelease(u.out, resp.Release) } - if u.output == "table" { + if outputFormat(u.output) == outputTable { fmt.Fprintf(u.out, "Release %q has been upgraded.\n", u.release) } // Print the status like status command does @@ -318,13 +318,5 @@ func (u *upgradeCmd) run() error { return prettyError(err) } - output, err := PrintStatusFormated(u.output, status) - - if err != nil { - return err - } - - fmt.Fprintf(u.out, output) - - return nil + return write(u.out, &statusWriter{status}, outputFormat(u.output)) } diff --git a/docs/helm/helm_install.md b/docs/helm/helm_install.md index dc0591f6a..d44f9ded5 100644 --- a/docs/helm/helm_install.md +++ b/docs/helm/helm_install.md @@ -93,7 +93,7 @@ helm install [CHART] [flags] --namespace string Namespace to install the release into. Defaults to the current kube config namespace. --no-crd-hook Prevent CRD hooks from running, but run other hooks --no-hooks Prevent hooks from running during install - -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") + -o, --output string Prints the output in the specified format. Allowed values: table, json, yaml (default "table") --password string Chart repository password where to locate the requested chart --render-subchart-notes Render subchart notes along with the parent --replace Re-use the given name, even if that name is already used. This is unsafe in production diff --git a/docs/helm/helm_repo_list.md b/docs/helm/helm_repo_list.md index 5f13c8c2d..3ff2cbaf0 100644 --- a/docs/helm/helm_repo_list.md +++ b/docs/helm/helm_repo_list.md @@ -14,7 +14,7 @@ helm repo list [flags] ``` -h, --help help for list - -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") + -o, --output string Prints the output in the specified format. Allowed values: table, json, yaml (default "table") ``` ### Options inherited from parent commands diff --git a/docs/helm/helm_search.md b/docs/helm/helm_search.md index e040b738f..558cadfee 100644 --- a/docs/helm/helm_search.md +++ b/docs/helm/helm_search.md @@ -20,7 +20,7 @@ helm search [keyword] [flags] ``` --col-width uint Specifies the max column width of output (default 60) -h, --help help for search - -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") + -o, --output string Prints the output in the specified format. Allowed values: table, json, yaml (default "table") -r, --regexp Use regular expressions for searching -v, --version string Search using semantic versioning constraints -l, --versions Show the long listing, with each version of each chart on its own line diff --git a/docs/helm/helm_status.md b/docs/helm/helm_status.md index 2c75ce21a..91c3a1427 100644 --- a/docs/helm/helm_status.md +++ b/docs/helm/helm_status.md @@ -23,7 +23,7 @@ helm status [flags] RELEASE_NAME ``` -h, --help help for status - -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") + -o, --output string Prints the output in the specified format. Allowed values: table, json, yaml (default "table") --revision int32 If set, display the status of the named release with revision --tls Enable TLS for request --tls-ca-cert string Path to TLS CA certificate file (default "$HELM_HOME/ca.pem") diff --git a/docs/helm/helm_upgrade.md b/docs/helm/helm_upgrade.md index effb505f9..35888d568 100644 --- a/docs/helm/helm_upgrade.md +++ b/docs/helm/helm_upgrade.md @@ -79,7 +79,7 @@ helm upgrade [RELEASE] [CHART] [flags] --keyring string Path to the keyring that contains public signing keys (default "~/.gnupg/pubring.gpg") --namespace string Namespace to install the release into (only used if --install is set). Defaults to the current kube config namespace --no-hooks Disable pre/post upgrade hooks - -o, --output string Prints the output in the specified format (json|table|yaml) (default "table") + -o, --output string Prints the output in the specified format. Allowed values: table, json, yaml (default "table") --password string Chart repository password where to locate the requested chart --recreate-pods Performs pods restart for the resource if applicable --render-subchart-notes Render subchart notes along with parent From 58c004bb89c3cc88ac3afb0d5d2570fa5fdc0dd2 Mon Sep 17 00:00:00 2001 From: yuxiaobo Date: Wed, 25 Sep 2019 15:33:30 +0800 Subject: [PATCH 23/29] Improve the quality of annotations Signed-off-by: yuxiaobo --- cmd/helm/create.go | 2 +- cmd/helm/search/search.go | 2 +- pkg/chartutil/doc.go | 2 +- pkg/releaseutil/filter_test.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/helm/create.go b/cmd/helm/create.go index da91291fd..8ecffdba6 100644 --- a/cmd/helm/create.go +++ b/cmd/helm/create.go @@ -106,7 +106,7 @@ func (c *createCmd) run() error { if c.starter != "" { // Create from the starter lstarter := filepath.Join(c.home.Starters(), c.starter) - // If path is absolute, we dont want to prefix it with helm starters folder + // If path is absolute, we don't want to prefix it with helm starters folder if filepath.IsAbs(c.starter) { lstarter = c.starter } diff --git a/cmd/helm/search/search.go b/cmd/helm/search/search.go index a9d0616e9..2fd6b4581 100644 --- a/cmd/helm/search/search.go +++ b/cmd/helm/search/search.go @@ -55,7 +55,7 @@ type Index struct { charts map[string]*repo.ChartVersion } -// NewIndex creats a new Index. +// NewIndex creates a new Index. func NewIndex() *Index { return &Index{lines: map[string]string{}, charts: map[string]*repo.ChartVersion{}} } diff --git a/pkg/chartutil/doc.go b/pkg/chartutil/doc.go index a4f6d4515..ad2224f94 100644 --- a/pkg/chartutil/doc.go +++ b/pkg/chartutil/doc.go @@ -17,7 +17,7 @@ limitations under the License. /*Package chartutil contains tools for working with charts. Charts are described in the protocol buffer definition (pkg/proto/hapi/charts). -This packe provides utilities for serializing and deserializing charts. +This package provides utilities for serializing and deserializing charts. A chart can be represented on the file system in one of two ways: diff --git a/pkg/releaseutil/filter_test.go b/pkg/releaseutil/filter_test.go index 802b1db7a..4ec81a8da 100644 --- a/pkg/releaseutil/filter_test.go +++ b/pkg/releaseutil/filter_test.go @@ -54,6 +54,6 @@ func TestFilterAll(t *testing.T) { case r0.Version == 4: t.Fatal("got release with status revision 4") case r0.Info.Status.Code == rspb.Status_DELETED: - t.Fatal("got release with status DELTED") + t.Fatal("got release with status DELETED") } } From 9d8a84ee3daa0870689ba24ca8bf6bb13a0d38ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E8=B0=AD=E5=86=9B?= <2799194073@qq.com> Date: Wed, 25 Sep 2019 21:10:51 +0800 Subject: [PATCH 24/29] fix-up typo (#6501) Signed-off-by: chentanjun <2799194073@qq.com> --- cmd/helm/template_test.go | 2 +- pkg/provenance/sign.go | 2 +- pkg/tiller/release_list.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index 3c5026b08..2baf887eb 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -158,7 +158,7 @@ func TestTemplateCmd(t *testing.T) { }, { name: "check_invalid_name_template", - desc: "verify the relase name generate by template is invalid", + desc: "verify the release name generate by template is invalid", args: []string{subchart1ChartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"}, expectError: "is invalid", }, diff --git a/pkg/provenance/sign.go b/pkg/provenance/sign.go index 26ae26031..d0e4d06c7 100644 --- a/pkg/provenance/sign.go +++ b/pkg/provenance/sign.go @@ -122,7 +122,7 @@ func NewFromKeyring(keyringfile, id string) (*Signatory, error) { return s, nil } - // We're gonna go all GnuPG on this and look for a string that _contains_. If + // We're going to go all GnuPG on this and look for a string that _contains_. If // two or more keys contain the string and none are a direct match, we error // out. var candidate *openpgp.Entity diff --git a/pkg/tiller/release_list.go b/pkg/tiller/release_list.go index 6d62c7bc4..cd3b63856 100644 --- a/pkg/tiller/release_list.go +++ b/pkg/tiller/release_list.go @@ -126,7 +126,7 @@ func (s *ReleaseServer) ListReleases(req *services.ListReleasesRequest, stream s return nil } -// partition packs releases into slices upto the capacity cap in bytes. +// partition packs releases into slices up to the capacity cap in bytes. func (s *ReleaseServer) partition(rels []*release.Release, cap int) <-chan []*release.Release { chunks := make(chan []*release.Release, 1) go func() { From 0b229bdd042cbb099ab1a3b61e780b261a24f92c Mon Sep 17 00:00:00 2001 From: yuxiaobo96 <41496192+yuxiaobo96@users.noreply.github.com> Date: Fri, 27 Sep 2019 17:47:55 +0800 Subject: [PATCH 25/29] Improve the quality of the document (#6510) Signed-off-by: yuxiaobo --- pkg/getter/getter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/getter/getter.go b/pkg/getter/getter.go index c595fec69..062c7269e 100644 --- a/pkg/getter/getter.go +++ b/pkg/getter/getter.go @@ -68,7 +68,7 @@ func (p Providers) ByScheme(scheme string) (Constructor, error) { } // All finds all of the registered getters as a list of Provider instances. -// Currently the build-in http/https getter and the discovered +// Currently the built-in http/https getter and the discovered // plugins with downloader notations are collected. func All(settings environment.EnvSettings) Providers { result := Providers{ From 8648ccf5d35d682dcd5f7a9c2082f0aaf071e817 Mon Sep 17 00:00:00 2001 From: Till Hoffmann Date: Fri, 27 Sep 2019 12:47:18 +0200 Subject: [PATCH 26/29] fixed typo Signed-off-by: Till Hoffmann --- pkg/engine/engine.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 9a155de2e..b4b6475c9 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -267,7 +267,7 @@ func (e *Engine) renderWithReferences(tpls map[string]renderable, referenceTpls rendered = make(map[string]string, len(files)) var buf bytes.Buffer for _, file := range files { - // Don't render partials. We don't care out the direct output of partials. + // Don't render partials. We don't care about the direct output of partials. // They are only included from other templates. if strings.HasPrefix(path.Base(file), "_") { continue From 1726142e297e9c4a0de45d65b6ca7564bfc25d61 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Fri, 27 Sep 2019 10:52:31 -0400 Subject: [PATCH 27/29] feat(comp) Dynamic completion to use same binary as main call The binary of Helm to use for dynamic completion should be the same as the actual Helm binary being used. For example, if PATH points to a version of helm v3, but the user calls a binary named helm2 to use a renamed v2 version, then dynamic completion should also use helm2. If not, in this example, the dynamic completion will use the information returned by helm v3. This improvement is particularly useful for users that will run both helm v2 and helm v3 at the same time. Signed-off-by: Marc Khouzam --- cmd/helm/helm.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 20742836d..f3b8fc215 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -69,13 +69,22 @@ __helm_override_flags() done } +__helm_binary_name() +{ + local helm_binary + helm_binary="${words[0]}" + __helm_debug "${FUNCNAME[0]}: helm_binary is ${helm_binary}" + echo ${helm_binary} +} + __helm_list_releases() { __helm_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" local out filter # Use ^ to map from the start of the release name filter="^${words[c]}" - if out=$(helm list $(__helm_override_flags) -a -q ${filter} 2>/dev/null); then + # Use eval in case helm_binary_name or __helm_override_flags contains a variable (e.g., $HOME/bin/h2) + if out=$(eval $(__helm_binary_name) list $(__helm_override_flags) -a -q -m 1000 ${filter} 2>/dev/null); then COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) fi } @@ -86,7 +95,8 @@ __helm_list_repos() local out oflags oflags=$(__helm_override_flags) __helm_debug "${FUNCNAME[0]}: __helm_override_flags are ${oflags}" - if out=$(helm repo list ${oflags} | tail +2 | cut -f1 2>/dev/null); then + # Use eval in case helm_binary_name contains a variable (e.g., $HOME/bin/h2) + if out=$(eval $(__helm_binary_name) repo list ${oflags} 2>/dev/null | tail +2 | cut -f1); then COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) fi } @@ -97,7 +107,8 @@ __helm_list_plugins() local out oflags oflags=$(__helm_override_flags) __helm_debug "${FUNCNAME[0]}: __helm_override_flags are ${oflags}" - if out=$(helm plugin list ${oflags} | tail +2 | cut -f1 2>/dev/null); then + # Use eval in case helm_binary_name contains a variable (e.g., $HOME/bin/h2) + if out=$(eval $(__helm_binary_name) plugin list ${oflags} 2>/dev/null | tail +2 | cut -f1); then COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) fi } From ce7880f4038cbea154f50a2b178e3dfca49bca48 Mon Sep 17 00:00:00 2001 From: Alexander Sowitzki Date: Thu, 26 Sep 2019 01:22:29 +0200 Subject: [PATCH 28/29] Add Arch Linux, KubeOne and Kubermatic to distro documentation Signed-off-by: Alexander Sowitzki --- docs/kubernetes_distros.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/kubernetes_distros.md b/docs/kubernetes_distros.md index 52a5e1acc..b564b7014 100644 --- a/docs/kubernetes_distros.md +++ b/docs/kubernetes_distros.md @@ -31,6 +31,7 @@ Helm works with [Azure Kubernetes Service](https://docs.microsoft.com/en-us/azur Kubernetes bootstrapped with `kubeadm` is known to work on the following Linux distributions: +- Arch Linux - Ubuntu 16.04 - Fedora release 25 @@ -53,3 +54,11 @@ Helm Client and Helm Server (Tiller) are pre-installed with [Platform9 Managed K Helm (both client and server) has been tested and is working on Mesospheres DC/OS 1.11 Kubernetes platform, and requires no additional configuration. + +## Kubermatic + +Helm works in user clusters that are created by Kubermatic without caveats. Since seed cluster can be setup up in different ways Helm support depends on them. + +## KubeOne + +Helm works in clusters that are set up by KubeOne without caveats. From d251b94efc23ef5ec00f473cf9c44e4679963e32 Mon Sep 17 00:00:00 2001 From: Abejide Femi Date: Wed, 2 Oct 2019 10:20:53 +0100 Subject: [PATCH 29/29] refactor manager file in pkg folder (#6551) Signed-off-by: abejidefemi1@gmail.com --- pkg/downloader/manager.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 6c6886e8a..23a5b587e 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -442,8 +442,7 @@ func (m *Manager) UpdateRepositories() error { if err != nil { return err } - repos := rf.Repositories - if len(repos) > 0 { + if repos := rf.Repositories; len(repos) > 0 { // This prints warnings straight to out. if err := m.parallelRepoUpdate(repos); err != nil { return err @@ -616,7 +615,7 @@ func writeLock(chartpath string, lock *chartutil.RequirementsLock) error { } // tarFromLocalDir archive a dep chart from local directory and save it into charts/ -func tarFromLocalDir(chartpath string, name string, repo string, version string) (string, error) { +func tarFromLocalDir(chartpath, name, repo, version string) (string, error) { destPath := filepath.Join(chartpath, "charts") if !strings.HasPrefix(repo, "file://") {