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 {
bool reuse_values = 10;
// Force resource update through delete/recreate if needed.
bool force = 11;
// Render subchart notes if enabled
bool subNotes = 12;
}
// UpdateReleaseResponse is the response to an update request.
......@@ -273,6 +275,8 @@ message InstallReleaseRequest {
bool wait = 9;
bool disable_crd_hook = 10;
bool subNotes = 11;
}
// InstallReleaseResponse is the response from a release installation.
......
......@@ -129,6 +129,7 @@ type installCmd struct {
password string
devel bool
depUp bool
subNotes bool
certFile string
keyFile string
......@@ -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.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.subNotes, "render-subchart-notes", false, "render subchart notes along with the parent")
return cmd
}
......@@ -276,6 +278,7 @@ func (i *installCmd) run() error {
helm.InstallReuseName(i.replace),
helm.InstallDisableHooks(i.disableHooks),
helm.InstallDisableCRDHook(i.disableCRDHook),
helm.InstallSubNotes(i.subNotes),
helm.InstallTimeout(i.timeout),
helm.InstallWait(i.wait))
if err != nil {
......
......@@ -78,6 +78,7 @@ type upgradeCmd struct {
username string
password string
devel bool
subNotes bool
certFile string
keyFile string
......@@ -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.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.subNotes, "render-subchart-notes", false, "render subchart notes along with parent")
f.MarkDeprecated("disable-hooks", "use --no-hooks instead")
......@@ -224,6 +226,7 @@ func (u *upgradeCmd) run() error {
helm.UpgradeTimeout(u.timeout),
helm.ResetValues(u.resetValues),
helm.ReuseValues(u.reuseValues),
helm.UpgradeSubNotes(u.subNotes),
helm.UpgradeWait(u.wait))
if err != nil {
return fmt.Errorf("UPGRADE FAILED: %v", prettyError(err))
......
......@@ -95,6 +95,7 @@ func (h *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ...
req := &reqOpts.instReq
req.Chart = chart
req.Namespace = ns
req.SubNotes = reqOpts.subNotes
req.DryRun = reqOpts.dryRun
req.DisableHooks = reqOpts.disableHooks
req.DisableCrdHook = reqOpts.disableCRDHook
......@@ -171,6 +172,7 @@ func (h *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts
req.DryRun = reqOpts.dryRun
req.Name = rlsName
req.DisableHooks = reqOpts.disableHooks
req.SubNotes = reqOpts.subNotes
req.Recreate = reqOpts.recreate
req.Force = reqOpts.force
req.ResetValues = reqOpts.resetValues
......
......@@ -53,6 +53,8 @@ type options struct {
disableHooks bool
// if set, skip CRD hook only
disableCRDHook bool
// if set, render SubChart Notes
subNotes bool
// name of release
releaseName string
// tls.Config to use for rpc if tls enabled
......@@ -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
func RollbackDisableHooks(disable bool) RollbackOption {
return func(opts *options) {
......
This diff is collapsed.
......@@ -84,7 +84,7 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
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 {
// Return a release with partial data so that client can show debugging
// information.
......
......@@ -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()
rs := rsFixture()
......@@ -291,6 +291,39 @@ func TestInstallRelease_WithChartAndDependencyNotes(t *testing.T) {
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") {
t.Fatalf("Expected '%s', got '%s'", notesText+"\n"+notesText+" child", rel.Info.Status.Notes)
}
......
......@@ -20,6 +20,7 @@ import (
"bytes"
"errors"
"fmt"
"path"
"regexp"
"strings"
......@@ -259,7 +260,7 @@ func GetVersionSet(client discovery.ServerGroupsInterface) (chartutil.VersionSet
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.
sver := version.GetVersion()
if ch.Metadata.TillerVersion != "" &&
......@@ -291,14 +292,18 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
var notesBuffer bytes.Buffer
for k, v := range files {
if strings.HasSuffix(k, notesFileSuffix) {
// If buffer contains data, add newline before adding more
if notesBuffer.Len() > 0 {
notesBuffer.WriteString("\n")
if subNotes || (k == path.Join(ch.Metadata.Name, "templates", notesFileSuffix)) {
// If buffer contains data, add newline before adding more
if notesBuffer.Len() > 0 {
notesBuffer.WriteString("\n")
}
notesBuffer.WriteString(v)
}
notesBuffer.WriteString(v)
delete(files, k)
}
}
notes := notesBuffer.String()
// Sort hooks, manifests, and partials. Only hooks and manifests are returned,
......
......@@ -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 {
reqOpts := &installOptions{
&services.InstallReleaseRequest{
......
......@@ -113,7 +113,7 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
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 {
return nil, nil, err
}
......
......@@ -65,8 +65,8 @@ func TestEqual(t *testing.T) {
func TestExtractHostname(t *testing.T) {
tests := map[string]string{
"http://example.com": "example.com",
"https://example.com/foo": "example.com",
"http://example.com": "example.com",
"https://example.com/foo": "example.com",
"https://example.com:31337/not/with/a/bang/but/a/whimper": "example.com",
}
for start, expect := range tests {
......
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