Commit ac88aaf2 authored by Michelle Noorali's avatar Michelle Noorali Committed by Adam Reese

feat(*): add helm rollback functionality

This feature allows you to rollback release to the
previous version of release.
resolves #1004
parent 9547f471
...@@ -30,6 +30,8 @@ message Hook { ...@@ -30,6 +30,8 @@ message Hook {
POST_DELETE = 4; POST_DELETE = 4;
PRE_UPGRADE = 5; PRE_UPGRADE = 5;
POST_UPGRADE = 6; POST_UPGRADE = 6;
PRE_ROLLBACK = 7;
POST_ROLLBACK = 8;
} }
string name = 1; string name = 1;
// Kind is the Kubernetes kind. // Kind is the Kubernetes kind.
......
...@@ -69,7 +69,12 @@ service ReleaseService { ...@@ -69,7 +69,12 @@ service ReleaseService {
// GetVersion returns the current version of the server. // GetVersion returns the current version of the server.
rpc GetVersion(GetVersionRequest) returns (GetVersionResponse) { rpc GetVersion(GetVersionRequest) returns (GetVersionResponse) {
} }
// RollbackRelease rolls back a release to a previous version.
rpc RollbackRelease(RollbackReleaseRequest) returns (RollbackReleaseResponse) {
}
} }
// ListReleasesRequest requests a list of releases. // ListReleasesRequest requests a list of releases.
...@@ -188,6 +193,20 @@ message UpdateReleaseResponse { ...@@ -188,6 +193,20 @@ message UpdateReleaseResponse {
hapi.release.Release release = 1; hapi.release.Release release = 1;
} }
message RollbackReleaseRequest {
// The name of the release
string name = 1;
// dry_run, if true, will run through the release logic but no create
bool dry_run = 2;
// DisableHooks causes the server to skip running any hooks for the rollback
bool disable_hooks = 3;
}
// RollbackReleaseResponse is the response to an update request.
message RollbackReleaseResponse {
hapi.release.Release release = 1;
}
// InstallReleaseRequest is the request for an installation of a chart. // InstallReleaseRequest is the request for an installation of a chart.
message InstallReleaseRequest { message InstallReleaseRequest {
// Chart is the protobuf representation of a chart. // Chart is the protobuf representation of a chart.
......
...@@ -159,6 +159,10 @@ func (c *fakeReleaseClient) UpdateRelease(rlsName string, chStr string, opts ... ...@@ -159,6 +159,10 @@ func (c *fakeReleaseClient) UpdateRelease(rlsName string, chStr string, opts ...
return nil, nil return nil, nil
} }
func (c *fakeReleaseClient) RollbackRelease(rlsName string, opts ...helm.RollbackOption) (*rls.RollbackReleaseResponse, error) {
return nil, nil
}
func (c *fakeReleaseClient) ReleaseContent(rlsName string, opts ...helm.ContentOption) (resp *rls.GetReleaseContentResponse, err error) { func (c *fakeReleaseClient) ReleaseContent(rlsName string, opts ...helm.ContentOption) (resp *rls.GetReleaseContentResponse, err error) {
if len(c.rels) > 0 { if len(c.rels) > 0 {
resp = &rls.GetReleaseContentResponse{ resp = &rls.GetReleaseContentResponse{
......
...@@ -27,9 +27,7 @@ import ( ...@@ -27,9 +27,7 @@ import (
const rollbackDesc = ` const rollbackDesc = `
This command rolls back a release to the previous version. This command rolls back a release to the previous version.
The argument of the rollback command is the name of a release.
The rollback argument is the name of a release.
` `
type rollbackCmd struct { type rollbackCmd struct {
...@@ -55,22 +53,25 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command { ...@@ -55,22 +53,25 @@ func newRollbackCmd(c helm.Interface, out io.Writer) *cobra.Command {
if err := checkArgsLength(len(args), "release name"); err != nil { if err := checkArgsLength(len(args), "release name"); err != nil {
return err return err
} }
rollback.name = args[0]
rollback.client = ensureHelmClient(rollback.client) rollback.client = ensureHelmClient(rollback.client)
return rollback.run() return rollback.run()
}, },
} }
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&rollback.dryRun, "dry-run", false, "simulate an install") f.BoolVar(&rollback.dryRun, "dry-run", false, "simulate a rollback")
f.BoolVar(&rollback.disableHooks, "no-hooks", false, "prevent hooks from running during rollback") f.BoolVar(&rollback.disableHooks, "no-hooks", false, "prevent hooks from running during rollback")
return cmd return cmd
} }
func (r *rollbackCmd) run() error { func (r *rollbackCmd) run() error {
_, err := r.client.RollbackRelease(r.name, helm.RollbackDryRun(r.dryRun), helm.RollbackDisableHooks(r.disableHooks))
if err != nil {
return prettyError(err)
}
msg := "This command is under construction. Coming soon to a Helm near you!" fmt.Fprintf(r.out, "Rollback was a success! Happy Helming!\n")
fmt.Fprintf(r.out, msg)
return nil return nil
} }
...@@ -30,7 +30,7 @@ func TestRollbackCmd(t *testing.T) { ...@@ -30,7 +30,7 @@ func TestRollbackCmd(t *testing.T) {
name: "rollback a release", name: "rollback a release",
args: []string{"funny-honey"}, args: []string{"funny-honey"},
resp: nil, resp: nil,
expected: "This command is under construction. Coming soon to a Helm near you!", expected: "Rollback was a success! Happy Helming!",
}, },
} }
......
...@@ -36,6 +36,8 @@ const ( ...@@ -36,6 +36,8 @@ const (
postDelete = "post-delete" postDelete = "post-delete"
preUpgrade = "pre-upgrade" preUpgrade = "pre-upgrade"
postUpgrade = "post-upgrade" postUpgrade = "post-upgrade"
preRollback = "pre-rollback"
postRollback = "post-rollback"
) )
var events = map[string]release.Hook_Event{ var events = map[string]release.Hook_Event{
...@@ -45,6 +47,8 @@ var events = map[string]release.Hook_Event{ ...@@ -45,6 +47,8 @@ var events = map[string]release.Hook_Event{
postDelete: release.Hook_POST_DELETE, postDelete: release.Hook_POST_DELETE,
preUpgrade: release.Hook_PRE_UPGRADE, preUpgrade: release.Hook_PRE_UPGRADE,
postUpgrade: release.Hook_POST_UPGRADE, postUpgrade: release.Hook_POST_UPGRADE,
preRollback: release.Hook_PRE_ROLLBACK,
postRollback: release.Hook_POST_ROLLBACK,
} }
type simpleHead struct { type simpleHead struct {
......
...@@ -30,6 +30,7 @@ import ( ...@@ -30,6 +30,7 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/technosophos/moniker" "github.com/technosophos/moniker"
ctx "golang.org/x/net/context" ctx "golang.org/x/net/context"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/helm/cmd/tiller/environment" "k8s.io/helm/cmd/tiller/environment"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
...@@ -39,7 +40,6 @@ import ( ...@@ -39,7 +40,6 @@ import (
"k8s.io/helm/pkg/storage/driver" "k8s.io/helm/pkg/storage/driver"
"k8s.io/helm/pkg/timeconv" "k8s.io/helm/pkg/timeconv"
"k8s.io/helm/pkg/version" "k8s.io/helm/pkg/version"
"k8s.io/kubernetes/pkg/api/unversioned"
) )
var srv *releaseServer var srv *releaseServer
...@@ -303,10 +303,7 @@ func (s *releaseServer) performUpdate(originalRelease, updatedRelease *release.R ...@@ -303,10 +303,7 @@ func (s *releaseServer) performUpdate(originalRelease, updatedRelease *release.R
} }
} }
kubeCli := s.env.KubeClient if err := s.performKubeUpdate(originalRelease, updatedRelease); err != nil {
original := bytes.NewBufferString(originalRelease.Manifest)
modified := bytes.NewBufferString(updatedRelease.Manifest)
if err := kubeCli.Update(updatedRelease.Namespace, original, modified); err != nil {
return nil, err return nil, err
} }
...@@ -382,6 +379,114 @@ func (s *releaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele ...@@ -382,6 +379,114 @@ func (s *releaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
return currentRelease, updatedRelease, nil return currentRelease, updatedRelease, nil
} }
func (s *releaseServer) RollbackRelease(c ctx.Context, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
currentRelease, targetRelease, err := s.prepareRollback(req)
if err != nil {
return nil, err
}
rel, err := s.performRollback(currentRelease, targetRelease, req)
if err != nil {
return nil, err
}
if err := s.env.Releases.Create(targetRelease); err != nil {
return nil, err
}
return rel, nil
}
func (s *releaseServer) performRollback(currentRelease, targetRelease *release.Release, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
res := &services.RollbackReleaseResponse{Release: targetRelease}
if req.DryRun {
log.Printf("Dry run for %s", targetRelease.Name)
return res, nil
}
// pre-rollback hooks
if !req.DisableHooks {
if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, preRollback); err != nil {
return res, err
}
}
if err := s.performKubeUpdate(currentRelease, targetRelease); err != nil {
return nil, err
}
// post-rollback hooks
if !req.DisableHooks {
if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, postRollback); err != nil {
return res, err
}
}
currentRelease.Info.Status.Code = release.Status_SUPERSEDED
if err := s.env.Releases.Update(currentRelease); err != nil {
return nil, fmt.Errorf("Update of %s failed: %s", currentRelease.Name, err)
}
targetRelease.Info.Status.Code = release.Status_DEPLOYED
return res, nil
}
func (s *releaseServer) performKubeUpdate(currentRelease, targetRelease *release.Release) error {
kubeCli := s.env.KubeClient
current := bytes.NewBufferString(currentRelease.Manifest)
target := bytes.NewBufferString(targetRelease.Manifest)
if err := kubeCli.Update(targetRelease.Namespace, current, target); err != nil {
return err
}
return nil
}
// prepareRollback finds the previous release and prepares a new release object with
// the previous release's configuration
func (s *releaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*release.Release, *release.Release, error) {
if req.Name == "" {
return nil, nil, errMissingRelease
}
// finds the non-deleted release with the given name
currentRelease, err := s.env.Releases.Deployed(req.Name)
if err != nil {
return nil, nil, err
}
previousRelease, err := s.env.Releases.Get(req.Name, currentRelease.Version-1)
if err != nil {
return nil, nil, err
}
ts := timeconv.Now()
// Store a new release object with previous release's configuration
targetRelease := &release.Release{
Name: req.Name,
Namespace: currentRelease.Namespace,
Chart: previousRelease.Chart,
Config: previousRelease.Config,
Info: &release.Info{
FirstDeployed: currentRelease.Info.FirstDeployed,
LastDeployed: ts,
Status: &release.Status{
Code: release.Status_UNKNOWN,
Notes: previousRelease.Info.Status.Notes,
},
},
Version: currentRelease.Version + 1,
Manifest: previousRelease.Manifest,
Hooks: previousRelease.Hooks,
}
return currentRelease, targetRelease, nil
}
func (s *releaseServer) uniqName(start string, reuse bool) (string, error) { func (s *releaseServer) uniqName(start string, reuse bool) (string, error) {
// If a name is supplied, we check to see if that name is taken. If not, it // If a name is supplied, we check to see if that name is taken. If not, it
......
...@@ -60,6 +60,16 @@ data: ...@@ -60,6 +60,16 @@ data:
name: value name: value
` `
var manifestWithRollbackHooks = `apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
annotations:
"helm.sh/hook": post-rollback,pre-rollback
data:
name: value
`
func rsFixture() *releaseServer { func rsFixture() *releaseServer {
return &releaseServer{ return &releaseServer{
env: mockEnvironment(), env: mockEnvironment(),
...@@ -117,6 +127,23 @@ func namedReleaseStub(name string, status release.Status_Code) *release.Release ...@@ -117,6 +127,23 @@ func namedReleaseStub(name string, status release.Status_Code) *release.Release
} }
} }
func upgradeReleaseVersion(rel *release.Release) *release.Release {
date := timestamp.Timestamp{Seconds: 242085845, Nanos: 0}
rel.Info.Status.Code = release.Status_SUPERSEDED
return &release.Release{
Name: rel.Name,
Info: &release.Info{
FirstDeployed: rel.Info.FirstDeployed,
LastDeployed: &date,
Status: &release.Status{Code: release.Status_DEPLOYED},
},
Chart: rel.Chart,
Config: rel.Config,
Version: rel.Version + 1,
}
}
func TestGetVersionSet(t *testing.T) { func TestGetVersionSet(t *testing.T) {
rs := rsFixture() rs := rsFixture()
vs, err := rs.getVersionSet() vs, err := rs.getVersionSet()
...@@ -601,6 +628,150 @@ func TestUpdateReleaseNoChanges(t *testing.T) { ...@@ -601,6 +628,150 @@ func TestUpdateReleaseNoChanges(t *testing.T) {
} }
} }
func TestRollbackReleaseNoHooks(t *testing.T) {
c := context.Background()
rs := rsFixture()
rel := releaseStub()
rel.Hooks = []*release.Hook{
{
Name: "test-cm",
Kind: "ConfigMap",
Path: "test-cm",
Manifest: manifestWithRollbackHooks,
Events: []release.Hook_Event{
release.Hook_PRE_ROLLBACK,
release.Hook_POST_ROLLBACK,
},
},
}
rs.env.Releases.Create(rel)
upgradedRel := upgradeReleaseVersion(rel)
rs.env.Releases.Update(rel)
rs.env.Releases.Create(upgradedRel)
req := &services.RollbackReleaseRequest{
Name: rel.Name,
DisableHooks: true,
}
res, err := rs.RollbackRelease(c, req)
if err != nil {
t.Fatalf("Failed rollback: %s", err)
}
if hl := res.Release.Hooks[0].LastRun; hl != nil {
t.Errorf("Expected that no hooks were run. Got %d", hl)
}
}
func TestRollbackRelease(t *testing.T) {
c := context.Background()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
upgradedRel := upgradeReleaseVersion(rel)
upgradedRel.Hooks = []*release.Hook{
{
Name: "test-cm",
Kind: "ConfigMap",
Path: "test-cm",
Manifest: manifestWithRollbackHooks,
Events: []release.Hook_Event{
release.Hook_PRE_ROLLBACK,
release.Hook_POST_ROLLBACK,
},
},
}
upgradedRel.Manifest = "hello world"
rs.env.Releases.Update(rel)
rs.env.Releases.Create(upgradedRel)
req := &services.RollbackReleaseRequest{
Name: rel.Name,
}
res, err := rs.RollbackRelease(c, req)
if err != nil {
t.Fatalf("Failed rollback: %s", err)
}
if res.Release.Name == "" {
t.Errorf("Expected release name.")
}
if res.Release.Name != rel.Name {
t.Errorf("Updated release name does not match previous release name. Expected %s, got %s", rel.Name, res.Release.Name)
}
if res.Release.Namespace != rel.Namespace {
t.Errorf("Expected release namespace '%s', got '%s'.", rel.Namespace, res.Release.Namespace)
}
if res.Release.Version != 3 {
t.Errorf("Expected release version to be %v, got %v", 3, res.Release.Version)
}
updated, 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)
}
if len(updated.Hooks) != 1 {
t.Fatalf("Expected 1 hook, got %d", len(updated.Hooks))
}
if updated.Hooks[0].Manifest != manifestWithHook {
t.Errorf("Unexpected manifest: %v", updated.Hooks[0].Manifest)
}
anotherUpgradedRelease := upgradeReleaseVersion(upgradedRel)
rs.env.Releases.Update(upgradedRel)
rs.env.Releases.Create(anotherUpgradedRelease)
res, err = rs.RollbackRelease(c, req)
if err != nil {
t.Fatalf("Failed rollback: %s", err)
}
updated, 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)
}
if len(updated.Hooks) != 1 {
t.Fatalf("Expected 1 hook, got %d", len(updated.Hooks))
}
if updated.Hooks[0].Manifest != manifestWithRollbackHooks {
t.Errorf("Unexpected manifest: %v", updated.Hooks[0].Manifest)
}
if res.Release.Version != 4 {
t.Errorf("Expected release version to be %v, got %v", 3, res.Release.Version)
}
if updated.Hooks[0].Events[0] != release.Hook_PRE_ROLLBACK {
t.Errorf("Expected event 0 to be pre rollback")
}
if updated.Hooks[0].Events[1] != release.Hook_POST_ROLLBACK {
t.Errorf("Expected event 1 to be post rollback")
}
if len(res.Release.Manifest) == 0 {
t.Errorf("No manifest returned: %v", res.Release)
}
if len(updated.Manifest) == 0 {
t.Errorf("Expected manifest in %v", res)
}
if !strings.Contains(updated.Manifest, "hello world") {
t.Errorf("unexpected output: %s", rel.Manifest)
}
}
func TestUninstallRelease(t *testing.T) { func TestUninstallRelease(t *testing.T) {
c := helm.NewContext() c := helm.NewContext()
rs := rsFixture() rs := rsFixture()
......
...@@ -131,6 +131,17 @@ func (h *Client) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, err ...@@ -131,6 +131,17 @@ func (h *Client) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, err
return h.opts.rpcGetVersion(rls.NewReleaseServiceClient(c), opts...) return h.opts.rpcGetVersion(rls.NewReleaseServiceClient(c), opts...)
} }
// RollbackRelease rolls back a release to the previous version
func (h *Client) RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
c, err := grpc.Dial(h.opts.host, grpc.WithInsecure())
if err != nil {
return nil, err
}
defer c.Close()
return h.opts.rpcRollbackRelease(rlsName, rls.NewReleaseServiceClient(c), opts...)
}
// ReleaseStatus returns the given release's status. // ReleaseStatus returns the given release's status.
// //
// Note: there aren't currently any supported StatusOptions, // Note: there aren't currently any supported StatusOptions,
......
...@@ -27,6 +27,7 @@ type Interface interface { ...@@ -27,6 +27,7 @@ type Interface interface {
DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error) DeleteRelease(rlsName string, opts ...DeleteOption) (*rls.UninstallReleaseResponse, error)
ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) ReleaseStatus(rlsName string, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error)
UpdateRelease(rlsName, chStr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error) UpdateRelease(rlsName, chStr string, opts ...UpdateOption) (*rls.UpdateReleaseResponse, error)
RollbackRelease(rlsName string, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error)
ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error) ReleaseContent(rlsName string, opts ...ContentOption) (*rls.GetReleaseContentResponse, error)
GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error) GetVersion(opts ...VersionOption) (*rls.GetVersionResponse, error)
} }
...@@ -53,6 +53,8 @@ type options struct { ...@@ -53,6 +53,8 @@ type options struct {
statusReq rls.GetReleaseStatusRequest statusReq rls.GetReleaseStatusRequest
// release get content options are applied directly to the get release content request // release get content options are applied directly to the get release content request
contentReq rls.GetReleaseContentRequest contentReq rls.GetReleaseContentRequest
// release rollback options are applied directly to the rollback release request
rollbackReq rls.RollbackReleaseRequest
} }
// Host specifies the host address of the Tiller release server, (default = ":44134"). // Host specifies the host address of the Tiller release server, (default = ":44134").
...@@ -124,17 +126,17 @@ func ValueOverrides(raw []byte) InstallOption { ...@@ -124,17 +126,17 @@ func ValueOverrides(raw []byte) InstallOption {
} }
} }
// UpdateValueOverrides specifies a list of values to include when upgrading // ReleaseName specifies the name of the release when installing.
func UpdateValueOverrides(raw []byte) UpdateOption { func ReleaseName(name string) InstallOption {
return func(opts *options) { return func(opts *options) {
opts.updateReq.Values = &cpb.Config{Raw: string(raw)} opts.instReq.Name = name
} }
} }
// ReleaseName specifies the name of the release when installing. // UpdateValueOverrides specifies a list of values to include when upgrading
func ReleaseName(name string) InstallOption { func UpdateValueOverrides(raw []byte) UpdateOption {
return func(opts *options) { return func(opts *options) {
opts.instReq.Name = name opts.updateReq.Values = &cpb.Config{Raw: string(raw)}
} }
} }
...@@ -159,38 +161,52 @@ func DeletePurge(purge bool) DeleteOption { ...@@ -159,38 +161,52 @@ func DeletePurge(purge bool) DeleteOption {
} }
} }
// UpgradeDisableHooks will disable hooks for an upgrade operation. // InstallDryRun will (if true) execute an installation as a dry run.
func UpgradeDisableHooks(disable bool) UpdateOption { func InstallDryRun(dry bool) InstallOption {
return func(opts *options) {
opts.dryRun = dry
}
}
// InstallDisableHooks disables hooks during installation.
func InstallDisableHooks(disable bool) InstallOption {
return func(opts *options) { return func(opts *options) {
opts.disableHooks = disable opts.disableHooks = disable
} }
} }
// UpgradeDryRun will (if true) execute an upgrade as a dry run. // InstallReuseName will (if true) instruct Tiller to re-use an existing name.
func UpgradeDryRun(dry bool) UpdateOption { func InstallReuseName(reuse bool) InstallOption {
return func(opts *options) { return func(opts *options) {
opts.dryRun = dry opts.reuseName = reuse
} }
} }
// InstallDisableHooks disables hooks during installation. // RollbackDisableHooks will disable hooks for a rollback operation
func InstallDisableHooks(disable bool) InstallOption { func RollbackDisableHooks(disable bool) RollbackOption {
return func(opts *options) { return func(opts *options) {
opts.disableHooks = disable opts.disableHooks = disable
} }
} }
// InstallDryRun will (if true) execute an installation as a dry run. // RollbackDryRun will (if true) execute a rollback as a dry run.
func InstallDryRun(dry bool) InstallOption { func RollbackDryRun(dry bool) RollbackOption {
return func(opts *options) { return func(opts *options) {
opts.dryRun = dry opts.dryRun = dry
} }
} }
// InstallReuseName will (if true) instruct Tiller to re-use an existing name. // UpgradeDisableHooks will disable hooks for an upgrade operation.
func InstallReuseName(reuse bool) InstallOption { func UpgradeDisableHooks(disable bool) UpdateOption {
return func(opts *options) { return func(opts *options) {
opts.reuseName = reuse opts.disableHooks = disable
}
}
// UpgradeDryRun will (if true) execute an upgrade as a dry run.
func UpgradeDryRun(dry bool) UpdateOption {
return func(opts *options) {
opts.dryRun = dry
} }
} }
...@@ -230,6 +246,11 @@ type VersionOption func(*options) ...@@ -230,6 +246,11 @@ type VersionOption func(*options)
// the defaults used when running the `helm upgrade` command. // the defaults used when running the `helm upgrade` command.
type UpdateOption func(*options) type UpdateOption func(*options)
// RollbackOption allows specififying various settings configurable
// by the helm client user for overriding the defaults used when
// running the `helm rollback` command.
type RollbackOption func(*options)
// RPC helpers defined on `options` type. Note: These actually execute the // RPC helpers defined on `options` type. Note: These actually execute the
// the corresponding tiller RPC. There is no particular reason why these // the corresponding tiller RPC. There is no particular reason why these
// are APIs are hung off `options`, they are internal to pkg/helm to remain // are APIs are hung off `options`, they are internal to pkg/helm to remain
...@@ -303,6 +324,18 @@ func (o *options) rpcUpdateRelease(rlsName string, chr *cpb.Chart, rlc rls.Relea ...@@ -303,6 +324,18 @@ func (o *options) rpcUpdateRelease(rlsName string, chr *cpb.Chart, rlc rls.Relea
return rlc.UpdateRelease(NewContext(), &o.updateReq) return rlc.UpdateRelease(NewContext(), &o.updateReq)
} }
// Executes tiller.UpdateRelease RPC.
func (o *options) rpcRollbackRelease(rlsName string, rlc rls.ReleaseServiceClient, opts ...RollbackOption) (*rls.RollbackReleaseResponse, error) {
for _, opt := range opts {
opt(o)
}
o.rollbackReq.DryRun = o.dryRun
o.rollbackReq.Name = rlsName
return rlc.RollbackRelease(context.TODO(), &o.rollbackReq)
}
// Executes tiller.GetReleaseStatus RPC. // Executes tiller.GetReleaseStatus RPC.
func (o *options) rpcGetReleaseStatus(rlsName string, rlc rls.ReleaseServiceClient, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) { func (o *options) rpcGetReleaseStatus(rlsName string, rlc rls.ReleaseServiceClient, opts ...StatusOption) (*rls.GetReleaseStatusResponse, error) {
for _, opt := range opts { for _, opt := range opts {
......
...@@ -170,6 +170,7 @@ func (c *Client) Update(namespace string, currentReader, targetReader io.Reader) ...@@ -170,6 +170,7 @@ func (c *Client) Update(namespace string, currentReader, targetReader io.Reader)
updateErrors := []string{} updateErrors := []string{}
err = target.Visit(func(info *resource.Info, err error) error { err = target.Visit(func(info *resource.Info, err error) error {
targetInfos = append(targetInfos, info) targetInfos = append(targetInfos, info)
if err != nil { if err != nil {
return err return err
......
...@@ -45,6 +45,8 @@ const ( ...@@ -45,6 +45,8 @@ const (
Hook_POST_DELETE Hook_Event = 4 Hook_POST_DELETE Hook_Event = 4
Hook_PRE_UPGRADE Hook_Event = 5 Hook_PRE_UPGRADE Hook_Event = 5
Hook_POST_UPGRADE Hook_Event = 6 Hook_POST_UPGRADE Hook_Event = 6
Hook_PRE_ROLLBACK Hook_Event = 7
Hook_POST_ROLLBACK Hook_Event = 8
) )
var Hook_Event_name = map[int32]string{ var Hook_Event_name = map[int32]string{
...@@ -55,6 +57,8 @@ var Hook_Event_name = map[int32]string{ ...@@ -55,6 +57,8 @@ var Hook_Event_name = map[int32]string{
4: "POST_DELETE", 4: "POST_DELETE",
5: "PRE_UPGRADE", 5: "PRE_UPGRADE",
6: "POST_UPGRADE", 6: "POST_UPGRADE",
7: "PRE_ROLLBACK",
8: "POST_ROLLBACK",
} }
var Hook_Event_value = map[string]int32{ var Hook_Event_value = map[string]int32{
"UNKNOWN": 0, "UNKNOWN": 0,
...@@ -64,6 +68,8 @@ var Hook_Event_value = map[string]int32{ ...@@ -64,6 +68,8 @@ var Hook_Event_value = map[string]int32{
"POST_DELETE": 4, "POST_DELETE": 4,
"PRE_UPGRADE": 5, "PRE_UPGRADE": 5,
"POST_UPGRADE": 6, "POST_UPGRADE": 6,
"PRE_ROLLBACK": 7,
"POST_ROLLBACK": 8,
} }
func (x Hook_Event) String() string { func (x Hook_Event) String() string {
...@@ -106,24 +112,26 @@ func init() { ...@@ -106,24 +112,26 @@ func init() {
func init() { proto.RegisterFile("hapi/release/hook.proto", fileDescriptor0) } func init() { proto.RegisterFile("hapi/release/hook.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 301 bytes of a gzipped FileDescriptorProto // 321 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x4c, 0x8f, 0x4f, 0x4f, 0xc2, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x4c, 0x8f, 0x4d, 0x6e, 0xea, 0x30,
0x18, 0xc6, 0x1d, 0x8c, 0x01, 0x2f, 0x04, 0x97, 0x5e, 0x6c, 0xb8, 0x48, 0x38, 0x71, 0xea, 0x0c, 0x14, 0x85, 0x5f, 0x20, 0x24, 0x70, 0xe1, 0xd1, 0xd4, 0x93, 0x5a, 0x4c, 0x8a, 0x18, 0x31, 0x72,
0xc6, 0x0f, 0x80, 0xa1, 0x51, 0x23, 0x19, 0xa4, 0x8c, 0x98, 0x78, 0x21, 0x25, 0x16, 0x58, 0x60, 0x2a, 0xaa, 0x2e, 0x00, 0x8a, 0xd5, 0x56, 0x44, 0x01, 0x99, 0xa0, 0x4a, 0x9d, 0x20, 0xa3, 0x1a,
0xed, 0xb2, 0x75, 0x5e, 0xfc, 0x7a, 0x7e, 0x30, 0xd3, 0xee, 0x4f, 0xbc, 0xbd, 0xfb, 0xbd, 0xbf, 0x88, 0x20, 0x71, 0x44, 0x4c, 0xd7, 0xd3, 0xf5, 0x75, 0x15, 0x95, 0x9d, 0x1f, 0x75, 0x76, 0xfd,
0x3d, 0x7d, 0x1f, 0xb8, 0x3b, 0xf3, 0x34, 0x0e, 0x32, 0x71, 0x15, 0x3c, 0x17, 0xc1, 0x59, 0xa9, 0xdd, 0xcf, 0xc7, 0x3e, 0x70, 0x77, 0xe4, 0x59, 0xec, 0x5f, 0xc4, 0x59, 0xf0, 0x5c, 0xf8, 0x47,
0x0b, 0x49, 0x33, 0xa5, 0x15, 0x1a, 0x9a, 0x05, 0xa9, 0x16, 0xe3, 0xfb, 0x93, 0x52, 0xa7, 0xab, 0x29, 0x4f, 0x24, 0xbb, 0x48, 0x25, 0x51, 0x4f, 0x2f, 0x48, 0xb9, 0x18, 0xdc, 0x1f, 0xa4, 0x3c,
0x08, 0xec, 0xee, 0x50, 0x1c, 0x03, 0x1d, 0x27, 0x22, 0xd7, 0x3c, 0x49, 0x4b, 0x7d, 0xfa, 0xdb, 0x9c, 0x85, 0x6f, 0x76, 0xbb, 0xeb, 0xde, 0x57, 0x71, 0x22, 0x72, 0xc5, 0x93, 0xac, 0xd0, 0x47,
0x02, 0xf7, 0x55, 0xa9, 0x0b, 0x42, 0xe0, 0x4a, 0x9e, 0x08, 0xec, 0x4c, 0x9c, 0x59, 0x9f, 0xd9, 0x3f, 0x0d, 0xb0, 0x5f, 0xa5, 0x3c, 0x21, 0x04, 0x76, 0xca, 0x13, 0x81, 0xad, 0xa1, 0x35, 0xee,
0xd9, 0xb0, 0x4b, 0x2c, 0xbf, 0x70, 0xab, 0x64, 0x66, 0x36, 0x2c, 0xe5, 0xfa, 0x8c, 0xdb, 0x25, 0x30, 0x33, 0x6b, 0x76, 0x8a, 0xd3, 0x4f, 0xdc, 0x28, 0x98, 0x9e, 0x35, 0xcb, 0xb8, 0x3a, 0xe2,
0x33, 0x33, 0x1a, 0x43, 0x2f, 0xe1, 0x32, 0x3e, 0x8a, 0x5c, 0x63, 0xd7, 0xf2, 0xe6, 0x1b, 0x3d, 0x66, 0xc1, 0xf4, 0x8c, 0x06, 0xd0, 0x4e, 0x78, 0x1a, 0xef, 0x45, 0xae, 0xb0, 0x6d, 0x78, 0x7d,
0x80, 0x27, 0xbe, 0x85, 0xd4, 0x39, 0xee, 0x4c, 0xda, 0xb3, 0xd1, 0x1c, 0x93, 0xff, 0x07, 0x12, 0x46, 0x0f, 0xe0, 0x88, 0x2f, 0x91, 0xaa, 0x1c, 0xb7, 0x86, 0xcd, 0x71, 0x7f, 0x82, 0xc9, 0xdf,
0xf3, 0x36, 0xa1, 0x46, 0x60, 0x95, 0x87, 0x9e, 0xa0, 0x77, 0xe5, 0xb9, 0xde, 0x67, 0x85, 0xc4, 0x0f, 0x12, 0xfd, 0x36, 0xa1, 0x5a, 0x60, 0xa5, 0x87, 0x9e, 0xa0, 0x7d, 0xe6, 0xb9, 0xda, 0x5e,
0xde, 0xc4, 0x99, 0x0d, 0xe6, 0x63, 0x52, 0xd6, 0x20, 0x75, 0x0d, 0x12, 0xd5, 0x35, 0x58, 0xd7, 0xae, 0x29, 0x76, 0x86, 0xd6, 0xb8, 0x3b, 0x19, 0x90, 0xa2, 0x06, 0xa9, 0x6a, 0x90, 0xa8, 0xaa,
0xb8, 0xac, 0x90, 0xd3, 0x1f, 0xe8, 0xd8, 0x1c, 0x34, 0x80, 0xee, 0x2e, 0x7c, 0x0f, 0xd7, 0x1f, 0xc1, 0x5c, 0xed, 0xb2, 0x6b, 0x3a, 0xfa, 0xb6, 0xa0, 0x65, 0x82, 0x50, 0x17, 0xdc, 0x4d, 0xb8,
0xa1, 0x7f, 0x83, 0x6e, 0x61, 0xb0, 0x61, 0x74, 0xff, 0x16, 0x6e, 0xa3, 0xc5, 0x6a, 0xe5, 0x3b, 0x08, 0x97, 0xef, 0xa1, 0xf7, 0x0f, 0xdd, 0x40, 0x77, 0xc5, 0xe8, 0xf6, 0x2d, 0x5c, 0x47, 0xd3,
0xc8, 0x87, 0xe1, 0x66, 0xbd, 0x8d, 0x1a, 0xd2, 0x42, 0x23, 0x00, 0xa3, 0x2c, 0xe9, 0x8a, 0x46, 0x20, 0xf0, 0x2c, 0xe4, 0x41, 0x6f, 0xb5, 0x5c, 0x47, 0x35, 0x69, 0xa0, 0x3e, 0x80, 0x56, 0xe6,
0xd4, 0x6f, 0xdb, 0x5f, 0x8c, 0x51, 0x01, 0xb7, 0xce, 0xd8, 0x6d, 0x5e, 0xd8, 0x62, 0x49, 0xfd, 0x34, 0xa0, 0x11, 0xf5, 0x9a, 0xe6, 0x8a, 0x36, 0x4a, 0x60, 0x57, 0x19, 0x9b, 0xd5, 0x0b, 0x9b,
0x4e, 0x93, 0x51, 0x13, 0xef, 0xb9, 0xff, 0xd9, 0xad, 0x1a, 0x1d, 0x3c, 0x7b, 0xe4, 0xe3, 0x5f, 0xce, 0xa9, 0xd7, 0xaa, 0x33, 0x2a, 0xe2, 0x18, 0xc2, 0xe8, 0x96, 0x2d, 0x83, 0x60, 0x36, 0x7d,
0x00, 0x00, 0x00, 0xff, 0xff, 0x16, 0x64, 0x61, 0x76, 0xa2, 0x01, 0x00, 0x00, 0x5e, 0x78, 0x2e, 0xba, 0x85, 0xff, 0xc6, 0xa9, 0x51, 0x7b, 0xd6, 0xf9, 0x70, 0xcb, 0xde, 0x3b,
0xc7, 0x54, 0x79, 0xfc, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x2e, 0x6f, 0xbd, 0xc8, 0x01, 0x00,
0x00,
} }
...@@ -18,6 +18,8 @@ It has these top-level messages: ...@@ -18,6 +18,8 @@ It has these top-level messages:
GetReleaseContentResponse GetReleaseContentResponse
UpdateReleaseRequest UpdateReleaseRequest
UpdateReleaseResponse UpdateReleaseResponse
RollbackReleaseRequest
RollbackReleaseResponse
InstallReleaseRequest InstallReleaseRequest
InstallReleaseResponse InstallReleaseResponse
UninstallReleaseRequest UninstallReleaseRequest
...@@ -280,6 +282,37 @@ func (m *UpdateReleaseResponse) GetRelease() *hapi_release3.Release { ...@@ -280,6 +282,37 @@ func (m *UpdateReleaseResponse) GetRelease() *hapi_release3.Release {
return nil return nil
} }
type RollbackReleaseRequest struct {
// The name of the release
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
// dry_run, if true, will run through the release logic but no create
DryRun bool `protobuf:"varint,2,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"`
// DisableHooks causes the server to skip running any hooks for the rollback
DisableHooks bool `protobuf:"varint,3,opt,name=disable_hooks,json=disableHooks" json:"disable_hooks,omitempty"`
}
func (m *RollbackReleaseRequest) Reset() { *m = RollbackReleaseRequest{} }
func (m *RollbackReleaseRequest) String() string { return proto.CompactTextString(m) }
func (*RollbackReleaseRequest) ProtoMessage() {}
func (*RollbackReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
// RollbackReleaseResponse is the response to an update request.
type RollbackReleaseResponse struct {
Release *hapi_release3.Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"`
}
func (m *RollbackReleaseResponse) Reset() { *m = RollbackReleaseResponse{} }
func (m *RollbackReleaseResponse) String() string { return proto.CompactTextString(m) }
func (*RollbackReleaseResponse) ProtoMessage() {}
func (*RollbackReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
func (m *RollbackReleaseResponse) GetRelease() *hapi_release3.Release {
if m != nil {
return m.Release
}
return nil
}
// InstallReleaseRequest is the request for an installation of a chart. // InstallReleaseRequest is the request for an installation of a chart.
type InstallReleaseRequest struct { type InstallReleaseRequest struct {
// Chart is the protobuf representation of a chart. // Chart is the protobuf representation of a chart.
...@@ -305,7 +338,7 @@ type InstallReleaseRequest struct { ...@@ -305,7 +338,7 @@ type InstallReleaseRequest struct {
func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} } func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} }
func (m *InstallReleaseRequest) String() string { return proto.CompactTextString(m) } func (m *InstallReleaseRequest) String() string { return proto.CompactTextString(m) }
func (*InstallReleaseRequest) ProtoMessage() {} func (*InstallReleaseRequest) ProtoMessage() {}
func (*InstallReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } func (*InstallReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
func (m *InstallReleaseRequest) GetChart() *hapi_chart3.Chart { func (m *InstallReleaseRequest) GetChart() *hapi_chart3.Chart {
if m != nil { if m != nil {
...@@ -329,7 +362,7 @@ type InstallReleaseResponse struct { ...@@ -329,7 +362,7 @@ type InstallReleaseResponse struct {
func (m *InstallReleaseResponse) Reset() { *m = InstallReleaseResponse{} } func (m *InstallReleaseResponse) Reset() { *m = InstallReleaseResponse{} }
func (m *InstallReleaseResponse) String() string { return proto.CompactTextString(m) } func (m *InstallReleaseResponse) String() string { return proto.CompactTextString(m) }
func (*InstallReleaseResponse) ProtoMessage() {} func (*InstallReleaseResponse) ProtoMessage() {}
func (*InstallReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } func (*InstallReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
func (m *InstallReleaseResponse) GetRelease() *hapi_release3.Release { func (m *InstallReleaseResponse) GetRelease() *hapi_release3.Release {
if m != nil { if m != nil {
...@@ -351,7 +384,7 @@ type UninstallReleaseRequest struct { ...@@ -351,7 +384,7 @@ type UninstallReleaseRequest struct {
func (m *UninstallReleaseRequest) Reset() { *m = UninstallReleaseRequest{} } func (m *UninstallReleaseRequest) Reset() { *m = UninstallReleaseRequest{} }
func (m *UninstallReleaseRequest) String() string { return proto.CompactTextString(m) } func (m *UninstallReleaseRequest) String() string { return proto.CompactTextString(m) }
func (*UninstallReleaseRequest) ProtoMessage() {} func (*UninstallReleaseRequest) ProtoMessage() {}
func (*UninstallReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } func (*UninstallReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
// UninstallReleaseResponse represents a successful response to an uninstall request. // UninstallReleaseResponse represents a successful response to an uninstall request.
type UninstallReleaseResponse struct { type UninstallReleaseResponse struct {
...@@ -362,7 +395,7 @@ type UninstallReleaseResponse struct { ...@@ -362,7 +395,7 @@ type UninstallReleaseResponse struct {
func (m *UninstallReleaseResponse) Reset() { *m = UninstallReleaseResponse{} } func (m *UninstallReleaseResponse) Reset() { *m = UninstallReleaseResponse{} }
func (m *UninstallReleaseResponse) String() string { return proto.CompactTextString(m) } func (m *UninstallReleaseResponse) String() string { return proto.CompactTextString(m) }
func (*UninstallReleaseResponse) ProtoMessage() {} func (*UninstallReleaseResponse) ProtoMessage() {}
func (*UninstallReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } func (*UninstallReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
func (m *UninstallReleaseResponse) GetRelease() *hapi_release3.Release { func (m *UninstallReleaseResponse) GetRelease() *hapi_release3.Release {
if m != nil { if m != nil {
...@@ -378,7 +411,7 @@ type GetVersionRequest struct { ...@@ -378,7 +411,7 @@ type GetVersionRequest struct {
func (m *GetVersionRequest) Reset() { *m = GetVersionRequest{} } func (m *GetVersionRequest) Reset() { *m = GetVersionRequest{} }
func (m *GetVersionRequest) String() string { return proto.CompactTextString(m) } func (m *GetVersionRequest) String() string { return proto.CompactTextString(m) }
func (*GetVersionRequest) ProtoMessage() {} func (*GetVersionRequest) ProtoMessage() {}
func (*GetVersionRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } func (*GetVersionRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} }
type GetVersionResponse struct { type GetVersionResponse struct {
Version *hapi_version.Version `protobuf:"bytes,1,opt,name=Version" json:"Version,omitempty"` Version *hapi_version.Version `protobuf:"bytes,1,opt,name=Version" json:"Version,omitempty"`
...@@ -387,7 +420,7 @@ type GetVersionResponse struct { ...@@ -387,7 +420,7 @@ type GetVersionResponse struct {
func (m *GetVersionResponse) Reset() { *m = GetVersionResponse{} } func (m *GetVersionResponse) Reset() { *m = GetVersionResponse{} }
func (m *GetVersionResponse) String() string { return proto.CompactTextString(m) } func (m *GetVersionResponse) String() string { return proto.CompactTextString(m) }
func (*GetVersionResponse) ProtoMessage() {} func (*GetVersionResponse) ProtoMessage() {}
func (*GetVersionResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } func (*GetVersionResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} }
func (m *GetVersionResponse) GetVersion() *hapi_version.Version { func (m *GetVersionResponse) GetVersion() *hapi_version.Version {
if m != nil { if m != nil {
...@@ -406,6 +439,8 @@ func init() { ...@@ -406,6 +439,8 @@ func init() {
proto.RegisterType((*GetReleaseContentResponse)(nil), "hapi.services.tiller.GetReleaseContentResponse") proto.RegisterType((*GetReleaseContentResponse)(nil), "hapi.services.tiller.GetReleaseContentResponse")
proto.RegisterType((*UpdateReleaseRequest)(nil), "hapi.services.tiller.UpdateReleaseRequest") proto.RegisterType((*UpdateReleaseRequest)(nil), "hapi.services.tiller.UpdateReleaseRequest")
proto.RegisterType((*UpdateReleaseResponse)(nil), "hapi.services.tiller.UpdateReleaseResponse") proto.RegisterType((*UpdateReleaseResponse)(nil), "hapi.services.tiller.UpdateReleaseResponse")
proto.RegisterType((*RollbackReleaseRequest)(nil), "hapi.services.tiller.RollbackReleaseRequest")
proto.RegisterType((*RollbackReleaseResponse)(nil), "hapi.services.tiller.RollbackReleaseResponse")
proto.RegisterType((*InstallReleaseRequest)(nil), "hapi.services.tiller.InstallReleaseRequest") proto.RegisterType((*InstallReleaseRequest)(nil), "hapi.services.tiller.InstallReleaseRequest")
proto.RegisterType((*InstallReleaseResponse)(nil), "hapi.services.tiller.InstallReleaseResponse") proto.RegisterType((*InstallReleaseResponse)(nil), "hapi.services.tiller.InstallReleaseResponse")
proto.RegisterType((*UninstallReleaseRequest)(nil), "hapi.services.tiller.UninstallReleaseRequest") proto.RegisterType((*UninstallReleaseRequest)(nil), "hapi.services.tiller.UninstallReleaseRequest")
...@@ -444,6 +479,8 @@ type ReleaseServiceClient interface { ...@@ -444,6 +479,8 @@ type ReleaseServiceClient interface {
UninstallRelease(ctx context.Context, in *UninstallReleaseRequest, opts ...grpc.CallOption) (*UninstallReleaseResponse, error) UninstallRelease(ctx context.Context, in *UninstallReleaseRequest, opts ...grpc.CallOption) (*UninstallReleaseResponse, error)
// GetVersion returns the current version of the server. // GetVersion returns the current version of the server.
GetVersion(ctx context.Context, in *GetVersionRequest, opts ...grpc.CallOption) (*GetVersionResponse, error) GetVersion(ctx context.Context, in *GetVersionRequest, opts ...grpc.CallOption) (*GetVersionResponse, error)
// RollbackRelease rolls back a release to a previous version.
RollbackRelease(ctx context.Context, in *RollbackReleaseRequest, opts ...grpc.CallOption) (*RollbackReleaseResponse, error)
} }
type releaseServiceClient struct { type releaseServiceClient struct {
...@@ -540,6 +577,15 @@ func (c *releaseServiceClient) GetVersion(ctx context.Context, in *GetVersionReq ...@@ -540,6 +577,15 @@ func (c *releaseServiceClient) GetVersion(ctx context.Context, in *GetVersionReq
return out, nil return out, nil
} }
func (c *releaseServiceClient) RollbackRelease(ctx context.Context, in *RollbackReleaseRequest, opts ...grpc.CallOption) (*RollbackReleaseResponse, error) {
out := new(RollbackReleaseResponse)
err := grpc.Invoke(ctx, "/hapi.services.tiller.ReleaseService/RollbackRelease", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for ReleaseService service // Server API for ReleaseService service
type ReleaseServiceServer interface { type ReleaseServiceServer interface {
...@@ -560,6 +606,8 @@ type ReleaseServiceServer interface { ...@@ -560,6 +606,8 @@ type ReleaseServiceServer interface {
UninstallRelease(context.Context, *UninstallReleaseRequest) (*UninstallReleaseResponse, error) UninstallRelease(context.Context, *UninstallReleaseRequest) (*UninstallReleaseResponse, error)
// GetVersion returns the current version of the server. // GetVersion returns the current version of the server.
GetVersion(context.Context, *GetVersionRequest) (*GetVersionResponse, error) GetVersion(context.Context, *GetVersionRequest) (*GetVersionResponse, error)
// RollbackRelease rolls back a release to a previous version.
RollbackRelease(context.Context, *RollbackReleaseRequest) (*RollbackReleaseResponse, error)
} }
func RegisterReleaseServiceServer(s *grpc.Server, srv ReleaseServiceServer) { func RegisterReleaseServiceServer(s *grpc.Server, srv ReleaseServiceServer) {
...@@ -695,6 +743,24 @@ func _ReleaseService_GetVersion_Handler(srv interface{}, ctx context.Context, de ...@@ -695,6 +743,24 @@ func _ReleaseService_GetVersion_Handler(srv interface{}, ctx context.Context, de
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _ReleaseService_RollbackRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RollbackReleaseRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ReleaseServiceServer).RollbackRelease(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/hapi.services.tiller.ReleaseService/RollbackRelease",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ReleaseServiceServer).RollbackRelease(ctx, req.(*RollbackReleaseRequest))
}
return interceptor(ctx, in, info, handler)
}
var _ReleaseService_serviceDesc = grpc.ServiceDesc{ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
ServiceName: "hapi.services.tiller.ReleaseService", ServiceName: "hapi.services.tiller.ReleaseService",
HandlerType: (*ReleaseServiceServer)(nil), HandlerType: (*ReleaseServiceServer)(nil),
...@@ -723,6 +789,10 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{ ...@@ -723,6 +789,10 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
MethodName: "GetVersion", MethodName: "GetVersion",
Handler: _ReleaseService_GetVersion_Handler, Handler: _ReleaseService_GetVersion_Handler,
}, },
{
MethodName: "RollbackRelease",
Handler: _ReleaseService_RollbackRelease_Handler,
},
}, },
Streams: []grpc.StreamDesc{ Streams: []grpc.StreamDesc{
{ {
...@@ -737,62 +807,64 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{ ...@@ -737,62 +807,64 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) } func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 899 bytes of a gzipped FileDescriptorProto // 944 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x6e, 0xe3, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x6e, 0xe3, 0x44,
0x14, 0xae, 0xf3, 0xe3, 0x24, 0xa7, 0x3f, 0x4a, 0x67, 0xd3, 0xd6, 0xb5, 0x00, 0x45, 0x46, 0xb0, 0x14, 0xae, 0xf3, 0x9f, 0xd3, 0x1f, 0xd2, 0xb3, 0x69, 0xe3, 0x5a, 0x80, 0x22, 0x23, 0xd8, 0xb0,
0x61, 0x81, 0x14, 0xc2, 0x2d, 0x42, 0xea, 0x66, 0xa3, 0xb6, 0xda, 0x92, 0x95, 0x26, 0x14, 0x24, 0xb0, 0x29, 0x84, 0x5b, 0x84, 0xd4, 0xcd, 0x46, 0x6d, 0xd9, 0x92, 0x95, 0x26, 0x14, 0x24, 0x2e,
0x2e, 0x88, 0xdc, 0x64, 0xb2, 0x35, 0x38, 0x9e, 0x30, 0x33, 0xae, 0xe8, 0x23, 0xf0, 0x0c, 0xdc, 0x88, 0xdc, 0x64, 0xb2, 0xf5, 0xae, 0xe3, 0x09, 0x9e, 0x49, 0x45, 0x1f, 0x81, 0x0b, 0x5e, 0x82,
0xf1, 0x1e, 0x3c, 0x19, 0x37, 0xc8, 0xf3, 0xe3, 0xc6, 0xa9, 0xcd, 0x7a, 0x73, 0x63, 0x7b, 0xe6, 0xf7, 0xe0, 0xc9, 0xb8, 0x41, 0x9e, 0xf1, 0xb8, 0x71, 0x62, 0x6f, 0xbd, 0xb9, 0x89, 0x3d, 0x73,
0x7c, 0xf3, 0x9d, 0x73, 0xbe, 0x99, 0x73, 0xc6, 0xe0, 0xde, 0xf9, 0xab, 0xe0, 0x8c, 0x13, 0x76, 0x3e, 0x7f, 0xe7, 0x9b, 0xef, 0xcc, 0x9c, 0x09, 0x58, 0xb7, 0xce, 0xc2, 0x3d, 0xe5, 0x34, 0xb8,
0x1f, 0xcc, 0x08, 0x3f, 0x13, 0x41, 0x18, 0x12, 0xd6, 0x5f, 0x31, 0x2a, 0x28, 0xea, 0x24, 0xb6, 0x73, 0x27, 0x94, 0x9f, 0x0a, 0xd7, 0xf3, 0x68, 0xd0, 0x5d, 0x04, 0x4c, 0x30, 0x6c, 0x86, 0xb1,
0xbe, 0xb1, 0xf5, 0x95, 0xcd, 0x3d, 0x96, 0x2b, 0x66, 0x77, 0x3e, 0x13, 0xea, 0xa9, 0xd0, 0xee, 0xae, 0x8e, 0x75, 0x55, 0xcc, 0x3a, 0x96, 0x5f, 0x4c, 0x6e, 0x9d, 0x40, 0xa8, 0x5f, 0x85, 0xb6,
0xc9, 0xfa, 0x3c, 0x8d, 0x16, 0xc1, 0x5b, 0x6d, 0x50, 0x2e, 0x18, 0x09, 0x89, 0xcf, 0x89, 0x79, 0x5a, 0xab, 0xf3, 0xcc, 0x9f, 0xb9, 0x6f, 0xa2, 0x80, 0x4a, 0x11, 0x50, 0x8f, 0x3a, 0x9c, 0xea,
0x67, 0x16, 0x19, 0x5b, 0x10, 0x2d, 0xa8, 0x36, 0x9c, 0x66, 0x0c, 0x5c, 0xf8, 0x22, 0xe6, 0x19, 0x67, 0xe2, 0x23, 0x1d, 0x73, 0xfd, 0x19, 0x8b, 0x02, 0x27, 0x89, 0x00, 0x17, 0x8e, 0x58, 0xf2,
0xbe, 0x7b, 0xc2, 0x78, 0x40, 0x23, 0xf3, 0x56, 0x36, 0xef, 0xef, 0x0a, 0x3c, 0xbb, 0x0e, 0xb8, 0x04, 0xdf, 0x1d, 0x0d, 0xb8, 0xcb, 0x7c, 0xfd, 0x54, 0x31, 0xfb, 0x9f, 0x02, 0x3c, 0xb9, 0x72,
0xc0, 0x6a, 0x21, 0xc7, 0xe4, 0xf7, 0x98, 0x70, 0x81, 0x3a, 0x50, 0x0f, 0x83, 0x65, 0x20, 0x1c, 0xb9, 0x20, 0xea, 0x43, 0x4e, 0xe8, 0x1f, 0x4b, 0xca, 0x05, 0x36, 0xa1, 0xec, 0xb9, 0x73, 0x57,
0xab, 0x6b, 0xf5, 0xaa, 0x58, 0x0d, 0xd0, 0x31, 0xd8, 0x74, 0xb1, 0xe0, 0x44, 0x38, 0x95, 0xae, 0x98, 0x46, 0xdb, 0xe8, 0x14, 0x89, 0x1a, 0xe0, 0x31, 0x54, 0xd8, 0x6c, 0xc6, 0xa9, 0x30, 0x0b,
0xd5, 0x6b, 0x61, 0x3d, 0x42, 0xdf, 0x41, 0x83, 0x53, 0x26, 0xa6, 0xb7, 0x0f, 0x4e, 0xb5, 0x6b, 0x6d, 0xa3, 0x53, 0x27, 0xd1, 0x08, 0x7f, 0x80, 0x2a, 0x67, 0x81, 0x18, 0xdf, 0xdc, 0x9b, 0xc5,
0xf5, 0x0e, 0x06, 0x9f, 0xf4, 0xf3, 0xa4, 0xe8, 0x27, 0x9e, 0x26, 0x94, 0x89, 0x7e, 0xf2, 0x78, 0xb6, 0xd1, 0x39, 0xe8, 0x7d, 0xde, 0x4d, 0xb3, 0xa2, 0x1b, 0x66, 0x1a, 0xb1, 0x40, 0x74, 0xc3,
0xf9, 0x80, 0x6d, 0x2e, 0xdf, 0x09, 0xef, 0x22, 0x08, 0x05, 0x61, 0x4e, 0x4d, 0xf1, 0xaa, 0x11, 0x9f, 0x17, 0xf7, 0xa4, 0xc2, 0xe5, 0x33, 0xe4, 0x9d, 0xb9, 0x9e, 0xa0, 0x81, 0x59, 0x52, 0xbc,
0xba, 0x00, 0x90, 0xbc, 0x94, 0xcd, 0x09, 0x73, 0xea, 0x92, 0xba, 0x57, 0x82, 0xfa, 0x4d, 0x82, 0x6a, 0x84, 0xe7, 0x00, 0x92, 0x97, 0x05, 0x53, 0x1a, 0x98, 0x65, 0x49, 0xdd, 0xc9, 0x41, 0xfd,
0xc7, 0x2d, 0x6e, 0x3e, 0xd1, 0xb7, 0xb0, 0xa7, 0x24, 0x99, 0xce, 0xe8, 0x9c, 0x70, 0xc7, 0xee, 0x3a, 0xc4, 0x93, 0x3a, 0xd7, 0xaf, 0xf8, 0x3d, 0xec, 0x29, 0x4b, 0xc6, 0x13, 0x36, 0xa5, 0xdc,
0x56, 0x7b, 0x07, 0x83, 0x53, 0x45, 0x65, 0x14, 0x9e, 0x28, 0xd1, 0x86, 0x74, 0x4e, 0xf0, 0xae, 0xac, 0xb4, 0x8b, 0x9d, 0x83, 0xde, 0x89, 0xa2, 0xd2, 0x0e, 0x8f, 0x94, 0x69, 0x7d, 0x36, 0xa5,
0x82, 0x27, 0xdf, 0xdc, 0xfb, 0x05, 0x9a, 0x86, 0xde, 0x1b, 0x80, 0xad, 0x82, 0x47, 0xbb, 0xd0, 0x64, 0x57, 0xc1, 0xc3, 0x77, 0x6e, 0xff, 0x0e, 0x35, 0x4d, 0x6f, 0xf7, 0xa0, 0xa2, 0xc4, 0xe3,
0xb8, 0x19, 0xbf, 0x1e, 0xbf, 0xf9, 0x69, 0xdc, 0xde, 0x41, 0x4d, 0xa8, 0x8d, 0xcf, 0xbf, 0x1f, 0x2e, 0x54, 0xaf, 0x87, 0xaf, 0x86, 0xaf, 0x7f, 0x1d, 0x36, 0x76, 0xb0, 0x06, 0xa5, 0xe1, 0xd9,
0xb5, 0x2d, 0x74, 0x08, 0xfb, 0xd7, 0xe7, 0x93, 0x1f, 0xa6, 0x78, 0x74, 0x3d, 0x3a, 0x9f, 0x8c, 0x4f, 0x83, 0x86, 0x81, 0x87, 0xb0, 0x7f, 0x75, 0x36, 0xfa, 0x79, 0x4c, 0x06, 0x57, 0x83, 0xb3,
0x5e, 0xb5, 0x2b, 0xde, 0x47, 0xd0, 0x4a, 0xa3, 0x42, 0x0d, 0xa8, 0x9e, 0x4f, 0x86, 0x6a, 0xc9, 0xd1, 0xe0, 0x65, 0xa3, 0x60, 0x7f, 0x0a, 0xf5, 0x58, 0x15, 0x56, 0xa1, 0x78, 0x36, 0xea, 0xab,
0xab, 0xd1, 0x64, 0xd8, 0xb6, 0xbc, 0x3f, 0x2d, 0xe8, 0x64, 0x37, 0x81, 0xaf, 0x68, 0xc4, 0x49, 0x4f, 0x5e, 0x0e, 0x46, 0xfd, 0x86, 0x61, 0xff, 0x65, 0x40, 0x33, 0x59, 0x04, 0xbe, 0x60, 0x3e,
0xb2, 0x0b, 0x33, 0x1a, 0x47, 0xe9, 0x2e, 0xc8, 0x01, 0x42, 0x50, 0x8b, 0xc8, 0x1f, 0x66, 0x0f, 0xa7, 0x61, 0x15, 0x26, 0x6c, 0xe9, 0xc7, 0x55, 0x90, 0x03, 0x44, 0x28, 0xf9, 0xf4, 0x4f, 0x5d,
0xe4, 0x77, 0x82, 0x14, 0x54, 0xf8, 0xa1, 0xd4, 0xbf, 0x8a, 0xd5, 0x00, 0x7d, 0x0d, 0x4d, 0x9d, 0x03, 0xf9, 0x1e, 0x22, 0x05, 0x13, 0x8e, 0x27, 0xfd, 0x2f, 0x12, 0x35, 0xc0, 0x6f, 0xa1, 0x16,
0x1c, 0x77, 0x6a, 0xdd, 0x6a, 0x6f, 0x77, 0x70, 0x94, 0x4d, 0x59, 0x7b, 0xc4, 0x29, 0xcc, 0xbb, 0x2d, 0x8e, 0x9b, 0xa5, 0x76, 0xb1, 0xb3, 0xdb, 0x3b, 0x4a, 0x2e, 0x39, 0xca, 0x48, 0x62, 0x98,
0x80, 0x93, 0x0b, 0x62, 0x22, 0x51, 0x8a, 0x98, 0x33, 0x91, 0xf8, 0xf5, 0x97, 0x44, 0x06, 0x93, 0x7d, 0x0e, 0xad, 0x73, 0xaa, 0x95, 0x28, 0x47, 0xf4, 0x9e, 0x08, 0xf3, 0x3a, 0x73, 0x2a, 0xc5,
0xf8, 0xf5, 0x97, 0x04, 0x39, 0xd0, 0xd0, 0x07, 0x4a, 0x86, 0x53, 0xc7, 0x66, 0xe8, 0x09, 0x70, 0x84, 0x79, 0x9d, 0x39, 0x45, 0x13, 0xaa, 0xd1, 0x86, 0x92, 0x72, 0xca, 0x44, 0x0f, 0x6d, 0x01,
0x9e, 0x12, 0xe9, 0xbc, 0xf2, 0x98, 0x3e, 0x85, 0x5a, 0x72, 0x9c, 0x25, 0xcd, 0xee, 0x00, 0x65, 0xe6, 0x26, 0x51, 0xb4, 0xae, 0x34, 0xa6, 0x2f, 0xa0, 0x14, 0x6e, 0x67, 0x49, 0xb3, 0xdb, 0xc3,
0xe3, 0xbc, 0x8a, 0x16, 0x14, 0x4b, 0x3b, 0xfa, 0x00, 0x5a, 0x09, 0x9e, 0xaf, 0xfc, 0x19, 0x91, 0xa4, 0xce, 0x4b, 0x7f, 0xc6, 0x88, 0x8c, 0xe3, 0xc7, 0x50, 0x0f, 0xf1, 0x7c, 0xe1, 0x4c, 0xa8,
0xd9, 0xb6, 0xf0, 0xe3, 0x84, 0x77, 0xb9, 0xee, 0x75, 0x48, 0x23, 0x41, 0x22, 0xb1, 0x5d, 0xfc, 0x5c, 0x6d, 0x9d, 0x3c, 0x4c, 0xd8, 0x17, 0xab, 0x59, 0xfb, 0xcc, 0x17, 0xd4, 0x17, 0xdb, 0xe9,
0xd7, 0x70, 0x9a, 0xc3, 0xa4, 0x13, 0x38, 0x83, 0x86, 0x0e, 0x4d, 0xb2, 0x15, 0xea, 0x6a, 0x50, 0xbf, 0x82, 0x93, 0x14, 0xa6, 0x68, 0x01, 0xa7, 0x50, 0x8d, 0xa4, 0x49, 0xb6, 0x4c, 0x5f, 0x35,
0xde, 0x3f, 0x16, 0x74, 0x6e, 0x56, 0x73, 0x5f, 0x10, 0x63, 0xfa, 0x9f, 0xa0, 0x9e, 0x43, 0x5d, 0xca, 0xfe, 0xd7, 0x80, 0xe6, 0xf5, 0x62, 0xea, 0x08, 0xaa, 0x43, 0xef, 0x11, 0xf5, 0x14, 0xca,
0xb6, 0x05, 0xad, 0xc5, 0xa1, 0xe2, 0x56, 0xbd, 0x63, 0x98, 0x3c, 0xb1, 0xb2, 0xa3, 0x17, 0x60, 0xb2, 0x2d, 0x44, 0x5e, 0x1c, 0x2a, 0x6e, 0xd5, 0x3b, 0xfa, 0xe1, 0x2f, 0x51, 0x71, 0x7c, 0x06,
0xdf, 0xfb, 0x61, 0x4c, 0xb8, 0x14, 0x22, 0x55, 0x4d, 0x23, 0x65, 0x4f, 0xc1, 0x1a, 0x81, 0x4e, 0x95, 0x3b, 0xc7, 0x5b, 0x52, 0x2e, 0x8d, 0x88, 0x5d, 0x8b, 0x90, 0xb2, 0xa7, 0x90, 0x08, 0x81,
0xa0, 0x31, 0x67, 0x0f, 0x53, 0x16, 0x47, 0xb2, 0xc8, 0x9a, 0xd8, 0x9e, 0xb3, 0x07, 0x1c, 0x47, 0x2d, 0xa8, 0x4e, 0x83, 0xfb, 0x71, 0xb0, 0xf4, 0xe5, 0x21, 0xab, 0x91, 0xca, 0x34, 0xb8, 0x27,
0xe8, 0x63, 0xd8, 0x9f, 0x07, 0xdc, 0xbf, 0x0d, 0xc9, 0xf4, 0x8e, 0xd2, 0xdf, 0xb8, 0xac, 0xb3, 0x4b, 0x1f, 0x3f, 0x83, 0xfd, 0xa9, 0xcb, 0x9d, 0x1b, 0x8f, 0x8e, 0x6f, 0x19, 0x7b, 0xc7, 0xe5,
0x26, 0xde, 0xd3, 0x93, 0x97, 0xc9, 0x9c, 0x77, 0x09, 0x47, 0x1b, 0xe1, 0x6f, 0xab, 0xc4, 0xbf, 0x39, 0xab, 0x91, 0xbd, 0x68, 0xf2, 0x22, 0x9c, 0xb3, 0x2f, 0xe0, 0x68, 0x4d, 0xfe, 0xb6, 0x4e,
0x16, 0x1c, 0x5d, 0x45, 0x5c, 0xf8, 0x61, 0xb8, 0x21, 0x45, 0x9a, 0xb6, 0x55, 0x3a, 0xed, 0xca, 0xbc, 0x85, 0x63, 0xc2, 0x3c, 0xef, 0xc6, 0x99, 0xbc, 0xcb, 0x61, 0xc5, 0x8a, 0xea, 0xc2, 0xfb,
0xfb, 0xa4, 0x5d, 0xcd, 0xa4, 0x6d, 0x84, 0xaf, 0xad, 0x09, 0x5f, 0x46, 0x8a, 0xec, 0x01, 0xb4, 0x55, 0x17, 0x53, 0x54, 0xff, 0x08, 0xad, 0x8d, 0x5c, 0xdb, 0xea, 0xfe, 0xcf, 0x80, 0xa3, 0x4b,
0x37, 0x0e, 0x20, 0xfa, 0x10, 0x80, 0x91, 0x98, 0x93, 0xa9, 0x24, 0x6f, 0xc8, 0xf5, 0x2d, 0x39, 0x9f, 0x0b, 0xc7, 0xf3, 0xd6, 0x74, 0xc7, 0xe5, 0x32, 0x72, 0x97, 0xab, 0xf0, 0x21, 0xe5, 0x2a,
0x33, 0xf6, 0x97, 0xc4, 0xbb, 0x82, 0xe3, 0xcd, 0xe4, 0xb7, 0x15, 0xf2, 0x0e, 0x4e, 0x6e, 0xa2, 0x26, 0x16, 0xae, 0x5d, 0x2a, 0xad, 0xb8, 0x94, 0xa7, 0x84, 0xc9, 0x83, 0x53, 0x59, 0x3b, 0x38,
0x20, 0x57, 0xc9, 0xbc, 0x43, 0xf5, 0x24, 0xb7, 0x4a, 0x4e, 0x6e, 0x1d, 0xa8, 0xaf, 0x62, 0xf6, 0xf8, 0x09, 0x40, 0x40, 0x97, 0x9c, 0x8e, 0x25, 0x79, 0x55, 0x7e, 0x5f, 0x97, 0x33, 0x43, 0x67,
0x96, 0x68, 0xad, 0xd4, 0xc0, 0x7b, 0x0d, 0xce, 0x53, 0x4f, 0xdb, 0x86, 0xfd, 0x0c, 0x0e, 0x2f, 0x4e, 0xed, 0x4b, 0x38, 0x5e, 0x5f, 0xfc, 0xb6, 0x46, 0xde, 0x42, 0xeb, 0xda, 0x77, 0x53, 0x9d,
0x88, 0xf8, 0x51, 0x55, 0x99, 0x0e, 0xd8, 0x1b, 0x01, 0x5a, 0x9f, 0x7c, 0xe4, 0xd6, 0x53, 0x59, 0x4c, 0xdb, 0x01, 0x1b, 0x6b, 0x2b, 0xa4, 0xac, 0xad, 0x09, 0xe5, 0xc5, 0x32, 0x78, 0x43, 0x23,
0x6e, 0x73, 0x85, 0x19, 0xbc, 0x41, 0x0d, 0xfe, 0xb2, 0xe1, 0xc0, 0x74, 0x1c, 0x75, 0x3f, 0xa0, 0xaf, 0xd4, 0xc0, 0x7e, 0x05, 0xe6, 0x66, 0xa6, 0x6d, 0x65, 0x3f, 0x81, 0xc3, 0x73, 0x2a, 0x7e,
0x00, 0xf6, 0xd6, 0x5b, 0x2b, 0xfa, 0xac, 0xf8, 0xfa, 0xd8, 0xb8, 0x03, 0xdd, 0x17, 0x65, 0xa0, 0x51, 0xdd, 0x21, 0x12, 0x6c, 0x0f, 0x00, 0x57, 0x27, 0x1f, 0xb8, 0xa3, 0xa9, 0x24, 0xb7, 0xbe,
0x2a, 0x54, 0x6f, 0xe7, 0x2b, 0x0b, 0x71, 0x68, 0x6f, 0x76, 0x3c, 0xf4, 0x65, 0x3e, 0x47, 0x41, 0x7a, 0x35, 0x5e, 0xa3, 0x7a, 0x7f, 0x57, 0xe1, 0x40, 0x77, 0x4a, 0x75, 0xaf, 0xa1, 0x0b, 0x7b,
0x8b, 0x75, 0xfb, 0x65, 0xe1, 0xc6, 0x2d, 0xba, 0x97, 0x72, 0x66, 0xdb, 0x14, 0x7a, 0x27, 0x4d, 0xab, 0x57, 0x02, 0x7e, 0x99, 0x7d, 0xed, 0xad, 0xdd, 0xdd, 0xd6, 0xb3, 0x3c, 0x50, 0x25, 0xd5,
0xb6, 0x33, 0xba, 0x67, 0xa5, 0xf1, 0xa9, 0xdf, 0x5f, 0x61, 0x3f, 0xd3, 0x10, 0x50, 0x81, 0x5a, 0xde, 0xf9, 0xc6, 0x40, 0x0e, 0x8d, 0xf5, 0x4e, 0x8d, 0xcf, 0xd3, 0x39, 0x32, 0xae, 0x06, 0xab,
0x79, 0x4d, 0xcf, 0xfd, 0xbc, 0x14, 0x36, 0xf5, 0xb5, 0x84, 0x83, 0x6c, 0xd1, 0xa0, 0x02, 0x82, 0x9b, 0x17, 0xae, 0xd3, 0xe2, 0x9d, 0xb4, 0x33, 0xd9, 0x5e, 0xf1, 0x51, 0x9a, 0x64, 0x47, 0xb7,
0xdc, 0xbe, 0xe2, 0x7e, 0x51, 0x0e, 0x9c, 0xba, 0xe3, 0xd0, 0xde, 0x3c, 0xee, 0x45, 0xfb, 0x58, 0x4e, 0x73, 0xe3, 0xe3, 0xbc, 0x6f, 0x61, 0x3f, 0xd1, 0xc8, 0x30, 0xc3, 0xad, 0xb4, 0x66, 0x6d,
0x50, 0x80, 0x45, 0xfb, 0x58, 0x54, 0x45, 0xde, 0x0e, 0xf2, 0x01, 0x1e, 0x2b, 0x00, 0x3d, 0x2f, 0x7d, 0x95, 0x0b, 0x1b, 0xe7, 0x9a, 0xc3, 0x41, 0xf2, 0xd0, 0x60, 0x06, 0x41, 0x6a, 0x5f, 0xb1,
0xdc, 0x90, 0x6c, 0xe1, 0xb8, 0xbd, 0x77, 0x03, 0x8d, 0x8b, 0x97, 0xf0, 0x73, 0xd3, 0xe0, 0x6e, 0xbe, 0xce, 0x07, 0x8e, 0xd3, 0x71, 0x68, 0xac, 0x6f, 0xf7, 0xac, 0x3a, 0x66, 0x1c, 0xc0, 0xac,
0x6d, 0xf9, 0xfb, 0xf7, 0xcd, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x0d, 0xc6, 0x82, 0x07, 0xcf, 0x3a, 0x66, 0x9d, 0x22, 0x7b, 0x07, 0x1d, 0x80, 0x87, 0x13, 0x80, 0x4f, 0x33, 0x0b, 0x92, 0x3c,
0x0a, 0x00, 0x00, 0x38, 0x56, 0xe7, 0x71, 0x60, 0x9c, 0x62, 0x01, 0x1f, 0xad, 0x75, 0x71, 0xcc, 0xb0, 0x26, 0xfd,
0x62, 0xb1, 0x9e, 0xe7, 0x44, 0xeb, 0x8c, 0x2f, 0xe0, 0xb7, 0x9a, 0x06, 0xdf, 0x54, 0xe4, 0x1f,
0xe5, 0xef, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x0b, 0x37, 0x7c, 0x73, 0xf9, 0x0b, 0x00, 0x00,
} }
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