Skip to content

Commit

Permalink
Use dry-run to resolve manifest when rolling back (#1133)
Browse files Browse the repository at this point in the history
* Use dry-run to resolve manifest when rolling back

* Use ReleaseContent. Add tests
  • Loading branch information
Andres Martinez Gotor committed Aug 22, 2019
1 parent 662e39b commit e3cc60f
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 15 deletions.
17 changes: 6 additions & 11 deletions cmd/tiller-proxy/internal/handler/handler.go
Expand Up @@ -221,13 +221,13 @@ func (h *TillerProxy) RollbackRelease(w http.ResponseWriter, req *http.Request,
response.NewErrorResponse(http.StatusUnprocessableEntity, "Missing revision to rollback in request").Write(w)
return
}
revisionInt, err := strconv.ParseInt(revision, 10, 64)
if err != nil {
response.NewErrorResponse(errorCode(err), err.Error()).Write(w)
return
}
if !h.DisableAuth {
chartDetails, ch, err := getChart(req, h.ChartClient)
if err != nil {
response.NewErrorResponse(errorCode(err), err.Error()).Write(w)
return
}
manifest, err := h.ProxyClient.ResolveManifest(params["namespace"], chartDetails.Values, ch)
manifest, err := h.ProxyClient.ResolveManifestFromRelease(params["releaseName"], int32(revisionInt))
if err != nil {
response.NewErrorResponse(errorCode(err), err.Error()).Write(w)
return
Expand All @@ -244,11 +244,6 @@ func (h *TillerProxy) RollbackRelease(w http.ResponseWriter, req *http.Request,
return
}
}
revisionInt, err := strconv.ParseInt(revision, 10, 64)
if err != nil {
response.NewErrorResponse(errorCode(err), err.Error()).Write(w)
return
}
rel, err := h.ProxyClient.RollbackRelease(params["releaseName"], params["namespace"], int32(revisionInt))
if err != nil {
response.NewErrorResponse(errorCodeWithDefault(err, http.StatusUnprocessableEntity), err.Error()).Write(w)
Expand Down
6 changes: 3 additions & 3 deletions cmd/tiller-proxy/internal/handler/handler_test.go
Expand Up @@ -387,7 +387,7 @@ func TestActions(t *testing.T) {
DisableAuth: false,
ForbiddenActions: []auth.Action{},
// Request params
RequestBody: `{"chartName": "foo", "releaseName": "foo", "version": "1.0.0"}`,
RequestBody: "",
RequestQuery: "?revision=1",
Action: "rollback",
Params: map[string]string{"namespace": "default", "releaseName": "foo"},
Expand All @@ -405,7 +405,7 @@ func TestActions(t *testing.T) {
DisableAuth: true,
ForbiddenActions: []auth.Action{},
// Request params
RequestBody: `{"chartName": "foo", "releaseName": "foobar", "version": "1.0.0"}`,
RequestBody: "",
RequestQuery: "?revision=1",
Action: "rollback",
Params: map[string]string{"namespace": "default", "releaseName": "foobar"},
Expand All @@ -421,7 +421,7 @@ func TestActions(t *testing.T) {
DisableAuth: true,
ForbiddenActions: []auth.Action{},
// Request params
RequestBody: `{"chartName": "foo", "releaseName": "foobar", "version": "1.0.0"}`,
RequestBody: "",
RequestQuery: "",
Action: "rollback",
Params: map[string]string{"namespace": "default", "releaseName": "foobar"},
Expand Down
4 changes: 4 additions & 0 deletions pkg/proxy/fake/proxy.go
Expand Up @@ -37,6 +37,10 @@ func (f *FakeProxy) ResolveManifest(namespace, values string, ch *chart.Chart) (
return "", nil
}

func (f *FakeProxy) ResolveManifestFromRelease(releaseName string, revision int32) (string, error) {
return "", nil
}

func (f *FakeProxy) ListReleases(namespace string, releaseListLimit int, status string) ([]proxy.AppOverview, error) {
res := []proxy.AppOverview{}
for _, r := range f.Releases {
Expand Down
15 changes: 15 additions & 0 deletions pkg/proxy/proxy.go
Expand Up @@ -125,6 +125,20 @@ func (p *Proxy) ResolveManifest(namespace, values string, ch *chart.Chart) (stri
return strings.TrimLeft(resDry.Release.Manifest, "\n"), nil
}

// ResolveManifestFromRelease returns a manifest given the release name and revision
func (p *Proxy) ResolveManifestFromRelease(releaseName string, revision int32) (string, error) {
// We use the release returned after running a dry-run to know the components of the release
res, err := p.helmClient.ReleaseContent(
releaseName,
helm.ContentReleaseVersion(revision),
)
if err != nil {
return "", err
}
// The manifest returned has some extra new lines at the beginning
return strings.TrimLeft(res.Release.Manifest, "\n"), nil
}

// Apply the same filtering than helm CLI
// Ref: https://github.com/helm/helm/blob/d3b69c1fc1ac62f1cc40f93fcd0cba275c0596de/cmd/helm/list.go#L173
func filterList(rels []*release.Release) []*release.Release {
Expand Down Expand Up @@ -327,6 +341,7 @@ func prettyError(err error) error {
type TillerClient interface {
GetReleaseStatus(relName string) (release.Status_Code, error)
ResolveManifest(namespace, values string, ch *chart.Chart) (string, error)
ResolveManifestFromRelease(releaseName string, revision int32) (string, error)
ListReleases(namespace string, releaseListLimit int, status string) ([]AppOverview, error)
CreateRelease(name, namespace, values string, ch *chart.Chart) (*release.Release, error)
UpdateRelease(name, namespace string, values string, ch *chart.Chart) (*release.Release, error)
Expand Down
81 changes: 80 additions & 1 deletion pkg/proxy/proxy_test.go
Expand Up @@ -29,7 +29,12 @@ import (
"k8s.io/helm/pkg/proto/hapi/release"
)

func newFakeProxy(existingTillerReleases []AppOverview) *Proxy {
type AppOverviewTest struct {
AppOverview
Manifest string
}

func newFakeProxyWithManifest(existingTillerReleases []AppOverviewTest) *Proxy {
helmClient := helm.FakeClient{}
// Populate Fake helm client with releases
for _, r := range existingTillerReleases {
Expand Down Expand Up @@ -63,12 +68,21 @@ func newFakeProxy(existingTillerReleases []AppOverview) *Proxy {
Code: status,
},
},
Manifest: r.Manifest,
})
}
kubeClient := fake.NewSimpleClientset()
return NewProxy(kubeClient, &helmClient)
}

func newFakeProxy(existingTillerReleases []AppOverview) *Proxy {
releasesWithManifest := []AppOverviewTest{}
for _, r := range existingTillerReleases {
releasesWithManifest = append(releasesWithManifest, AppOverviewTest{r, ""})
}
return newFakeProxyWithManifest(releasesWithManifest)
}

func TestListAllReleases(t *testing.T) {
app1 := AppOverview{"foo", "1.0.0", "my_ns", "icon.png", "DEPLOYED", "wordpress", chart.Metadata{
Version: "1.0.0",
Expand Down Expand Up @@ -241,6 +255,71 @@ func TestResolveManifest(t *testing.T) {
}
}

func TestResolveManifestFromRelease(t *testing.T) {
app1 := AppOverview{"foo", "1.0.0", "my_ns", "icon.png", "DEPLOYED", "wordpress", chart.Metadata{
Version: "1.0.0",
Icon: "icon.png",
Name: "wordpress",
}}
app2 := AppOverview{"bar", "1.0.0", "other_ns", "icon2.png", "DELETED", "wordpress", chart.Metadata{
Version: "1.0.0",
Icon: "icon2.png",
Name: "wordpress",
}}
type testStruct struct {
description string
existingApps []AppOverviewTest
releaseName string
shouldFail bool
expectedManifest string
}
tests := []testStruct{
{
"should return the right manifest",
[]AppOverviewTest{{app1, "foo: bar"}, {app2, "bar: foo"}},
app2.ReleaseName,
false,
"bar: foo",
},
{
"should trim initial empty lines",
[]AppOverviewTest{{app1, "\nfoo: bar"}, {app2, "bar: foo"}},
app1.ReleaseName,
false,
"foo: bar",
},
{
"should fail if the app doesn't exists",
[]AppOverviewTest{{app1, "foo: bar"}, {app2, "bar: foo"}},
"foobar",
true,
"",
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
proxy := newFakeProxyWithManifest(test.existingApps)

manifest, err := proxy.ResolveManifestFromRelease(test.releaseName, 1)
if test.shouldFail {
if err == nil {
t.Error("Test should have failed")
}
} else {
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if test.expectedManifest != manifest {
t.Errorf("manifest doesn't match. Want %s got %s", test.expectedManifest, manifest)
}
if strings.HasPrefix(manifest, "\n") {
t.Error("The manifest should not contain new lines at the beginning")
}
}
})
}
}

func TestCreateHelmRelease(t *testing.T) {
ns := "myns"
rs := "foo"
Expand Down

0 comments on commit e3cc60f

Please sign in to comment.