pull/2440/merge
Kent Rancourt 8 years ago committed by GitHub
commit bee29994ca

@ -50,4 +50,7 @@ message Release {
// Namespace is the kubernetes namespace of the release.
string namespace = 8;
// Stages are subsets of rendered templates indexed by stage number
map<int32, string> stages = 9;
}

@ -35,6 +35,8 @@ type Release struct {
Version int32 `protobuf:"varint,7,opt,name=version" json:"version,omitempty"`
// Namespace is the kubernetes namespace of the release.
Namespace string `protobuf:"bytes,8,opt,name=namespace" json:"namespace,omitempty"`
// Stages are subsets of rendered templates indexed by stage number
Stages map[int32]string `protobuf:"bytes,9,rep,name=stages" json:"stages,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
}
func (m *Release) Reset() { *m = Release{} }
@ -98,6 +100,13 @@ func (m *Release) GetNamespace() string {
return ""
}
func (m *Release) GetStages() map[int32]string {
if m != nil {
return m.Stages
}
return nil
}
func init() {
proto.RegisterType((*Release)(nil), "hapi.release.Release")
}
@ -105,21 +114,25 @@ func init() {
func init() { proto.RegisterFile("hapi/release/release.proto", fileDescriptor2) }
var fileDescriptor2 = []byte{
// 256 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbf, 0x4e, 0xc3, 0x40,
0x0c, 0xc6, 0x95, 0x36, 0x7f, 0x1a, 0xc3, 0x82, 0x07, 0xb0, 0x22, 0x86, 0x88, 0x01, 0x22, 0x86,
0x54, 0x82, 0x37, 0x80, 0x05, 0xd6, 0x1b, 0xd9, 0x8e, 0xe8, 0x42, 0x4e, 0xa5, 0xe7, 0x28, 0x17,
0xf1, 0x2c, 0x3c, 0x2e, 0xba, 0x3f, 0x85, 0x94, 0x2e, 0x4e, 0xec, 0xdf, 0xa7, 0xcf, 0xdf, 0x19,
0xaa, 0x41, 0x8e, 0x7a, 0x3b, 0xa9, 0x4f, 0x25, 0xad, 0x3a, 0x7c, 0xdb, 0x71, 0xe2, 0x99, 0xf1,
0xdc, 0xb1, 0x36, 0xce, 0xaa, 0xab, 0x23, 0xe5, 0xc0, 0xbc, 0x0b, 0xb2, 0x7f, 0x40, 0x9b, 0x9e,
0x8f, 0x40, 0x37, 0xc8, 0x69, 0xde, 0x76, 0x6c, 0x7a, 0xfd, 0x11, 0xc1, 0xe5, 0x12, 0xb8, 0x1a,
0xe6, 0x37, 0xdf, 0x2b, 0x28, 0x44, 0xf0, 0x41, 0x84, 0xd4, 0xc8, 0xbd, 0xa2, 0xa4, 0x4e, 0x9a,
0x52, 0xf8, 0x7f, 0xbc, 0x85, 0xd4, 0xd9, 0xd3, 0xaa, 0x4e, 0x9a, 0xb3, 0x07, 0x6c, 0x97, 0xf9,
0xda, 0x57, 0xd3, 0xb3, 0xf0, 0x1c, 0xef, 0x20, 0xf3, 0xb6, 0xb4, 0xf6, 0xc2, 0x8b, 0x20, 0x0c,
0x9b, 0x9e, 0x5d, 0x15, 0x81, 0xe3, 0x3d, 0xe4, 0x21, 0x18, 0xa5, 0x4b, 0xcb, 0xa8, 0xf4, 0x44,
0x44, 0x05, 0x56, 0xb0, 0xd9, 0x4b, 0xa3, 0x7b, 0x65, 0x67, 0xca, 0x7c, 0xa8, 0xdf, 0x1e, 0x1b,
0xc8, 0xdc, 0x41, 0x2c, 0xe5, 0xf5, 0xfa, 0x34, 0xd9, 0x0b, 0xf3, 0x4e, 0x04, 0x01, 0x12, 0x14,
0x5f, 0x6a, 0xb2, 0x9a, 0x0d, 0x15, 0x75, 0xd2, 0x64, 0xe2, 0xd0, 0xe2, 0x35, 0x94, 0xee, 0x91,
0x76, 0x94, 0x9d, 0xa2, 0x8d, 0x5f, 0xf0, 0x37, 0x78, 0x2a, 0xdf, 0x8a, 0x68, 0xf7, 0x9e, 0xfb,
0x63, 0x3d, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0xc8, 0x8f, 0xec, 0x97, 0xbb, 0x01, 0x00, 0x00,
// 318 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x31, 0x4f, 0xfb, 0x30,
0x10, 0xc5, 0x95, 0xa6, 0x4e, 0x9a, 0xeb, 0x7f, 0xf8, 0x73, 0x42, 0x60, 0x45, 0x0c, 0x81, 0x01,
0x22, 0x86, 0x54, 0x82, 0x85, 0x32, 0x82, 0x90, 0x60, 0x35, 0x1b, 0x9b, 0xa9, 0x9c, 0x36, 0x6a,
0x6b, 0x57, 0x71, 0xa8, 0xd4, 0x2f, 0xc1, 0x67, 0x46, 0x3e, 0xbb, 0x90, 0xc2, 0xe2, 0xf8, 0xee,
0xfd, 0x72, 0xef, 0xf2, 0x02, 0xf9, 0x42, 0x6e, 0x9a, 0x49, 0xab, 0x56, 0x4a, 0x5a, 0xb5, 0x7f,
0x56, 0x9b, 0xd6, 0x74, 0x06, 0xff, 0x39, 0xad, 0x0a, 0xbd, 0xfc, 0xf4, 0x80, 0x5c, 0x18, 0xb3,
0xf4, 0xd8, 0x2f, 0xa1, 0xd1, 0xb5, 0x39, 0x10, 0x66, 0x0b, 0xd9, 0x76, 0x93, 0x99, 0xd1, 0x75,
0x33, 0x0f, 0xc2, 0x49, 0x5f, 0x70, 0xa7, 0xef, 0x5f, 0x7c, 0xc6, 0x90, 0x0a, 0x3f, 0x07, 0x11,
0x86, 0x5a, 0xae, 0x15, 0x8f, 0x8a, 0xa8, 0xcc, 0x04, 0xdd, 0xf1, 0x12, 0x86, 0x6e, 0x3c, 0x1f,
0x14, 0x51, 0x39, 0xbe, 0xc1, 0xaa, 0xbf, 0x5f, 0xf5, 0xa2, 0x6b, 0x23, 0x48, 0xc7, 0x2b, 0x60,
0x34, 0x96, 0xc7, 0x04, 0x1e, 0x79, 0xd0, 0x3b, 0x3d, 0xba, 0x53, 0x78, 0x1d, 0xaf, 0x21, 0xf1,
0x8b, 0xf1, 0x61, 0x7f, 0x64, 0x20, 0x49, 0x11, 0x81, 0xc0, 0x1c, 0x46, 0x6b, 0xa9, 0x9b, 0x5a,
0xd9, 0x8e, 0x33, 0x5a, 0xea, 0xbb, 0xc6, 0x12, 0x98, 0x0b, 0xc4, 0xf2, 0xa4, 0x88, 0xff, 0x6e,
0xf6, 0x6c, 0xcc, 0x52, 0x78, 0x00, 0x39, 0xa4, 0x5b, 0xd5, 0xda, 0xc6, 0x68, 0x9e, 0x16, 0x51,
0xc9, 0xc4, 0xbe, 0xc4, 0x33, 0xc8, 0xdc, 0x47, 0xda, 0x8d, 0x9c, 0x29, 0x3e, 0x22, 0x83, 0x9f,
0x06, 0x4e, 0x21, 0xb1, 0x9d, 0x9c, 0x2b, 0xcb, 0x33, 0xb2, 0x38, 0x3f, 0xb4, 0x08, 0xa9, 0x55,
0xaf, 0xc4, 0x3c, 0xe9, 0xae, 0xdd, 0x89, 0xf0, 0x42, 0x3e, 0x85, 0x71, 0xaf, 0x8d, 0xff, 0x21,
0x5e, 0xaa, 0x1d, 0xe5, 0xca, 0x84, 0xbb, 0xe2, 0x31, 0xb0, 0xad, 0x5c, 0x7d, 0x28, 0xca, 0x35,
0x13, 0xbe, 0xb8, 0x1f, 0xdc, 0x45, 0x0f, 0xd9, 0x5b, 0x1a, 0x1c, 0xde, 0x13, 0xfa, 0x45, 0xb7,
0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x60, 0xb7, 0xf2, 0x31, 0x02, 0x00, 0x00,
}

@ -666,7 +666,7 @@ func init() { proto.RegisterFile("hapi/rudder/rudder.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 584 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xd4, 0x56, 0xd1, 0x8e, 0xd2, 0x40,
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x56, 0xd1, 0x8e, 0xd2, 0x40,
0x14, 0xa5, 0xcb, 0x52, 0xe0, 0x92, 0x55, 0x32, 0xd9, 0x42, 0xd3, 0xf8, 0x40, 0xfa, 0x60, 0x88,
0xeb, 0x96, 0x04, 0x7d, 0xf4, 0x45, 0x59, 0xdc, 0xdd, 0x18, 0xd9, 0x64, 0x2a, 0x6e, 0xe2, 0x5b,
0x17, 0x2e, 0x58, 0x2d, 0x6d, 0x9d, 0x4e, 0xf7, 0x51, 0xfd, 0x1a, 0xff, 0x43, 0xbf, 0xcc, 0xb4,

@ -0,0 +1,20 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package stages
// StageAnno is the annotation name for a stage
const StageAnno = "helm.sh/stage"

@ -0,0 +1,21 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package tiller
import "bytes"
type docMap map[int]*bytes.Buffer

@ -29,6 +29,7 @@ import (
"k8s.io/helm/pkg/hooks"
"k8s.io/helm/pkg/proto/hapi/release"
util "k8s.io/helm/pkg/releaseutil"
"k8s.io/helm/pkg/stages"
)
var events = map[string]release.Hook_Event{
@ -72,9 +73,9 @@ type manifest struct {
//
// Files that do not parse into the expected format are simply placed into a map and
// returned.
func sortManifests(files map[string]string, apis chartutil.VersionSet, sort SortOrder) ([]*release.Hook, []manifest, error) {
func sortManifests(files map[string]string, apis chartutil.VersionSet, sort SortOrder) ([]*release.Hook, stageMap, error) {
hs := []*release.Hook{}
generic := []manifest{}
sm := stageMap{}
for n, c := range files {
// Skip partials. We could return these as a separate map, but there doesn't
@ -93,21 +94,30 @@ func sortManifests(files map[string]string, apis chartutil.VersionSet, sort Sort
if err != nil {
e := fmt.Errorf("YAML parse error on %s: %s", n, err)
return hs, generic, e
return hs, sm, e
}
if sh.Version != "" && !apis.Has(sh.Version) {
return hs, generic, fmt.Errorf("apiVersion %q in %s is not available", sh.Version, n)
return hs, sm, fmt.Errorf("apiVersion %q in %s is not available", sh.Version, n)
}
if sh.Metadata == nil || sh.Metadata.Annotations == nil || len(sh.Metadata.Annotations) == 0 {
generic = append(generic, manifest{name: n, content: c, head: &sh})
sm.add(0, manifest{name: n, content: c, head: &sh})
continue
}
hookTypes, ok := sh.Metadata.Annotations[hooks.HookAnno]
if !ok {
generic = append(generic, manifest{name: n, content: c, head: &sh})
// We're not a hook. Might we belong to a stage?
stgNo := 0
stgNoStr, ok := sh.Metadata.Annotations[stages.StageAnno]
if ok {
stgNo, err = strconv.Atoi(stgNoStr)
if err != nil {
stgNo = 0
}
}
sm.add(stgNo, manifest{name: n, content: c, head: &sh})
continue
}
@ -142,5 +152,5 @@ func sortManifests(files map[string]string, apis chartutil.VersionSet, sort Sort
}
hs = append(hs, h)
}
return hs, sortByKind(generic, sort), nil
return hs, sortByKind(sm, sort), nil
}

@ -120,14 +120,14 @@ metadata:
manifests[o.path] = o.manifest
}
hs, generic, err := sortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder)
hs, stgs, err := sortManifests(manifests, chartutil.NewVersionSet("v1", "v1beta1"), InstallOrder)
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
// This test will fail if 'six' or 'seven' was added.
if len(generic) != 1 {
t.Errorf("Expected 1 generic manifest, got %d", len(generic))
if len(stgs[0]) != 1 {
t.Errorf("Expected 1 generic manifest, got %d", len(stgs[0]))
}
if len(hs) != 3 {
@ -161,7 +161,7 @@ metadata:
}
// Verify the sort order
sorted := make([]manifest, len(data))
sortedStg := make(stage, len(data))
for i, s := range data {
var sh util.SimpleHead
err := yaml.Unmarshal([]byte(s.manifest), &sh)
@ -169,16 +169,17 @@ metadata:
// This is expected for manifests that are corrupt or empty.
t.Log(err)
}
sorted[i] = manifest{
sortedStg[i] = manifest{
content: s.manifest,
name: s.name,
head: &sh,
}
}
sorted = sortByKind(sorted, InstallOrder)
for i, m := range generic {
if m.content != sorted[i].content {
t.Errorf("Expected %q, got %q", m.content, sorted[i].content)
sortedStgs := stageMap{0: sortedStg}
sortedStg = sortByKind(sortedStgs, InstallOrder)[0]
for i, m := range stgs[0] {
if m.content != sortedStg[i].content {
t.Errorf("Expected %q, got %q", m.content, sortedStg[i].content)
}
}

@ -82,10 +82,14 @@ var UninstallOrder SortOrder = []string{
// sortByKind does an in-place sort of manifests by Kind.
//
// Results are sorted by 'ordering'
func sortByKind(manifests []manifest, ordering SortOrder) []manifest {
ks := newKindSorter(manifests, ordering)
func sortByKind(sm stageMap, ordering SortOrder) stageMap {
newSM := stageMap{}
for stgNo, stg := range sm {
ks := newKindSorter(stg, ordering)
sort.Sort(ks)
return ks.manifests
newSM[stgNo] = ks.manifests
}
return newSM
}
type kindSorter struct {

@ -24,7 +24,8 @@ import (
)
func TestKindSorter(t *testing.T) {
manifests := []manifest{
stgs := stageMap{
0: {
{
name: "i",
content: "",
@ -140,6 +141,7 @@ func TestKindSorter(t *testing.T) {
content: "",
head: &util.SimpleHead{Kind: "StatefulSet"},
},
},
}
for _, test := range []struct {
@ -152,11 +154,11 @@ func TestKindSorter(t *testing.T) {
} {
var buf bytes.Buffer
t.Run(test.description, func(t *testing.T) {
if got, want := len(test.expected), len(manifests); got != want {
if got, want := len(test.expected), len(stgs[0]); got != want {
t.Fatalf("Expected %d names in order, got %d", want, got)
}
defer buf.Reset()
for _, r := range sortByKind(manifests, test.order) {
for _, r := range sortByKind(stgs, test.order)[0] {
buf.WriteString(r.name)
}
if got := buf.String(); got != test.expected {

@ -154,7 +154,8 @@ func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient env
}
errs = []error{}
for _, file := range filesToDelete {
for _, stg := range filesToDelete {
for _, file := range stg {
b := bytes.NewBufferString(strings.TrimSpace(file.content))
if b.Len() == 0 {
continue
@ -168,5 +169,6 @@ func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient env
errs = append(errs, err)
}
}
}
return kept, errs
}

@ -448,11 +448,16 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
return nil, nil, err
}
hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions)
hooks, dm, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions)
if err != nil {
return nil, nil, err
}
docMap := make(map[int32]string, len(dm))
for i, d := range dm {
docMap[int32(i)] = d.String()
}
// Store an updated release.
updatedRelease := &release.Release{
Name: req.Name,
@ -466,14 +471,14 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
Description: "Preparing upgrade", // This should be overwritten later.
},
Version: revision,
Manifest: manifestDoc.String(),
Stages: docMap,
Hooks: hooks,
}
if len(notesTxt) > 0 {
updatedRelease.Info.Status.Notes = notesTxt
}
err = validateManifest(s.env.KubeClient, currentRelease.Namespace, manifestDoc.Bytes())
err = validateManifests(s.env.KubeClient, currentRelease.Namespace, dm)
return currentRelease, updatedRelease, err
}
@ -723,7 +728,11 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
return nil, err
}
hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions)
hooks, dm, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions)
docMap := make(map[int32]string, len(dm))
for i, d := range dm {
docMap[int32(i)] = d.String()
}
if err != nil {
// Return a release with partial data so that client can show debugging
// information.
@ -740,9 +749,7 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
},
Version: 0,
}
if manifestDoc != nil {
rel.Manifest = manifestDoc.String()
}
rel.Stages = docMap
return rel, err
}
@ -758,7 +765,7 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
Status: &release.Status{Code: release.Status_UNKNOWN},
Description: "Initial install underway", // Will be overwritten.
},
Manifest: manifestDoc.String(),
Stages: docMap,
Hooks: hooks,
Version: int32(revision),
}
@ -766,7 +773,7 @@ func (s *ReleaseServer) prepareRelease(req *services.InstallReleaseRequest) (*re
rel.Info.Status.Notes = notesTxt
}
err = validateManifest(s.env.KubeClient, req.Namespace, manifestDoc.Bytes())
err = validateManifests(s.env.KubeClient, req.Namespace, dm)
return rel, err
}
@ -789,7 +796,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, vs chartutil.VersionSet) ([]*release.Hook, docMap, string, error) {
// Guard to make sure Tiller is at the right version to handle this chart.
sver := version.GetVersion()
if ch.Metadata.TillerVersion != "" &&
@ -823,32 +830,23 @@ func (s *ReleaseServer) renderResources(ch *chart.Chart, values chartutil.Values
// Sort hooks, manifests, and partials. Only hooks and manifests are returned,
// as partials are not used after renderer.Render. Empty manifests are also
// removed here.
hooks, manifests, err := sortManifests(files, vs, InstallOrder)
if err != nil {
// By catching parse errors here, we can prevent bogus releases from going
// to Kubernetes.
//
// We return the files as a big blob of data to help the user debug parser
// errors.
b := bytes.NewBuffer(nil)
for name, content := range files {
if len(strings.TrimSpace(content)) == 0 {
continue
}
b.WriteString("\n---\n# Source: " + name + "\n")
b.WriteString(content)
hooks, sm, err := sortManifests(files, vs, InstallOrder)
// Aggregate all valid manifests into one big doc per stage.
dm := make(docMap, len(sm))
for stgNo, stg := range sm {
dm[stgNo] = bytes.NewBuffer(nil)
for _, m := range stg {
dm[stgNo].WriteString("\n---\n# Source: " + m.name + "\n")
dm[stgNo].WriteString(m.content)
}
return nil, b, "", err
}
// Aggregate all valid manifests into one big doc.
b := bytes.NewBuffer(nil)
for _, m := range manifests {
b.WriteString("\n---\n# Source: " + m.name + "\n")
b.WriteString(m.content)
if err != nil {
return nil, dm, "", err
}
return hooks, b, notes, nil
return hooks, dm, notes, nil
}
func (s *ReleaseServer) recordRelease(r *release.Release, reuse bool) {
@ -1094,10 +1092,15 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR
return res, nil
}
func validateManifest(c environment.KubeClient, ns string, manifest []byte) error {
r := bytes.NewReader(manifest)
func validateManifests(c environment.KubeClient, ns string, dm docMap) error {
for _, d := range dm {
r := bytes.NewReader(d.Bytes())
_, err := c.BuildUnstructured(ns, r)
if err != nil {
return err
}
}
return nil
}
// RunReleaseTest runs pre-defined tests stored as hooks on a given release

@ -313,16 +313,16 @@ func TestInstallRelease(t *testing.T) {
t.Errorf("Expected event 0 is pre-delete")
}
if len(res.Release.Manifest) == 0 {
if len(res.Release.Stages[0]) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
}
if len(rel.Manifest) == 0 {
if len(rel.Stages[0]) == 0 {
t.Errorf("Expected manifest in %v", res)
}
if !strings.Contains(rel.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Manifest)
if !strings.Contains(rel.Stages[0], "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Stages[0])
}
if rel.Info.Description != "Install complete" {
@ -382,16 +382,16 @@ func TestInstallRelease_WithNotes(t *testing.T) {
t.Errorf("Expected event 0 is pre-delete")
}
if len(res.Release.Manifest) == 0 {
if len(res.Release.Stages[0]) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
}
if len(rel.Manifest) == 0 {
if len(rel.Stages[0]) == 0 {
t.Errorf("Expected manifest in %v", res)
}
if !strings.Contains(rel.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Manifest)
if !strings.Contains(rel.Stages[0], "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Stages[0])
}
if rel.Info.Description != "Install complete" {
@ -452,16 +452,16 @@ func TestInstallRelease_WithNotesRendered(t *testing.T) {
t.Errorf("Expected event 0 is pre-delete")
}
if len(res.Release.Manifest) == 0 {
if len(res.Release.Stages[0]) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
}
if len(rel.Manifest) == 0 {
if len(rel.Stages[0]) == 0 {
t.Errorf("Expected manifest in %v", res)
}
if !strings.Contains(rel.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Manifest)
if !strings.Contains(rel.Stages[0], "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Stages[0])
}
if rel.Info.Description != "Install complete" {
@ -585,24 +585,24 @@ func TestInstallRelease_DryRun(t *testing.T) {
t.Errorf("Expected release name.")
}
if !strings.Contains(res.Release.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", res.Release.Manifest)
if !strings.Contains(res.Release.Stages[0], "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", res.Release.Stages[0])
}
if !strings.Contains(res.Release.Manifest, "---\n# Source: hello/templates/goodbye\ngoodbye: world") {
t.Errorf("unexpected output: %s", res.Release.Manifest)
if !strings.Contains(res.Release.Stages[0], "---\n# Source: hello/templates/goodbye\ngoodbye: world") {
t.Errorf("unexpected output: %s", res.Release.Stages[0])
}
if !strings.Contains(res.Release.Manifest, "hello: Earth") {
t.Errorf("Should contain partial content. %s", res.Release.Manifest)
if !strings.Contains(res.Release.Stages[0], "hello: Earth") {
t.Errorf("Should contain partial content. %s", res.Release.Stages[0])
}
if strings.Contains(res.Release.Manifest, "hello: {{ template \"_planet\" . }}") {
t.Errorf("Should not contain partial templates itself. %s", res.Release.Manifest)
if strings.Contains(res.Release.Stages[0], "hello: {{ template \"_planet\" . }}") {
t.Errorf("Should not contain partial templates itself. %s", res.Release.Stages[0])
}
if strings.Contains(res.Release.Manifest, "empty") {
t.Errorf("Should not contain template data for an empty file. %s", res.Release.Manifest)
if strings.Contains(res.Release.Stages[0], "empty") {
t.Errorf("Should not contain template data for an empty file. %s", res.Release.Stages[0])
}
if _, err := rs.env.Releases.Get(res.Release.Name, res.Release.Version); err == nil {
@ -744,7 +744,7 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected event 0 to be pre upgrade")
}
if len(res.Release.Manifest) == 0 {
if len(res.Release.Stages[0]) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
}
@ -754,12 +754,12 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected release values %q, got %q", rel.Config.Raw, res.Release.Config.Raw)
}
if len(updated.Manifest) == 0 {
if len(updated.Stages[0]) == 0 {
t.Errorf("Expected manifest in %v", res)
}
if !strings.Contains(updated.Manifest, "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Manifest)
if !strings.Contains(updated.Stages[0], "---\n# Source: hello/templates/hello\nhello: world") {
t.Errorf("unexpected output: %s", rel.Stages[0])
}
if res.Release.Version != 2 {
@ -1060,7 +1060,8 @@ func TestRollbackRelease(t *testing.T) {
},
}
upgradedRel.Manifest = "hello world"
upgradedRel.Stages = map[int32]string{}
upgradedRel.Stages[0] = "hello world"
rs.env.Releases.Update(rel)
rs.env.Releases.Create(upgradedRel)
@ -1135,16 +1136,16 @@ func TestRollbackRelease(t *testing.T) {
t.Errorf("Expected event 1 to be post rollback")
}
if len(res.Release.Manifest) == 0 {
if len(res.Release.Stages[0]) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
}
if len(updated.Manifest) == 0 {
if len(updated.Stages[0]) == 0 {
t.Errorf("Expected manifest in %v", res)
}
if !strings.Contains(updated.Manifest, "hello world") {
t.Errorf("unexpected output: %s", rel.Manifest)
if !strings.Contains(updated.Stages[0], "hello world") {
t.Errorf("unexpected output: %s", rel.Stages[0])
}
if res.Release.Info.Description != "Rollback to 2" {

@ -29,11 +29,13 @@ const resourcePolicyAnno = "helm.sh/resource-policy"
// during an uninstallRelease action.
const keepPolicy = "keep"
func filterManifestsToKeep(manifests []manifest) ([]manifest, []manifest) {
remaining := []manifest{}
keep := []manifest{}
for _, m := range manifests {
func filterManifestsToKeep(sm stageMap) (stageMap, stageMap) {
remainingMap := stageMap{}
keepMap := stageMap{}
for stgNo, stg := range sm {
remaining := stage{}
keep := stage{}
for _, m := range stg {
if m.head.Metadata == nil || m.head.Metadata.Annotations == nil || len(m.head.Metadata.Annotations) == 0 {
remaining = append(remaining, m)
@ -52,14 +54,23 @@ func filterManifestsToKeep(manifests []manifest) ([]manifest, []manifest) {
}
}
return keep, remaining
if len(remaining) > 0 {
remainingMap[stgNo] = remaining
}
if len(keep) > 0 {
keepMap[stgNo] = keep
}
}
return keepMap, remainingMap
}
func summarizeKeptManifests(manifests []manifest) string {
func summarizeKeptManifests(sm stageMap) string {
message := "These resources were kept due to the resource policy:\n"
for _, m := range manifests {
for _, stg := range sm {
for _, m := range stg {
details := "[" + m.head.Kind + "] " + m.head.Metadata.Name + "\n"
message = message + details
}
}
return message
}

@ -0,0 +1,29 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package tiller
type stage []manifest
type stageMap map[int]stage
func (s stageMap) add(stgNo int, man manifest) {
_, ok := s[stgNo]
if !ok {
s[stgNo] = stage{}
}
s[stgNo] = append(s[stgNo], man)
}
Loading…
Cancel
Save