From c1fcaf09ce3186368c70b33075b12dcbff4a9034 Mon Sep 17 00:00:00 2001 From: Maciej Kwiek Date: Wed, 8 Mar 2017 14:05:45 +0100 Subject: [PATCH] Experimental Rudder implementation This change introduces the concept of Rudders - pluggable modules that Tiller communicates with via grpc, which allow to decouple orchestration logic from Tiller into separate service. This commit consists of simple Rudder implementation which does exactly the same thing as built in Tiller orchestrator - it creates all k8s objects from provided manifest without orchestrating them. --experimental-release flag is introduced to enable this behaviour. This change allows to use the service and tiller outside of the cluster. Following commits will add Rudder to helm deployment. --- _proto/hapi/release/modules.proto | 83 ++++ cmd/rudder/rudder.go | 84 ++++ cmd/tiller/tiller.go | 14 +- pkg/proto/hapi/release/hook.pb.go | 12 + pkg/proto/hapi/release/modules.pb.go | 500 ++++++++++++++++++++++++ pkg/proto/hapi/release/release.pb.go | 6 +- pkg/proto/hapi/release/status.pb.go | 8 +- pkg/proto/hapi/release/test_run.pb.go | 8 +- pkg/proto/hapi/release/test_suite.pb.go | 6 +- pkg/rudder/client.go | 42 ++ pkg/tiller/release_modules.go | 50 +++ pkg/tiller/release_server.go | 18 +- pkg/tiller/release_server_test.go | 5 +- 13 files changed, 809 insertions(+), 27 deletions(-) create mode 100644 _proto/hapi/release/modules.proto create mode 100644 cmd/rudder/rudder.go create mode 100644 pkg/proto/hapi/release/modules.pb.go create mode 100644 pkg/rudder/client.go create mode 100644 pkg/tiller/release_modules.go diff --git a/_proto/hapi/release/modules.proto b/_proto/hapi/release/modules.proto new file mode 100644 index 000000000..4112bda7e --- /dev/null +++ b/_proto/hapi/release/modules.proto @@ -0,0 +1,83 @@ +syntax = "proto3"; + +package hapi.release; + +import "hapi/release/release.proto"; + +option go_package = "release"; + +service ReleaseModuleService { + rpc Version(VersionReleaseRequest) returns (VersionReleaseResponse) { + } + + // InstallRelease requests installation of a chart as a new release. + rpc InstallRelease(InstallReleaseRequest) returns (InstallReleaseResponse) { + } + + // DeleteRelease requests deletion of a named release. + rpc DeleteRelease(DeleteReleaseRequest) returns (DeleteReleaseResponse) { + } + + // RollbackRelease rolls back a release to a previous version. + rpc RollbackRelease(RollbackReleaseRequest) returns (RollbackReleaseResponse) { + } + + // UpgradeRelease updates release content. + rpc UpgradeRelease(UpgradeReleaseRequest) returns (UpgradeReleaseResponse) { + } +} + +message Result { + enum Status { + // No status set + UNKNOWN = 0; + // Operation was successful + SUCCESS = 1; + // Operation had no results (e.g. upgrade identical, rollback to same, delete non-existent) + UNCHANGED = 2; + // Operation failed + ERROR = 3; + } + string info = 1; + repeated string log = 2; +} + +message VersionReleaseRequest { +} + +message VersionReleaseResponse { + string name = 1; // The canonical name of the release module + string version = 2; // The version of the release module +} + +message InstallReleaseRequest { + hapi.release.Release release = 1; +} +message InstallReleaseResponse { + hapi.release.Release release = 1; + Result result = 2; +} + +message DeleteReleaseRequest { + hapi.release.Release release = 1; +} +message DeleteReleaseResponse { + hapi.release.Release release = 1; + Result result = 2; +} + +message UpgradeReleaseRequest{ + hapi.release.Release release = 1; +} +message UpgradeReleaseResponse{ + hapi.release.Release release = 1; + Result result = 2; +} + +message RollbackReleaseRequest{ + hapi.release.Release release = 1; +} +message RollbackReleaseResponse{ + hapi.release.Release release = 1; + Result result = 2; +} diff --git a/cmd/rudder/rudder.go b/cmd/rudder/rudder.go new file mode 100644 index 000000000..55b9f1773 --- /dev/null +++ b/cmd/rudder/rudder.go @@ -0,0 +1,84 @@ +/* +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 main // import "k8s.io/helm/cmd/rudder" + +import ( + "bytes" + "fmt" + "net" + + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/grpclog" + + "k8s.io/helm/pkg/kube" + "k8s.io/helm/pkg/proto/hapi/release" + "k8s.io/helm/pkg/rudder" +) + +var kubeClient = kube.New(nil) + +func main() { + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", rudder.GrpcAddr)) + if err != nil { + grpclog.Fatalf("failed to listen: %v", err) + } + grpcServer := grpc.NewServer() + release.RegisterReleaseModuleServiceServer(grpcServer, &ReleaseModuleServiceServer{}) + + grpclog.Print("Server starting") + grpcServer.Serve(lis) + grpclog.Print("Server started") +} + +// ReleaseModuleServiceServer provides implementation for release.ReleaseModuleServiceServer +type ReleaseModuleServiceServer struct{} + +// Version is not yet implemented +func (r *ReleaseModuleServiceServer) Version(ctx context.Context, in *release.VersionReleaseRequest) (*release.VersionReleaseResponse, error) { + grpclog.Print("version") + return &release.VersionReleaseResponse{}, nil +} + +// InstallRelease creates a release using kubeClient.Create +func (r *ReleaseModuleServiceServer) InstallRelease(ctx context.Context, in *release.InstallReleaseRequest) (*release.InstallReleaseResponse, error) { + grpclog.Print("install") + b := bytes.NewBufferString(in.Release.Manifest) + err := kubeClient.Create(in.Release.Namespace, b, 500, false) + if err != nil { + grpclog.Printf("error when creating release: %s", err) + } + return &release.InstallReleaseResponse{}, err +} + +// DeleteRelease is not implemented +func (r *ReleaseModuleServiceServer) DeleteRelease(ctx context.Context, in *release.DeleteReleaseRequest) (*release.DeleteReleaseResponse, error) { + grpclog.Print("delete") + return nil, nil +} + +// RollbackRelease is not implemented +func (r *ReleaseModuleServiceServer) RollbackRelease(ctx context.Context, in *release.RollbackReleaseRequest) (*release.RollbackReleaseResponse, error) { + grpclog.Print("rollback") + return nil, nil +} + +// UpgradeRelease is not implemented +func (r *ReleaseModuleServiceServer) UpgradeRelease(ctx context.Context, in *release.UpgradeReleaseRequest) (*release.UpgradeReleaseResponse, error) { + grpclog.Print("upgrade") + return nil, nil +} diff --git a/cmd/tiller/tiller.go b/cmd/tiller/tiller.go index 2f193936e..e5f3a33f3 100644 --- a/cmd/tiller/tiller.go +++ b/cmd/tiller/tiller.go @@ -70,11 +70,12 @@ var rootServer *grpc.Server var env = environment.New() var ( - grpcAddr = ":44134" - probeAddr = ":44135" - traceAddr = ":44136" - enableTracing = false - store = storageConfigMap + grpcAddr = ":44134" + probeAddr = ":44135" + traceAddr = ":44136" + enableTracing = false + store = storageConfigMap + remoteReleaseModules = false ) var ( @@ -108,6 +109,7 @@ func main() { p.StringVarP(&grpcAddr, "listen", "l", ":44134", "address:port to listen on") p.StringVar(&store, "storage", storageConfigMap, "storage driver to use. One of 'configmap' or 'memory'") p.BoolVar(&enableTracing, "trace", false, "enable rpc tracing") + p.BoolVar(&remoteReleaseModules, "experimental-release", false, "enable experimental release modules") p.BoolVar(&tlsEnable, "tls", tlsEnableEnvVarDefault(), "enable TLS") p.BoolVar(&tlsVerify, "tls-verify", tlsVerifyEnvVarDefault(), "enable TLS and verify remote certificate") @@ -173,7 +175,7 @@ func start(c *cobra.Command, args []string) { srvErrCh := make(chan error) probeErrCh := make(chan error) go func() { - svc := tiller.NewReleaseServer(env, clientset) + svc := tiller.NewReleaseServer(env, clientset, remoteReleaseModules) services.RegisterReleaseServiceServer(rootServer, svc) if err := rootServer.Serve(lstn); err != nil { srvErrCh <- err diff --git a/pkg/proto/hapi/release/hook.pb.go b/pkg/proto/hapi/release/hook.pb.go index 1724842e3..2b8f0330a 100644 --- a/pkg/proto/hapi/release/hook.pb.go +++ b/pkg/proto/hapi/release/hook.pb.go @@ -8,6 +8,7 @@ Package release is a generated protocol buffer package. It is generated from these files: hapi/release/hook.proto hapi/release/info.proto + hapi/release/modules.proto hapi/release/release.proto hapi/release/status.proto hapi/release/test_run.proto @@ -16,6 +17,17 @@ It is generated from these files: It has these top-level messages: Hook Info + Result + VersionReleaseRequest + VersionReleaseResponse + InstallReleaseRequest + InstallReleaseResponse + DeleteReleaseRequest + DeleteReleaseResponse + UpgradeReleaseRequest + UpgradeReleaseResponse + RollbackReleaseRequest + RollbackReleaseResponse Release Status TestRun diff --git a/pkg/proto/hapi/release/modules.pb.go b/pkg/proto/hapi/release/modules.pb.go new file mode 100644 index 000000000..cfe36e572 --- /dev/null +++ b/pkg/proto/hapi/release/modules.pb.go @@ -0,0 +1,500 @@ +// Code generated by protoc-gen-go. +// source: hapi/release/modules.proto +// DO NOT EDIT! + +package release + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +type Result_Status int32 + +const ( + // No status set + Result_UNKNOWN Result_Status = 0 + // Operation was successful + Result_SUCCESS Result_Status = 1 + // Operation had no results (e.g. upgrade identical, rollback to same, delete non-existent) + Result_UNCHANGED Result_Status = 2 + // Operation failed + Result_ERROR Result_Status = 3 +) + +var Result_Status_name = map[int32]string{ + 0: "UNKNOWN", + 1: "SUCCESS", + 2: "UNCHANGED", + 3: "ERROR", +} +var Result_Status_value = map[string]int32{ + "UNKNOWN": 0, + "SUCCESS": 1, + "UNCHANGED": 2, + "ERROR": 3, +} + +func (x Result_Status) String() string { + return proto.EnumName(Result_Status_name, int32(x)) +} +func (Result_Status) EnumDescriptor() ([]byte, []int) { return fileDescriptor2, []int{0, 0} } + +type Result struct { + Info string `protobuf:"bytes,1,opt,name=info" json:"info,omitempty"` + Log []string `protobuf:"bytes,2,rep,name=log" json:"log,omitempty"` +} + +func (m *Result) Reset() { *m = Result{} } +func (m *Result) String() string { return proto.CompactTextString(m) } +func (*Result) ProtoMessage() {} +func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} } + +type VersionReleaseRequest struct { +} + +func (m *VersionReleaseRequest) Reset() { *m = VersionReleaseRequest{} } +func (m *VersionReleaseRequest) String() string { return proto.CompactTextString(m) } +func (*VersionReleaseRequest) ProtoMessage() {} +func (*VersionReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{1} } + +type VersionReleaseResponse struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` +} + +func (m *VersionReleaseResponse) Reset() { *m = VersionReleaseResponse{} } +func (m *VersionReleaseResponse) String() string { return proto.CompactTextString(m) } +func (*VersionReleaseResponse) ProtoMessage() {} +func (*VersionReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{2} } + +type InstallReleaseRequest struct { + Release *Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` +} + +func (m *InstallReleaseRequest) Reset() { *m = InstallReleaseRequest{} } +func (m *InstallReleaseRequest) String() string { return proto.CompactTextString(m) } +func (*InstallReleaseRequest) ProtoMessage() {} +func (*InstallReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{3} } + +func (m *InstallReleaseRequest) GetRelease() *Release { + if m != nil { + return m.Release + } + return nil +} + +type InstallReleaseResponse struct { + Release *Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` + Result *Result `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"` +} + +func (m *InstallReleaseResponse) Reset() { *m = InstallReleaseResponse{} } +func (m *InstallReleaseResponse) String() string { return proto.CompactTextString(m) } +func (*InstallReleaseResponse) ProtoMessage() {} +func (*InstallReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{4} } + +func (m *InstallReleaseResponse) GetRelease() *Release { + if m != nil { + return m.Release + } + return nil +} + +func (m *InstallReleaseResponse) GetResult() *Result { + if m != nil { + return m.Result + } + return nil +} + +type DeleteReleaseRequest struct { + Release *Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` +} + +func (m *DeleteReleaseRequest) Reset() { *m = DeleteReleaseRequest{} } +func (m *DeleteReleaseRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteReleaseRequest) ProtoMessage() {} +func (*DeleteReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{5} } + +func (m *DeleteReleaseRequest) GetRelease() *Release { + if m != nil { + return m.Release + } + return nil +} + +type DeleteReleaseResponse struct { + Release *Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` + Result *Result `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"` +} + +func (m *DeleteReleaseResponse) Reset() { *m = DeleteReleaseResponse{} } +func (m *DeleteReleaseResponse) String() string { return proto.CompactTextString(m) } +func (*DeleteReleaseResponse) ProtoMessage() {} +func (*DeleteReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{6} } + +func (m *DeleteReleaseResponse) GetRelease() *Release { + if m != nil { + return m.Release + } + return nil +} + +func (m *DeleteReleaseResponse) GetResult() *Result { + if m != nil { + return m.Result + } + return nil +} + +type UpgradeReleaseRequest struct { + Release *Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` +} + +func (m *UpgradeReleaseRequest) Reset() { *m = UpgradeReleaseRequest{} } +func (m *UpgradeReleaseRequest) String() string { return proto.CompactTextString(m) } +func (*UpgradeReleaseRequest) ProtoMessage() {} +func (*UpgradeReleaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{7} } + +func (m *UpgradeReleaseRequest) GetRelease() *Release { + if m != nil { + return m.Release + } + return nil +} + +type UpgradeReleaseResponse struct { + Release *Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` + Result *Result `protobuf:"bytes,2,opt,name=result" json:"result,omitempty"` +} + +func (m *UpgradeReleaseResponse) Reset() { *m = UpgradeReleaseResponse{} } +func (m *UpgradeReleaseResponse) String() string { return proto.CompactTextString(m) } +func (*UpgradeReleaseResponse) ProtoMessage() {} +func (*UpgradeReleaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{8} } + +func (m *UpgradeReleaseResponse) GetRelease() *Release { + if m != nil { + return m.Release + } + return nil +} + +func (m *UpgradeReleaseResponse) GetResult() *Result { + if m != nil { + return m.Result + } + return nil +} + +type RollbackReleaseRequest struct { + Release *Release `protobuf:"bytes,1,opt,name=release" json:"release,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 fileDescriptor2, []int{9} } + +func (m *RollbackReleaseRequest) GetRelease() *Release { + if m != nil { + return m.Release + } + return nil +} + +type RollbackReleaseResponse struct { + Release *Release `protobuf:"bytes,1,opt,name=release" json:"release,omitempty"` + Result *Result `protobuf:"bytes,2,opt,name=result" json:"result,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 fileDescriptor2, []int{10} } + +func (m *RollbackReleaseResponse) GetRelease() *Release { + if m != nil { + return m.Release + } + return nil +} + +func (m *RollbackReleaseResponse) GetResult() *Result { + if m != nil { + return m.Result + } + return nil +} + +func init() { + proto.RegisterType((*Result)(nil), "hapi.release.Result") + proto.RegisterType((*VersionReleaseRequest)(nil), "hapi.release.VersionReleaseRequest") + proto.RegisterType((*VersionReleaseResponse)(nil), "hapi.release.VersionReleaseResponse") + proto.RegisterType((*InstallReleaseRequest)(nil), "hapi.release.InstallReleaseRequest") + proto.RegisterType((*InstallReleaseResponse)(nil), "hapi.release.InstallReleaseResponse") + proto.RegisterType((*DeleteReleaseRequest)(nil), "hapi.release.DeleteReleaseRequest") + proto.RegisterType((*DeleteReleaseResponse)(nil), "hapi.release.DeleteReleaseResponse") + proto.RegisterType((*UpgradeReleaseRequest)(nil), "hapi.release.UpgradeReleaseRequest") + proto.RegisterType((*UpgradeReleaseResponse)(nil), "hapi.release.UpgradeReleaseResponse") + proto.RegisterType((*RollbackReleaseRequest)(nil), "hapi.release.RollbackReleaseRequest") + proto.RegisterType((*RollbackReleaseResponse)(nil), "hapi.release.RollbackReleaseResponse") + proto.RegisterEnum("hapi.release.Result_Status", Result_Status_name, Result_Status_value) +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion3 + +// Client API for ReleaseModuleService service + +type ReleaseModuleServiceClient interface { + Version(ctx context.Context, in *VersionReleaseRequest, opts ...grpc.CallOption) (*VersionReleaseResponse, error) + // InstallRelease requests installation of a chart as a new release. + InstallRelease(ctx context.Context, in *InstallReleaseRequest, opts ...grpc.CallOption) (*InstallReleaseResponse, error) + // DeleteRelease requests deletion of a named release. + DeleteRelease(ctx context.Context, in *DeleteReleaseRequest, opts ...grpc.CallOption) (*DeleteReleaseResponse, error) + // RollbackRelease rolls back a release to a previous version. + RollbackRelease(ctx context.Context, in *RollbackReleaseRequest, opts ...grpc.CallOption) (*RollbackReleaseResponse, error) + // UpgradeRelease updates release content. + UpgradeRelease(ctx context.Context, in *UpgradeReleaseRequest, opts ...grpc.CallOption) (*UpgradeReleaseResponse, error) +} + +type releaseModuleServiceClient struct { + cc *grpc.ClientConn +} + +func NewReleaseModuleServiceClient(cc *grpc.ClientConn) ReleaseModuleServiceClient { + return &releaseModuleServiceClient{cc} +} + +func (c *releaseModuleServiceClient) Version(ctx context.Context, in *VersionReleaseRequest, opts ...grpc.CallOption) (*VersionReleaseResponse, error) { + out := new(VersionReleaseResponse) + err := grpc.Invoke(ctx, "/hapi.release.ReleaseModuleService/Version", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *releaseModuleServiceClient) InstallRelease(ctx context.Context, in *InstallReleaseRequest, opts ...grpc.CallOption) (*InstallReleaseResponse, error) { + out := new(InstallReleaseResponse) + err := grpc.Invoke(ctx, "/hapi.release.ReleaseModuleService/InstallRelease", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *releaseModuleServiceClient) DeleteRelease(ctx context.Context, in *DeleteReleaseRequest, opts ...grpc.CallOption) (*DeleteReleaseResponse, error) { + out := new(DeleteReleaseResponse) + err := grpc.Invoke(ctx, "/hapi.release.ReleaseModuleService/DeleteRelease", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *releaseModuleServiceClient) RollbackRelease(ctx context.Context, in *RollbackReleaseRequest, opts ...grpc.CallOption) (*RollbackReleaseResponse, error) { + out := new(RollbackReleaseResponse) + err := grpc.Invoke(ctx, "/hapi.release.ReleaseModuleService/RollbackRelease", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *releaseModuleServiceClient) UpgradeRelease(ctx context.Context, in *UpgradeReleaseRequest, opts ...grpc.CallOption) (*UpgradeReleaseResponse, error) { + out := new(UpgradeReleaseResponse) + err := grpc.Invoke(ctx, "/hapi.release.ReleaseModuleService/UpgradeRelease", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for ReleaseModuleService service + +type ReleaseModuleServiceServer interface { + Version(context.Context, *VersionReleaseRequest) (*VersionReleaseResponse, error) + // InstallRelease requests installation of a chart as a new release. + InstallRelease(context.Context, *InstallReleaseRequest) (*InstallReleaseResponse, error) + // DeleteRelease requests deletion of a named release. + DeleteRelease(context.Context, *DeleteReleaseRequest) (*DeleteReleaseResponse, error) + // RollbackRelease rolls back a release to a previous version. + RollbackRelease(context.Context, *RollbackReleaseRequest) (*RollbackReleaseResponse, error) + // UpgradeRelease updates release content. + UpgradeRelease(context.Context, *UpgradeReleaseRequest) (*UpgradeReleaseResponse, error) +} + +func RegisterReleaseModuleServiceServer(s *grpc.Server, srv ReleaseModuleServiceServer) { + s.RegisterService(&_ReleaseModuleService_serviceDesc, srv) +} + +func _ReleaseModuleService_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VersionReleaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReleaseModuleServiceServer).Version(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hapi.release.ReleaseModuleService/Version", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReleaseModuleServiceServer).Version(ctx, req.(*VersionReleaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReleaseModuleService_InstallRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InstallReleaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReleaseModuleServiceServer).InstallRelease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hapi.release.ReleaseModuleService/InstallRelease", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReleaseModuleServiceServer).InstallRelease(ctx, req.(*InstallReleaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReleaseModuleService_DeleteRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteReleaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReleaseModuleServiceServer).DeleteRelease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hapi.release.ReleaseModuleService/DeleteRelease", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReleaseModuleServiceServer).DeleteRelease(ctx, req.(*DeleteReleaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReleaseModuleService_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.(ReleaseModuleServiceServer).RollbackRelease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hapi.release.ReleaseModuleService/RollbackRelease", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReleaseModuleServiceServer).RollbackRelease(ctx, req.(*RollbackReleaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ReleaseModuleService_UpgradeRelease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpgradeReleaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ReleaseModuleServiceServer).UpgradeRelease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hapi.release.ReleaseModuleService/UpgradeRelease", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ReleaseModuleServiceServer).UpgradeRelease(ctx, req.(*UpgradeReleaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _ReleaseModuleService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "hapi.release.ReleaseModuleService", + HandlerType: (*ReleaseModuleServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Version", + Handler: _ReleaseModuleService_Version_Handler, + }, + { + MethodName: "InstallRelease", + Handler: _ReleaseModuleService_InstallRelease_Handler, + }, + { + MethodName: "DeleteRelease", + Handler: _ReleaseModuleService_DeleteRelease_Handler, + }, + { + MethodName: "RollbackRelease", + Handler: _ReleaseModuleService_RollbackRelease_Handler, + }, + { + MethodName: "UpgradeRelease", + Handler: _ReleaseModuleService_UpgradeRelease_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: fileDescriptor2, +} + +func init() { proto.RegisterFile("hapi/release/modules.proto", fileDescriptor2) } + +var fileDescriptor2 = []byte{ + // 450 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x54, 0x5d, 0x6b, 0xd4, 0x40, + 0x14, 0xdd, 0x0f, 0xdd, 0x25, 0x77, 0xad, 0x86, 0xcb, 0x66, 0x1b, 0xf2, 0x54, 0xa6, 0x0a, 0x7d, + 0x90, 0x2c, 0xac, 0xaf, 0xbe, 0xe8, 0x76, 0xed, 0x16, 0x31, 0x85, 0x09, 0xa9, 0x50, 0x10, 0x4c, + 0xdb, 0x6b, 0x0d, 0x4e, 0x33, 0x31, 0x93, 0xac, 0xfe, 0x66, 0x7f, 0x85, 0xe4, 0x4b, 0x9a, 0x31, + 0x54, 0x64, 0xcb, 0x3e, 0x65, 0x26, 0xf7, 0xe4, 0xe4, 0x9c, 0x3b, 0xf7, 0x0c, 0x38, 0x5f, 0xc3, + 0x24, 0x9a, 0xa7, 0x24, 0x28, 0x54, 0x34, 0xbf, 0x95, 0xd7, 0xb9, 0x20, 0xe5, 0x26, 0xa9, 0xcc, + 0x24, 0x3e, 0x29, 0x6a, 0x6e, 0x5d, 0x73, 0xda, 0xc8, 0xfa, 0x59, 0x21, 0x99, 0x80, 0x11, 0x27, + 0x95, 0x8b, 0x0c, 0x11, 0x1e, 0x45, 0xf1, 0x17, 0x69, 0xf7, 0x0f, 0xfa, 0x47, 0x06, 0x2f, 0xd7, + 0x68, 0xc2, 0x50, 0xc8, 0x1b, 0x7b, 0x70, 0x30, 0x3c, 0x32, 0x78, 0xb1, 0x64, 0xaf, 0x61, 0xe4, + 0x67, 0x61, 0x96, 0x2b, 0x9c, 0xc0, 0x38, 0xf0, 0xde, 0x7b, 0x67, 0x1f, 0x3d, 0xb3, 0x57, 0x6c, + 0xfc, 0x60, 0xb9, 0x5c, 0xf9, 0xbe, 0xd9, 0xc7, 0x3d, 0x30, 0x02, 0x6f, 0xb9, 0x7e, 0xe3, 0x9d, + 0xac, 0x8e, 0xcd, 0x01, 0x1a, 0xf0, 0x78, 0xc5, 0xf9, 0x19, 0x37, 0x87, 0x6c, 0x1f, 0xac, 0x73, + 0x4a, 0x55, 0x24, 0x63, 0x5e, 0xa9, 0xe0, 0xf4, 0x3d, 0x27, 0x95, 0xb1, 0x77, 0x30, 0xd3, 0x0b, + 0x2a, 0x91, 0xb1, 0xa2, 0x42, 0x56, 0x1c, 0xde, 0x52, 0x23, 0xab, 0x58, 0xa3, 0x0d, 0xe3, 0x4d, + 0x85, 0xb6, 0x07, 0xe5, 0xeb, 0x66, 0xcb, 0xd6, 0x60, 0x9d, 0xc6, 0x2a, 0x0b, 0x85, 0x68, 0xff, + 0x00, 0xe7, 0x30, 0xae, 0x8d, 0x97, 0x4c, 0x93, 0x85, 0xe5, 0xde, 0xed, 0x91, 0xdb, 0xc0, 0x1b, + 0x14, 0xfb, 0x01, 0x33, 0x9d, 0xa9, 0x56, 0xf4, 0xbf, 0x54, 0xf8, 0x12, 0x46, 0x69, 0xd9, 0xe3, + 0x52, 0xed, 0x64, 0x31, 0xd5, 0xf1, 0x45, 0x8d, 0xd7, 0x18, 0x76, 0x02, 0xd3, 0x63, 0x12, 0x94, + 0xd1, 0xb6, 0x0e, 0x36, 0x60, 0x69, 0x44, 0xbb, 0x31, 0xb0, 0x06, 0x2b, 0x48, 0x6e, 0xd2, 0xf0, + 0x9a, 0x1e, 0xe0, 0x0c, 0x74, 0xa6, 0xdd, 0x58, 0x38, 0x85, 0x19, 0x97, 0x42, 0x5c, 0x86, 0x57, + 0xdf, 0xb6, 0xf5, 0xf0, 0x13, 0xf6, 0xff, 0xa2, 0xda, 0x89, 0x89, 0xc5, 0xaf, 0x21, 0x4c, 0x6b, + 0x8a, 0x0f, 0xe5, 0xed, 0xe0, 0x53, 0xba, 0x89, 0xae, 0x08, 0xcf, 0x61, 0x5c, 0x87, 0x0d, 0x0f, + 0xdb, 0x0c, 0x9d, 0xe1, 0x74, 0x9e, 0xdf, 0x0f, 0xaa, 0xdc, 0xb0, 0x1e, 0x7e, 0x82, 0xa7, 0xed, + 0xc8, 0xe8, 0xf4, 0x9d, 0xd1, 0xd4, 0xe9, 0xbb, 0x53, 0xc7, 0x7a, 0x78, 0x01, 0x7b, 0xad, 0x79, + 0x46, 0xd6, 0xfe, 0xb0, 0x2b, 0x35, 0xce, 0xe1, 0xbd, 0x98, 0x3f, 0xdc, 0x9f, 0xe1, 0x99, 0x76, + 0x4a, 0xa8, 0xc9, 0xea, 0x9e, 0x07, 0xe7, 0xc5, 0x3f, 0x50, 0x77, 0x9b, 0xd3, 0x9e, 0x65, 0xbd, + 0x39, 0x9d, 0x99, 0xd1, 0x9b, 0xd3, 0x1d, 0x07, 0xd6, 0x7b, 0x6b, 0x5c, 0x34, 0x53, 0x72, 0x39, + 0x2a, 0x6f, 0xf6, 0x57, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x89, 0x83, 0xd3, 0x0a, 0x21, 0x06, + 0x00, 0x00, +} diff --git a/pkg/proto/hapi/release/release.pb.go b/pkg/proto/hapi/release/release.pb.go index 47b321b50..f58ce1502 100644 --- a/pkg/proto/hapi/release/release.pb.go +++ b/pkg/proto/hapi/release/release.pb.go @@ -40,7 +40,7 @@ type Release struct { func (m *Release) Reset() { *m = Release{} } func (m *Release) String() string { return proto.CompactTextString(m) } func (*Release) ProtoMessage() {} -func (*Release) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} } +func (*Release) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } func (m *Release) GetName() string { if m != nil { @@ -102,9 +102,9 @@ func init() { proto.RegisterType((*Release)(nil), "hapi.release.Release") } -func init() { proto.RegisterFile("hapi/release/release.proto", fileDescriptor2) } +func init() { proto.RegisterFile("hapi/release/release.proto", fileDescriptor3) } -var fileDescriptor2 = []byte{ +var fileDescriptor3 = []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, diff --git a/pkg/proto/hapi/release/status.pb.go b/pkg/proto/hapi/release/status.pb.go index 0098207a7..71ed631c8 100644 --- a/pkg/proto/hapi/release/status.pb.go +++ b/pkg/proto/hapi/release/status.pb.go @@ -51,7 +51,7 @@ var Status_Code_value = map[string]int32{ func (x Status_Code) String() string { return proto.EnumName(Status_Code_name, int32(x)) } -func (Status_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor3, []int{0, 0} } +func (Status_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor4, []int{0, 0} } // Status defines the status of a release. type Status struct { @@ -67,7 +67,7 @@ type Status struct { func (m *Status) Reset() { *m = Status{} } func (m *Status) String() string { return proto.CompactTextString(m) } func (*Status) ProtoMessage() {} -func (*Status) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } +func (*Status) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} } func (m *Status) GetCode() Status_Code { if m != nil { @@ -102,9 +102,9 @@ func init() { proto.RegisterEnum("hapi.release.Status_Code", Status_Code_name, Status_Code_value) } -func init() { proto.RegisterFile("hapi/release/status.proto", fileDescriptor3) } +func init() { proto.RegisterFile("hapi/release/status.proto", fileDescriptor4) } -var fileDescriptor3 = []byte{ +var fileDescriptor4 = []byte{ // 291 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xdf, 0x6a, 0xc2, 0x30, 0x14, 0xc6, 0x57, 0xad, 0x3a, 0x8f, 0x22, 0x21, 0x1b, 0xac, 0xca, 0x06, 0xc5, 0xab, 0xde, 0xac, diff --git a/pkg/proto/hapi/release/test_run.pb.go b/pkg/proto/hapi/release/test_run.pb.go index 79fce4ab4..a40a410f8 100644 --- a/pkg/proto/hapi/release/test_run.pb.go +++ b/pkg/proto/hapi/release/test_run.pb.go @@ -36,7 +36,7 @@ var TestRun_Status_value = map[string]int32{ func (x TestRun_Status) String() string { return proto.EnumName(TestRun_Status_name, int32(x)) } -func (TestRun_Status) EnumDescriptor() ([]byte, []int) { return fileDescriptor4, []int{0, 0} } +func (TestRun_Status) EnumDescriptor() ([]byte, []int) { return fileDescriptor5, []int{0, 0} } type TestRun struct { Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -49,7 +49,7 @@ type TestRun struct { func (m *TestRun) Reset() { *m = TestRun{} } func (m *TestRun) String() string { return proto.CompactTextString(m) } func (*TestRun) ProtoMessage() {} -func (*TestRun) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} } +func (*TestRun) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} } func (m *TestRun) GetName() string { if m != nil { @@ -91,9 +91,9 @@ func init() { proto.RegisterEnum("hapi.release.TestRun_Status", TestRun_Status_name, TestRun_Status_value) } -func init() { proto.RegisterFile("hapi/release/test_run.proto", fileDescriptor4) } +func init() { proto.RegisterFile("hapi/release/test_run.proto", fileDescriptor5) } -var fileDescriptor4 = []byte{ +var fileDescriptor5 = []byte{ // 265 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0x41, 0x4b, 0xfb, 0x40, 0x14, 0xc4, 0xff, 0xc9, 0xbf, 0x26, 0x64, 0x53, 0x24, 0xec, 0x29, 0x54, 0xc1, 0xd0, 0x53, 0x4e, diff --git a/pkg/proto/hapi/release/test_suite.pb.go b/pkg/proto/hapi/release/test_suite.pb.go index f168bf1d2..304cded78 100644 --- a/pkg/proto/hapi/release/test_suite.pb.go +++ b/pkg/proto/hapi/release/test_suite.pb.go @@ -27,7 +27,7 @@ type TestSuite struct { func (m *TestSuite) Reset() { *m = TestSuite{} } func (m *TestSuite) String() string { return proto.CompactTextString(m) } func (*TestSuite) ProtoMessage() {} -func (*TestSuite) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} } +func (*TestSuite) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{0} } func (m *TestSuite) GetStartedAt() *google_protobuf.Timestamp { if m != nil { @@ -54,9 +54,9 @@ func init() { proto.RegisterType((*TestSuite)(nil), "hapi.release.TestSuite") } -func init() { proto.RegisterFile("hapi/release/test_suite.proto", fileDescriptor5) } +func init() { proto.RegisterFile("hapi/release/test_suite.proto", fileDescriptor6) } -var fileDescriptor5 = []byte{ +var fileDescriptor6 = []byte{ // 207 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0xc1, 0x4a, 0x86, 0x40, 0x14, 0x85, 0x31, 0x21, 0x71, 0x74, 0x35, 0x10, 0x88, 0x11, 0x49, 0x2b, 0x57, 0x33, 0x60, 0xab, diff --git a/pkg/rudder/client.go b/pkg/rudder/client.go new file mode 100644 index 000000000..cc3b193ab --- /dev/null +++ b/pkg/rudder/client.go @@ -0,0 +1,42 @@ +/* +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" + + "k8s.io/helm/pkg/proto/hapi/release" +) + +// GrpcAddr is port number for accessing Rudder service +var GrpcAddr = 10001 + +// InstallRelease calls Rudder InstallRelease method which should create provided release +func InstallRelease(rel *release.InstallReleaseRequest) (*release.InstallReleaseResponse, error) { + //TODO(mkwiek): parametrize this + conn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", GrpcAddr), grpc.WithInsecure()) + if err != nil { + return nil, err + } + + defer conn.Close() + client := release.NewReleaseModuleServiceClient(conn) + return client.InstallRelease(context.Background(), rel) +} diff --git a/pkg/tiller/release_modules.go b/pkg/tiller/release_modules.go new file mode 100644 index 000000000..12d4cdcb2 --- /dev/null +++ b/pkg/tiller/release_modules.go @@ -0,0 +1,50 @@ +/* +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" + + "k8s.io/helm/pkg/proto/hapi/release" + "k8s.io/helm/pkg/proto/hapi/services" + "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 +} + +// LocalReleaseModule is a local implementation of ReleaseModule +type LocalReleaseModule struct{} + +// 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) +} + +// 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 := &release.InstallReleaseRequest{Release: r} + _, err := rudder.InstallRelease(request) + return err +} diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index bd480fb32..4d56465cb 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -82,15 +82,24 @@ 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 } // NewReleaseServer creates a new release server. -func NewReleaseServer(env *environment.Environment, clientset internalclientset.Interface) *ReleaseServer { +func NewReleaseServer(env *environment.Environment, clientset internalclientset.Interface, useRemote bool) *ReleaseServer { + var releaseModule ReleaseModule + if useRemote { + releaseModule = &RemoteReleaseModule{} + } else { + releaseModule = &LocalReleaseModule{} + } + return &ReleaseServer{ - env: env, - clientset: clientset, + env: env, + clientset: clientset, + ReleaseModule: releaseModule, } } @@ -907,8 +916,7 @@ func (s *ReleaseServer) performRelease(r *release.Release, req *services.Install default: // nothing to replace, create as normal // regular manifests - b := bytes.NewBufferString(r.Manifest) - if err := s.env.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait); err != nil { + if err := s.ReleaseModule.Create(r, req, s.env); err != nil { msg := fmt.Sprintf("Release %q failed: %s", r.Name, err) log.Printf("warning: %s", msg) r.Info.Status.Code = release.Status_FAILED diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index 596f0803b..e34d68e98 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -99,8 +99,9 @@ data: func rsFixture() *ReleaseServer { return &ReleaseServer{ - env: MockEnvironment(), - clientset: fake.NewSimpleClientset(), + ReleaseModule: &LocalReleaseModule{}, + env: MockEnvironment(), + clientset: fake.NewSimpleClientset(), } }