Commit 1518f961 authored by jgleonard's avatar jgleonard

fix(helm): add --render-subchart-notes flag to 'helm install' and 'helm upgrade'

When 'helm <install|upgrade> --render-subchart-notes ...' is run, this will include
the notes from the subchart when rendered via Tiller.

Closes #2751
Signed-off-by: 's avatarjgleonard <jgleonard@gmail.com>
parent ab9349c4
...@@ -209,6 +209,8 @@ message UpdateReleaseRequest { ...@@ -209,6 +209,8 @@ message UpdateReleaseRequest {
bool reuse_values = 10; bool reuse_values = 10;
// Force resource update through delete/recreate if needed. // Force resource update through delete/recreate if needed.
bool force = 11; bool force = 11;
// Render subchart notes if enabled
bool subNotes = 12;
} }
// UpdateReleaseResponse is the response to an update request. // UpdateReleaseResponse is the response to an update request.
...@@ -273,6 +275,8 @@ message InstallReleaseRequest { ...@@ -273,6 +275,8 @@ message InstallReleaseRequest {
bool wait = 9; bool wait = 9;
bool disable_crd_hook = 10; bool disable_crd_hook = 10;
bool subNotes = 11;
} }
// InstallReleaseResponse is the response from a release installation. // InstallReleaseResponse is the response from a release installation.
......
...@@ -129,6 +129,7 @@ type installCmd struct { ...@@ -129,6 +129,7 @@ type installCmd struct {
password string password string
devel bool devel bool
depUp bool depUp bool
subNotes bool
certFile string certFile string
keyFile string keyFile string
...@@ -209,6 +210,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command { ...@@ -209,6 +210,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
f.StringVar(&inst.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&inst.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&inst.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") f.BoolVar(&inst.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.BoolVar(&inst.depUp, "dep-up", false, "run helm dependency update before installing the chart") 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")
return cmd return cmd
} }
...@@ -276,6 +278,7 @@ func (i *installCmd) run() error { ...@@ -276,6 +278,7 @@ func (i *installCmd) run() error {
helm.InstallReuseName(i.replace), helm.InstallReuseName(i.replace),
helm.InstallDisableHooks(i.disableHooks), helm.InstallDisableHooks(i.disableHooks),
helm.InstallDisableCRDHook(i.disableCRDHook), helm.InstallDisableCRDHook(i.disableCRDHook),
helm.InstallSubNotes(i.subNotes),
helm.InstallTimeout(i.timeout), helm.InstallTimeout(i.timeout),
helm.InstallWait(i.wait)) helm.InstallWait(i.wait))
if err != nil { if err != nil {
......
...@@ -78,6 +78,7 @@ type upgradeCmd struct { ...@@ -78,6 +78,7 @@ type upgradeCmd struct {
username string username string
password string password string
devel bool devel bool
subNotes bool
certFile string certFile string
keyFile string keyFile string
...@@ -139,6 +140,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command { ...@@ -139,6 +140,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
f.StringVar(&upgrade.keyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&upgrade.keyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.StringVar(&upgrade.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&upgrade.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&upgrade.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") f.BoolVar(&upgrade.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
f.BoolVar(&upgrade.subNotes, "render-subchart-notes", false, "render subchart notes along with parent")
f.MarkDeprecated("disable-hooks", "use --no-hooks instead") f.MarkDeprecated("disable-hooks", "use --no-hooks instead")
...@@ -224,6 +226,7 @@ func (u *upgradeCmd) run() error { ...@@ -224,6 +226,7 @@ func (u *upgradeCmd) run() error {
helm.UpgradeTimeout(u.timeout), helm.UpgradeTimeout(u.timeout),
helm.ResetValues(u.resetValues), helm.ResetValues(u.resetValues),
helm.ReuseValues(u.reuseValues), helm.ReuseValues(u.reuseValues),
helm.UpgradeSubNotes(u.subNotes),
helm.UpgradeWait(u.wait)) helm.UpgradeWait(u.wait))
if err != nil { if err != nil {
return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err)) return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err))
......
...@@ -95,6 +95,7 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ... ...@@ -95,6 +95,7 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...
req := &reqOpts.instReq req := &reqOpts.instReq
req.Chart = chart req.Chart = chart
req.Namespace = ns req.Namespace = ns
req.SubNotes = reqOpts.subNotes
req.DryRun = reqOpts.dryRun req.DryRun = reqOpts.dryRun
req.DisableHooks = reqOpts.disableHooks req.DisableHooks = reqOpts.disableHooks
req.DisableCrdHook = reqOpts.disableCRDHook req.DisableCrdHook = reqOpts.disableCRDHook
...@@ -171,6 +172,7 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts ...@@ -171,6 +172,7 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts
req.DryRun = reqOpts.dryRun req.DryRun = reqOpts.dryRun
req.Name = rlsName req.Name = rlsName
req.DisableHooks = reqOpts.disableHooks req.DisableHooks = reqOpts.disableHooks
req.SubNotes = reqOpts.subNotes
req.Recreate = reqOpts.recreate req.Recreate = reqOpts.recreate
req.Force = reqOpts.force req.Force = reqOpts.force
req.ResetValues = reqOpts.resetValues req.ResetValues = reqOpts.resetValues
......
...@@ -53,6 +53,8 @@ type options struct { ...@@ -53,6 +53,8 @@ type options struct {
disableHooks bool disableHooks bool
// if set, skip CRD hook only // if set, skip CRD hook only
disableCRDHook bool disableCRDHook bool
// if set, render SubChart Notes
subNotes bool
// name of release // name of release
releaseName string releaseName string
// tls.Config to use for rpc if tls enabled // tls.Config to use for rpc if tls enabled
...@@ -311,6 +313,20 @@ func InstallReuseName(reuse bool) InstallOption { ...@@ -311,6 +313,20 @@ func InstallReuseName(reuse bool) InstallOption {
} }
} }
// InstallSubNotes will (if true) instruct Tiller to render SubChart Notes
func InstallSubNotes(enable bool) InstallOption {
return func(opts *options) {
opts.subNotes = enable
}
}
// UpgradeSubNotes will (if true) instruct Tiller to render SubChart Notes
func UpgradeSubNotes(enable bool) UpdateOption {
return func(opts *options) {
opts.subNotes = enable
}
}
// RollbackDisableHooks will disable hooks for a rollback operation // RollbackDisableHooks will disable hooks for a rollback operation
func RollbackDisableHooks(disable bool) RollbackOption { func RollbackDisableHooks(disable bool) RollbackOption {
return func(opts *options) { return func(opts *options) {
......
This diff is collapsed.
...@@ -84,7 +84,7 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re ...@@ -84,7 +84,7 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
return nil, err return nil, err
} }
hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions) hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, req.SubNotes, caps.APIVersions)
if err != nil { if err != nil {
// Return a release with partial data so that client can show debugging // Return a release with partial data so that client can show debugging
// information. // information.
......
...@@ -268,7 +268,7 @@ func TestInstallRelease_WrongTillerVersion(t *testing.T) { ...@@ -268,7 +268,7 @@ func TestInstallRelease_WrongTillerVersion(t *testing.T) {
} }
} }
func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) { func TestInstallRelease_WithChartAndDependencyParentNotes(t *testing.T) {
c := helm.NewContext() c := helm.NewContext()
rs := rsFixture() rs := rsFixture()
...@@ -291,6 +291,39 @@ func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) { ...@@ -291,6 +291,39 @@ func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) {
t.Logf("rel: %v", rel) t.Logf("rel: %v", rel)
if rel.Info.Status.Notes != notesText {
t.Fatalf("Expected '%s', got '%s'", notesText, rel.Info.Status.Notes)
}
if rel.Info.Description != "Install complete" {
t.Errorf("unexpected description: %s", rel.Info.Description)
}
}
func TestInstallRelease_WithChartAndDependencyAllNotes(t *testing.T) {
c := helm.NewContext()
rs := rsFixture()
req := installRequest(withSubNotes(),
withChart(
withNotes(notesText),
withDependency(withNotes(notesText+" child")),
))
res, err := rs.InstallRelease(c, req)
if err != nil {
t.Fatalf("Failed install: %s", err)
}
if res.Release.Name == "" {
t.Errorf("Expected release name.")
}
rel, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version)
if err != nil {
t.Errorf("Expected release for %s (%v).", res.Release.Name, rs.env.Releases)
}
t.Logf("rel: %v", rel)
if !strings.Contains(rel.Info.Status.Notes, notesText) || !strings.Contains(rel.Info.Status.Notes, notesText+" child") { if !strings.Contains(rel.Info.Status.Notes, notesText) || !strings.Contains(rel.Info.Status.Notes, notesText+" child") {
t.Fatalf("Expected '%s', got '%s'", notesText+"\n"+notesText+" child", rel.Info.Status.Notes) t.Fatalf("Expected '%s', got '%s'", notesText+"\n"+notesText+" child", rel.Info.Status.Notes)
} }
......
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"path"
"regexp" "regexp"
"strings" "strings"
...@@ -259,7 +260,7 @@ func GetVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet ...@@ -259,7 +260,7 @@ func GetVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet
return chartutil.NewVersionSet(versions...), nil return chartutil.NewVersionSet(versions...), nil
} }
func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values, vs chartutil.VersionSet) ([]*release.Hook, *bytes.Buffer, string, error) { func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values, subNotes bool, vs chartutil.VersionSet) ([]*release.Hook, *bytes.Buffer, string, error) {
// Guard to make sure Tiller is at the right version to handle this chart. // Guard to make sure Tiller is at the right version to handle this chart.
sver := version.GetVersion() sver := version.GetVersion()
if ch.Metadata.TillerVersion != "" && if ch.Metadata.TillerVersion != "" &&
...@@ -291,14 +292,18 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values ...@@ -291,14 +292,18 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
var notesBuffer bytes.Buffer var notesBuffer bytes.Buffer
for k, v := range files { for k, v := range files {
if strings.HasSuffix(k, notesFileSuffix) { if strings.HasSuffix(k, notesFileSuffix) {
if subNotes || (k == path.Join(ch.Metadata.Name, "templates", notesFileSuffix)) {
// If buffer contains data, add newline before adding more // If buffer contains data, add newline before adding more
if notesBuffer.Len() > 0 { if notesBuffer.Len() > 0 {
notesBuffer.WriteString("\n") notesBuffer.WriteString("\n")
} }
notesBuffer.WriteString(v) notesBuffer.WriteString(v)
}
delete(files, k) delete(files, k)
} }
} }
notes := notesBuffer.String() notes := notesBuffer.String()
// Sort hooks, manifests, and partials. Only hooks and manifests are returned, // Sort hooks, manifests, and partials. Only hooks and manifests are returned,
......
...@@ -228,6 +228,12 @@ func withChart(chartOpts ...chartOption) installOption { ...@@ -228,6 +228,12 @@ func withChart(chartOpts ...chartOption) installOption {
} }
} }
func withSubNotes() installOption {
return func(opts *installOptions) {
opts.SubNotes = true
}
}
func installRequest(opts ...installOption) *services.InstallReleaseRequest { func installRequest(opts ...installOption) *services.InstallReleaseRequest {
reqOpts := &installOptions{ reqOpts := &installOptions{
&services.InstallReleaseRequest{ &services.InstallReleaseRequest{
......
...@@ -113,7 +113,7 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele ...@@ -113,7 +113,7 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
return nil, nil, err return nil, nil, err
} }
hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions) hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, req.SubNotes, caps.APIVersions)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment