diff --git a/pkg/rudder/client.go b/pkg/rudder/client.go deleted file mode 100644 index 219bb010a..000000000 --- a/pkg/rudder/client.go +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright 2017 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 rudder // import "k8s.io/helm/pkg/rudder" - -import ( - "fmt" - - "golang.org/x/net/context" - "google.golang.org/grpc" - - rudderAPI "k8s.io/helm/pkg/proto/hapi/rudder" -) - -// GrpcPort specifies port on which rudder will spawn a server -const ( - GrpcPort = 10001 -) - -var grpcAddr = fmt.Sprintf("127.0.0.1:%d", GrpcPort) - -// InstallRelease calls Rudder InstallRelease method which should create provided release -func InstallRelease(rel *rudderAPI.InstallReleaseRequest) (*rudderAPI.InstallReleaseResponse, error) { - //TODO(mkwiek): parametrize this - conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure()) - if err != nil { - return nil, err - } - - defer conn.Close() - client := rudderAPI.NewReleaseModuleServiceClient(conn) - return client.InstallRelease(context.Background(), rel) -} - -// UpgradeRelease calls Rudder UpgradeRelease method which should perform update -func UpgradeRelease(req *rudderAPI.UpgradeReleaseRequest) (*rudderAPI.UpgradeReleaseResponse, error) { - conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure()) - if err != nil { - return nil, err - } - defer conn.Close() - client := rudderAPI.NewReleaseModuleServiceClient(conn) - return client.UpgradeRelease(context.Background(), req) -} - -// RollbackRelease calls Rudder RollbackRelease method which should perform update -func RollbackRelease(req *rudderAPI.RollbackReleaseRequest) (*rudderAPI.RollbackReleaseResponse, error) { - conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure()) - if err != nil { - return nil, err - } - defer conn.Close() - client := rudderAPI.NewReleaseModuleServiceClient(conn) - return client.RollbackRelease(context.Background(), req) -} - -// ReleaseStatus calls Rudder ReleaseStatus method which should perform update -func ReleaseStatus(req *rudderAPI.ReleaseStatusRequest) (*rudderAPI.ReleaseStatusResponse, error) { - conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure()) - if err != nil { - return nil, err - } - defer conn.Close() - client := rudderAPI.NewReleaseModuleServiceClient(conn) - return client.ReleaseStatus(context.Background(), req) -} - -// DeleteRelease calls Rudder DeleteRelease method which should uninstall provided release -func DeleteRelease(rel *rudderAPI.DeleteReleaseRequest) (*rudderAPI.DeleteReleaseResponse, error) { - conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure()) - if err != nil { - return nil, err - } - - defer conn.Close() - client := rudderAPI.NewReleaseModuleServiceClient(conn) - return client.DeleteRelease(context.Background(), rel) -} diff --git a/pkg/tiller/release_install.go b/pkg/tiller/release_install.go index 8e7fd3acd..c7d2b4060 100644 --- a/pkg/tiller/release_install.go +++ b/pkg/tiller/release_install.go @@ -173,7 +173,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install Timeout: req.Timeout, } s.recordRelease(r, false) - if err := s.ReleaseModule.Update(old, r, updateReq, s.env); err != nil { + if err := s.Update(old, r, updateReq, s.env); err != nil { msg := fmt.Sprintf("Release replace %q failed: %s", r.Name, err) s.Log("warning: %s", msg) old.Info.Status.Code = release.Status_SUPERSEDED @@ -188,7 +188,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install // nothing to replace, create as normal // regular manifests s.recordRelease(r, false) - if err := s.ReleaseModule.Create(r, req, s.env); err != nil { + if err := s.Create(r, req, s.env); err != nil { msg := fmt.Sprintf("Release %q failed: %s", r.Name, err) s.Log("warning: %s", msg) r.Info.Status.Code = release.Status_FAILED diff --git a/pkg/tiller/release_modules.go b/pkg/tiller/release_modules.go deleted file mode 100644 index 876e1ba37..000000000 --- a/pkg/tiller/release_modules.go +++ /dev/null @@ -1,183 +0,0 @@ -/* -Copyright 2017 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" - "errors" - "fmt" - "log" - "strings" - - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" - - "k8s.io/helm/pkg/chartutil" - "k8s.io/helm/pkg/kube" - "k8s.io/helm/pkg/proto/hapi/release" - rudderAPI "k8s.io/helm/pkg/proto/hapi/rudder" - "k8s.io/helm/pkg/proto/hapi/services" - relutil "k8s.io/helm/pkg/releaseutil" - "k8s.io/helm/pkg/rudder" - "k8s.io/helm/pkg/tiller/environment" -) - -// ReleaseModule is an interface that allows ReleaseServer to run operations on release via either local implementation or Rudder service -type ReleaseModule interface { - Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error - Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error - Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error - Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) - Delete(r *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (string, []error) -} - -// LocalReleaseModule is a local implementation of ReleaseModule -type LocalReleaseModule struct { - clientset internalclientset.Interface -} - -// Create creates a release via kubeclient from provided environment -func (m *LocalReleaseModule) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error { - b := bytes.NewBufferString(r.Manifest) - return env.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait) -} - -// Update performs an update from current to target release -func (m *LocalReleaseModule) Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error { - c := bytes.NewBufferString(current.Manifest) - t := bytes.NewBufferString(target.Manifest) - return env.KubeClient.Update(target.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait) -} - -// Rollback performs a rollback from current to target release -func (m *LocalReleaseModule) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error { - c := bytes.NewBufferString(current.Manifest) - t := bytes.NewBufferString(target.Manifest) - return env.KubeClient.Update(target.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait) -} - -// Status returns kubectl-like formatted status of release objects -func (m *LocalReleaseModule) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) { - return env.KubeClient.Get(r.Namespace, bytes.NewBufferString(r.Manifest)) -} - -// Delete deletes the release and returns manifests that were kept in the deletion process -func (m *LocalReleaseModule) Delete(rel *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (kept string, errs []error) { - vs, err := GetVersionSet(m.clientset.Discovery()) - if err != nil { - return rel.Manifest, []error{fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err)} - } - return DeleteRelease(rel, vs, env.KubeClient) -} - -// RemoteReleaseModule is a ReleaseModule which calls Rudder service to operate on a release -type RemoteReleaseModule struct{} - -// Create calls rudder.InstallRelease -func (m *RemoteReleaseModule) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error { - request := &rudderAPI.InstallReleaseRequest{Release: r} - _, err := rudder.InstallRelease(request) - return err -} - -// Update calls rudder.UpgradeRelease -func (m *RemoteReleaseModule) Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error { - upgrade := &rudderAPI.UpgradeReleaseRequest{ - Current: current, - Target: target, - Recreate: req.Recreate, - Timeout: req.Timeout, - Wait: req.Wait, - Force: req.Force, - } - _, err := rudder.UpgradeRelease(upgrade) - return err -} - -// Rollback calls rudder.Rollback -func (m *RemoteReleaseModule) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error { - rollback := &rudderAPI.RollbackReleaseRequest{ - Current: current, - Target: target, - Recreate: req.Recreate, - Timeout: req.Timeout, - Wait: req.Wait, - } - _, err := rudder.RollbackRelease(rollback) - return err -} - -// Status returns status retrieved from rudder.ReleaseStatus -func (m *RemoteReleaseModule) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) { - statusRequest := &rudderAPI.ReleaseStatusRequest{Release: r} - resp, err := rudder.ReleaseStatus(statusRequest) - if resp == nil { - return "", err - } - return resp.Info.Status.Resources, err -} - -// Delete calls rudder.DeleteRelease -func (m *RemoteReleaseModule) Delete(r *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (string, []error) { - deleteRequest := &rudderAPI.DeleteReleaseRequest{Release: r} - resp, err := rudder.DeleteRelease(deleteRequest) - - errs := make([]error, 0) - result := "" - - if err != nil { - errs = append(errs, err) - } - if resp != nil { - result = resp.Release.Manifest - } - return result, errs -} - -// DeleteRelease is a helper that allows Rudder to delete a release without exposing most of Tiller inner functions -func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient environment.KubeClient) (kept string, errs []error) { - manifests := relutil.SplitManifests(rel.Manifest) - _, files, err := sortManifests(manifests, vs, UninstallOrder) - if err != nil { - // We could instead just delete everything in no particular order. - // FIXME: One way to delete at this point would be to try a label-based - // deletion. The problem with this is that we could get a false positive - // and delete something that was not legitimately part of this release. - return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)} - } - - filesToKeep, filesToDelete := filterManifestsToKeep(files) - if len(filesToKeep) > 0 { - kept = summarizeKeptManifests(filesToKeep, kubeClient, rel.Namespace) - } - - errs = []error{} - for _, file := range filesToDelete { - b := bytes.NewBufferString(strings.TrimSpace(file.Content)) - if b.Len() == 0 { - continue - } - if err := kubeClient.Delete(rel.Namespace, b); err != nil { - log.Printf("uninstall: Failed deletion of %q: %s", rel.Name, err) - if err == kube.ErrNoObjectsVisited { - // Rewrite the message from "no objects visited" - err = errors.New("object not found, skipping delete") - } - errs = append(errs, err) - } - } - return kept, errs -} diff --git a/pkg/tiller/release_rollback.go b/pkg/tiller/release_rollback.go index fa3d943f4..279022c25 100644 --- a/pkg/tiller/release_rollback.go +++ b/pkg/tiller/release_rollback.go @@ -128,7 +128,7 @@ func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.R s.Log("rollback hooks disabled for %s", req.Name) } - if err := s.ReleaseModule.Rollback(currentRelease, targetRelease, req, s.env); err != nil { + if err := s.Rollback(currentRelease, targetRelease, req, s.env); err != nil { msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err) s.Log("warning: %s", msg) currentRelease.Info.Status.Code = release.Status_SUPERSEDED diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index 7c4bc62cf..5d768ef32 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -20,6 +20,7 @@ import ( "bytes" "errors" "fmt" + "log" "path" "regexp" "strings" @@ -32,6 +33,7 @@ import ( "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/hooks" + "k8s.io/helm/pkg/kube" "k8s.io/helm/pkg/proto/hapi/chart" "k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/proto/hapi/services" @@ -81,28 +83,17 @@ var ValidName = regexp.MustCompile("^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+ // ReleaseServer implements the server-side gRPC endpoint for the HAPI services. type ReleaseServer struct { - ReleaseModule env *environment.Environment clientset internalclientset.Interface Log func(string, ...interface{}) } // NewReleaseServer creates a new release server. -func NewReleaseServer(env *environment.Environment, clientset internalclientset.Interface, useRemote bool) *ReleaseServer { - var releaseModule ReleaseModule - if useRemote { - releaseModule = &RemoteReleaseModule{} - } else { - releaseModule = &LocalReleaseModule{ - clientset: clientset, - } - } - +func NewReleaseServer(env *environment.Environment, clientset internalclientset.Interface) *ReleaseServer { return &ReleaseServer{ - env: env, - clientset: clientset, - ReleaseModule: releaseModule, - Log: func(_ string, _ ...interface{}) {}, + env: env, + clientset: clientset, + Log: func(_ string, _ ...interface{}) {}, } } @@ -442,3 +433,71 @@ func hookHasDeletePolicy(h *release.Hook, policy string) bool { } return false } + +// Create creates a release via kubeclient from provided environment +func (m *ReleaseServer) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error { + b := bytes.NewBufferString(r.Manifest) + return env.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait) +} + +// Update performs an update from current to target release +func (m *ReleaseServer) Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error { + c := bytes.NewBufferString(current.Manifest) + t := bytes.NewBufferString(target.Manifest) + return env.KubeClient.Update(target.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait) +} + +// Rollback performs a rollback from current to target release +func (m *ReleaseServer) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error { + c := bytes.NewBufferString(current.Manifest) + t := bytes.NewBufferString(target.Manifest) + return env.KubeClient.Update(target.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait) +} + +// Status returns kubectl-like formatted status of release objects +func (m *ReleaseServer) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) { + return env.KubeClient.Get(r.Namespace, bytes.NewBufferString(r.Manifest)) +} + +// Delete deletes the release and returns manifests that were kept in the deletion process +func (m *ReleaseServer) Delete(rel *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (kept string, errs []error) { + vs, err := GetVersionSet(m.clientset.Discovery()) + if err != nil { + return rel.Manifest, []error{fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err)} + } + return DeleteRelease(rel, vs, env.KubeClient) +} + +// DeleteRelease is a helper that allows Rudder to delete a release without exposing most of Tiller inner functions +func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient environment.KubeClient) (kept string, errs []error) { + manifests := relutil.SplitManifests(rel.Manifest) + _, files, err := sortManifests(manifests, vs, UninstallOrder) + if err != nil { + // We could instead just delete everything in no particular order. + // FIXME: One way to delete at this point would be to try a label-based + // deletion. The problem with this is that we could get a false positive + // and delete something that was not legitimately part of this release. + return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)} + } + + filesToKeep, filesToDelete := filterManifestsToKeep(files) + if len(filesToKeep) > 0 { + kept = summarizeKeptManifests(filesToKeep, kubeClient, rel.Namespace) + } + + for _, file := range filesToDelete { + b := bytes.NewBufferString(strings.TrimSpace(file.Content)) + if b.Len() == 0 { + continue + } + if err := kubeClient.Delete(rel.Namespace, b); err != nil { + log.Printf("uninstall: Failed deletion of %q: %s", rel.Name, err) + if err == kube.ErrNoObjectsVisited { + // Rewrite the message from "no objects visited" + err = errors.New("object not found, skipping delete") + } + errs = append(errs, err) + } + } + return kept, errs +} diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index 4b26d2577..8546e8db8 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -95,9 +95,6 @@ data: func rsFixture() *ReleaseServer { clientset := fake.NewSimpleClientset() return &ReleaseServer{ - ReleaseModule: &LocalReleaseModule{ - clientset: clientset, - }, env: MockEnvironment(), clientset: clientset, Log: func(_ string, _ ...interface{}) {}, @@ -531,9 +528,6 @@ func deletePolicyStub(kubeClient *mockHooksKubeClient) *ReleaseServer { clientset := fake.NewSimpleClientset() return &ReleaseServer{ - ReleaseModule: &LocalReleaseModule{ - clientset: clientset, - }, env: e, clientset: clientset, Log: func(_ string, _ ...interface{}) {}, diff --git a/pkg/tiller/release_status.go b/pkg/tiller/release_status.go index e0d75877d..8e7c96b4f 100644 --- a/pkg/tiller/release_status.go +++ b/pkg/tiller/release_status.go @@ -64,7 +64,7 @@ func (s *ReleaseServer) GetReleaseStatus(c ctx.Context, req *services.GetRelease // Ok, we got the status of the release as we had jotted down, now we need to match the // manifest we stashed away with reality from the cluster. - resp, err := s.ReleaseModule.Status(rel, req, s.env) + resp, err := s.Status(rel, req, s.env) if sc == release.Status_DELETED || sc == release.Status_FAILED { // Skip errors if this is already deleted or failed. return statusResp, nil diff --git a/pkg/tiller/release_uninstall.go b/pkg/tiller/release_uninstall.go index 423b6e7ef..0d575dc85 100644 --- a/pkg/tiller/release_uninstall.go +++ b/pkg/tiller/release_uninstall.go @@ -81,7 +81,7 @@ func (s *ReleaseServer) UninstallRelease(c ctx.Context, req *services.UninstallR s.Log("uninstall: Failed to store updated release: %s", err) } - kept, errs := s.ReleaseModule.Delete(rel, req, s.env) + kept, errs := s.Delete(rel, req, s.env) res.Info = kept es := make([]string, 0, len(errs)) diff --git a/pkg/tiller/release_update.go b/pkg/tiller/release_update.go index 6f5d37331..4f59e9aaa 100644 --- a/pkg/tiller/release_update.go +++ b/pkg/tiller/release_update.go @@ -189,7 +189,7 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) ( } // delete manifests from the old release - _, errs := s.ReleaseModule.Delete(oldRelease, nil, s.env) + _, errs := s.Delete(oldRelease, nil, s.env) oldRelease.Info.Status.Code = release.Status_DELETED oldRelease.Info.Description = "Deletion complete" @@ -221,7 +221,7 @@ func (s *ReleaseServer) performUpdateForce(req *services.UpdateReleaseRequest) ( // update new release with next revision number so as to append to the old release's history newRelease.Version = oldRelease.Version + 1 s.recordRelease(newRelease, false) - if err := s.ReleaseModule.Update(oldRelease, newRelease, req, s.env); err != nil { + if err := s.Update(oldRelease, newRelease, req, s.env); err != nil { msg := fmt.Sprintf("Upgrade %q failed: %s", newRelease.Name, err) s.Log("warning: %s", msg) newRelease.Info.Status.Code = release.Status_FAILED @@ -266,7 +266,7 @@ func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.R } else { s.Log("update hooks disabled for %s", req.Name) } - if err := s.ReleaseModule.Update(originalRelease, updatedRelease, req, s.env); err != nil { + if err := s.Update(originalRelease, updatedRelease, req, s.env); err != nil { msg := fmt.Sprintf("Upgrade %q failed: %s", updatedRelease.Name, err) s.Log("warning: %s", msg) updatedRelease.Info.Status.Code = release.Status_FAILED