From 50f434951261ea3c8132e49ecabf6df649f6f9cd Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Mon, 18 Apr 2016 17:28:04 -0600 Subject: [PATCH] feat(tiller): add template and release to install --- _proto/hapi/chart/chart.proto | 2 +- _proto/hapi/chart/template.proto | 22 ++++------ cmd/tiller/environment/environment.go | 3 +- cmd/tiller/environment/environment_test.go | 5 ++- cmd/tiller/releases_server.go | 36 ++++++++++++++-- glide.lock | 10 +++-- glide.yaml | 1 + pkg/engine/engine.go | 43 ++++++++++++++++--- pkg/engine/engine_test.go | 4 +- pkg/proto/hapi/chart/chart.pb.go | 23 +++++----- pkg/proto/hapi/chart/template.pb.go | 50 ++++++---------------- 11 files changed, 118 insertions(+), 81 deletions(-) diff --git a/_proto/hapi/chart/chart.proto b/_proto/hapi/chart/chart.proto index 150bd6a14..4529b440f 100644 --- a/_proto/hapi/chart/chart.proto +++ b/_proto/hapi/chart/chart.proto @@ -18,7 +18,7 @@ message Chart { hapi.chart.Metadata metadata = 1; // Templates for this chart. - hapi.chart.Templates templates = 2; + repeated hapi.chart.Template templates = 2; // Charts that this chart depends on. repeated Chart dependencies = 3; diff --git a/_proto/hapi/chart/template.proto b/_proto/hapi/chart/template.proto index 4f9968966..3e68113c2 100644 --- a/_proto/hapi/chart/template.proto +++ b/_proto/hapi/chart/template.proto @@ -4,20 +4,14 @@ package hapi.chart; option go_package = "chart"; +// Template represents a template as a name/value pair. // -// Template: -// -// TODO -// -message Templates { - // TODO - repeated Template templates = 1; -} - +// By convention, name is a relative path within the scope of the chart's +// base directory. message Template { - // TODO - string template_name = 1; - - // TODO - bytes template_data = 2; + // Name is the path-like name of the template. + string name = 1; + + // Data is the template as byte data. + bytes data = 2; } diff --git a/cmd/tiller/environment/environment.go b/cmd/tiller/environment/environment.go index 078d24b50..b8a38c0ad 100644 --- a/cmd/tiller/environment/environment.go +++ b/cmd/tiller/environment/environment.go @@ -3,6 +3,7 @@ package environment import ( "github.com/deis/tiller/pkg/engine" "github.com/deis/tiller/pkg/hapi" + "github.com/deis/tiller/pkg/proto/hapi/chart" "github.com/deis/tiller/pkg/storage" ) @@ -51,7 +52,7 @@ func (y EngineYard) Default() Engine { // An Engine must be capable of executing multiple concurrent requests, but // without tainting one request's environment with data from another request. type Engine interface { - Render(*hapi.Chart, *hapi.Values) (map[string]string, error) + Render(*chart.Chart, *chart.Config) (map[string]string, error) } // ReleaseStorage represents a storage engine for a Release. diff --git a/cmd/tiller/environment/environment_test.go b/cmd/tiller/environment/environment_test.go index ffe531490..2ab7d7f2d 100644 --- a/cmd/tiller/environment/environment_test.go +++ b/cmd/tiller/environment/environment_test.go @@ -4,13 +4,14 @@ import ( "testing" "github.com/deis/tiller/pkg/hapi" + "github.com/deis/tiller/pkg/proto/hapi/chart" ) type mockEngine struct { out map[string]string } -func (e *mockEngine) Render(chrt *hapi.Chart, v *hapi.Values) (map[string]string, error) { +func (e *mockEngine) Render(chrt *chart.Chart, v *chart.Config) (map[string]string, error) { return e.out, nil } @@ -63,7 +64,7 @@ func TestEngine(t *testing.T) { if engine, ok := env.EngineYard.Get("test"); !ok { t.Errorf("failed to get engine from EngineYard") - } else if out, err := engine.Render(&hapi.Chart{}, &hapi.Values{}); err != nil { + } else if out, err := engine.Render(&chart.Chart{}, &chart.Config{}); err != nil { t.Errorf("unexpected template error: %s", err) } else if out["albatross"] != "test" { t.Errorf("expected 'test', got %q", out["albatross"]) diff --git a/cmd/tiller/releases_server.go b/cmd/tiller/releases_server.go index a5b0da9ae..6dab276cb 100644 --- a/cmd/tiller/releases_server.go +++ b/cmd/tiller/releases_server.go @@ -4,7 +4,9 @@ import ( "errors" "github.com/deis/tiller/cmd/tiller/environment" + "github.com/deis/tiller/pkg/proto/hapi/release" "github.com/deis/tiller/pkg/proto/hapi/services" + "github.com/technosophos/moniker" ctx "golang.org/x/net/context" ) @@ -19,8 +21,11 @@ type releaseServer struct { env *environment.Environment } -// errNotImplemented is a temporary error for uninmplemented callbacks. -var errNotImplemented = errors.New("not implemented") +var ( + // errNotImplemented is a temporary error for uninmplemented callbacks. + errNotImplemented = errors.New("not implemented") + errMissingChart = errors.New("no chart provided") +) func (s *releaseServer) ListReleases(req *services.ListReleasesRequest, stream services.ReleaseService_ListReleasesServer) error { return errNotImplemented @@ -39,7 +44,32 @@ func (s *releaseServer) UpdateRelease(c ctx.Context, req *services.UpdateRelease } func (s *releaseServer) InstallRelease(c ctx.Context, req *services.InstallReleaseRequest) (*services.InstallReleaseResponse, error) { - return &services.InstallReleaseResponse{}, errNotImplemented + if req.Chart == nil { + return nil, errMissingChart + } + + // We should probably make a name generator part of the Environment. + namer := moniker.New() + // TODO: Make sure this is unique. + name := namer.Name() + + // Render the templates + _, err := s.env.EngineYard.Default().Render(req.Chart, req.Values) + if err != nil { + return nil, err + } + + // Store a release. + r := &release.Release{ + Name: name, + Chart: req.Chart, + Config: req.Values, + Info: &release.Info{ + Status: &release.Status{Code: release.Status_UNKNOWN}, + }, + } + + return &services.InstallReleaseResponse{Release: r}, errNotImplemented } func (s *releaseServer) UninstallRelease(c ctx.Context, req *services.UninstallReleaseRequest) (*services.UninstallReleaseResponse, error) { diff --git a/glide.lock b/glide.lock index 71ba5d45c..ed5d5e980 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: e7c99013acb06eb359cf20390579af9a4553ef0fbed3f7bbb784b4ab7c8df807 -updated: 2016-04-15T15:15:21.87772545-06:00 +hash: 264d156a2a07d53efbf5f608ead3eb31c261de5124e0235139b3f99c6ead4dba +updated: 2016-04-18T17:25:07.662942088-06:00 imports: - name: github.com/aokoli/goutils version: 9c37978a95bd5c709a15883b6242714ea6709e64 @@ -11,6 +11,8 @@ imports: version: f0a097ddac24fb00e07d2ac17f8671423f3ea47c subpackages: - proto + - ptypes/any + - ptypes/timestamp - name: github.com/Masterminds/semver version: 808ed7761c233af2de3f9729a041d68c62527f3a - name: github.com/Masterminds/sprig @@ -21,6 +23,8 @@ imports: - cobra - name: github.com/spf13/pflag version: 8f6a28b0916586e7f22fe931ae2fcfc380b1c0e6 +- name: github.com/technosophos/moniker + version: 9f956786b91d9786ca11aa5be6104542fa911546 - name: golang.org/x/net version: fb93926129b8ec0056f2f458b1f519654814edf0 subpackages: @@ -30,7 +34,7 @@ imports: - http2/hpack - internal/timeseries - name: google.golang.org/grpc - version: 8eeecf2291de9d171d0b1392a27ff3975679f4f5 + version: dec33edc378cf4971a2741cfd86ed70a644d6ba3 subpackages: - codes - credentials diff --git a/glide.yaml b/glide.yaml index 2b1531d12..7560443da 100644 --- a/glide.yaml +++ b/glide.yaml @@ -13,3 +13,4 @@ import: - package: github.com/Masterminds/semver version: 1.1.0 - package: github.com/BurntSushi/toml +- package: github.com/technosophos/moniker diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 59a42f96f..c19caab58 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -6,7 +6,8 @@ import ( "text/template" "github.com/Masterminds/sprig" - "github.com/deis/tiller/pkg/hapi" + chartutil "github.com/deis/tiller/pkg/chart" + "github.com/deis/tiller/pkg/proto/hapi/chart" ) // Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates. @@ -38,13 +39,41 @@ func New() *Engine { // // This will look in the chart's 'templates' data (e.g. the 'templates/' directory) // and attempt to render the templates there using the values passed in. -func (e *Engine) Render(chart *hapi.Chart, vals *hapi.Values) (map[string]string, error) { - // Uncomment this once the proto files compile. - //return render(chart.Chartfile.Name, chart.Templates, vals) - return map[string]string{}, nil +func (e *Engine) Render(chrt *chart.Chart, vals *chart.Config) (map[string]string, error) { + var cvals chartutil.Values + if chrt.Values == nil { + cvals = map[string]interface{}{} + } else { + var err error + cvals, err = chartutil.ReadValues([]byte(chrt.Values.Raw)) + if err != nil { + return map[string]string{}, err + } + } + + // Parse values if not nil + if vals != nil { + evals, err := chartutil.ReadValues([]byte(vals.Raw)) + if err != nil { + return map[string]string{}, err + } + // Coalesce chart default values and values + for k, v := range evals { + // FIXME: This needs to merge tables. Ideally, this feature should + // be part of the Values type. + cvals[k] = v + } + } + + // Render the charts + tmap := make(map[string]string, len(chrt.Templates)) + for _, tpl := range chrt.Templates { + tmap[tpl.Name] = string(tpl.Data) + } + return e.render(tmap, cvals) } -func (e *Engine) render(name string, tpls map[string]string, v interface{}) (map[string]string, error) { +func (e *Engine) render(tpls map[string]string, v interface{}) (map[string]string, error) { // Basically, what we do here is start with an empty parent template and then // build up a list of templates -- one for each file. Once all of the templates // have been parsed, we loop through again and execute every template. @@ -52,7 +81,7 @@ func (e *Engine) render(name string, tpls map[string]string, v interface{}) (map // The idea with this process is to make it possible for more complex templates // to share common blocks, but to make the entire thing feel like a file-based // template engine. - t := template.New(name) + t := template.New("gotpl") files := []string{} for fname, tpl := range tpls { t = t.New(fname).Funcs(e.FuncMap) diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index b0a00794b..dba3b2fe3 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -35,7 +35,7 @@ func TestRenderInternals(t *testing.T) { } vals := map[string]string{"Name": "one", "Value": "two"} - out, err := e.render("irrelevant", tpls, vals) + out, err := e.render(tpls, vals) if err != nil { t.Fatalf("Failed template rendering: %s", err) } @@ -68,7 +68,7 @@ func TestParallelRenderInternals(t *testing.T) { tt := fmt.Sprintf("expect-%d", i) tpls := map[string]string{fname: `{{.val}}`} v := map[string]string{"val": tt} - out, err := e.render("intentionally_duplicated", tpls, v) + out, err := e.render(tpls, v) if err != nil { t.Errorf("Failed to render %s: %s", tt, err) } diff --git a/pkg/proto/hapi/chart/chart.pb.go b/pkg/proto/hapi/chart/chart.pb.go index 86c246e83..81937a65e 100644 --- a/pkg/proto/hapi/chart/chart.pb.go +++ b/pkg/proto/hapi/chart/chart.pb.go @@ -16,7 +16,6 @@ It has these top-level messages: Config Maintainer Metadata - Templates Template */ package chart @@ -43,7 +42,7 @@ type Chart struct { // Contents of the Chartfile. Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata" json:"metadata,omitempty"` // Templates for this chart. - Templates *Templates `protobuf:"bytes,2,opt,name=templates" json:"templates,omitempty"` + Templates []*Template `protobuf:"bytes,2,rep,name=templates" json:"templates,omitempty"` // Charts that this chart depends on. Dependencies []*Chart `protobuf:"bytes,3,rep,name=dependencies" json:"dependencies,omitempty"` // Default config for this template. @@ -62,7 +61,7 @@ func (m *Chart) GetMetadata() *Metadata { return nil } -func (m *Chart) GetTemplates() *Templates { +func (m *Chart) GetTemplates() []*Template { if m != nil { return m.Templates } @@ -88,18 +87,18 @@ func init() { } var fileDescriptor0 = []byte{ - // 200 bytes of a gzipped FileDescriptorProto + // 197 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0xcb, 0x48, 0x2c, 0xc8, 0xd4, 0x4f, 0xce, 0x48, 0x2c, 0x2a, 0x81, 0x90, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x5c, 0x20, 0x71, 0x3d, 0xb0, 0x88, 0x94, 0x38, 0xb2, 0x9a, 0xfc, 0xbc, 0xb4, 0xcc, 0x74, 0x88, 0x22, 0x29, 0x49, 0x24, 0x89, 0xdc, 0xd4, 0x92, 0xc4, 0x94, 0xc4, 0x92, 0x44, 0x2c, 0x52, 0x25, 0xa9, - 0xb9, 0x05, 0x39, 0x89, 0x25, 0xa9, 0x10, 0x29, 0xa5, 0x8b, 0x8c, 0x5c, 0xac, 0xce, 0x20, 0x09, + 0xb9, 0x05, 0x39, 0x89, 0x25, 0xa9, 0x10, 0x29, 0xa5, 0x0b, 0x8c, 0x5c, 0xac, 0xce, 0x20, 0x09, 0x21, 0x03, 0x2e, 0x0e, 0x98, 0x36, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, 0x11, 0x3d, 0x84, - 0xbd, 0x7a, 0xbe, 0x50, 0xb9, 0x20, 0xb8, 0x2a, 0x21, 0x63, 0x2e, 0x4e, 0x98, 0x69, 0xc5, 0x12, - 0x4c, 0x60, 0x2d, 0xa2, 0xc8, 0x5a, 0x42, 0x60, 0x92, 0x41, 0x08, 0x75, 0x42, 0xa6, 0x5c, 0x3c, - 0x29, 0xa9, 0x05, 0xa9, 0x79, 0x29, 0xa9, 0x79, 0xc9, 0x99, 0x40, 0x7d, 0xcc, 0x0a, 0xcc, 0x40, - 0x7d, 0x82, 0xc8, 0xfa, 0xc0, 0xee, 0x09, 0x42, 0x51, 0x26, 0xa4, 0xc5, 0xc5, 0x56, 0x96, 0x98, - 0x53, 0x0a, 0xd4, 0xc0, 0x02, 0xb6, 0x48, 0x08, 0x45, 0x03, 0x38, 0x1c, 0x82, 0xa0, 0x2a, 0x9c, - 0xd8, 0xa3, 0x58, 0xc1, 0xe2, 0x49, 0x6c, 0x60, 0x3f, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, - 0x12, 0xa6, 0x6a, 0xa8, 0x58, 0x01, 0x00, 0x00, + 0xbd, 0x7a, 0xbe, 0x50, 0xb9, 0x20, 0xb8, 0x2a, 0x21, 0x23, 0x2e, 0x4e, 0x98, 0x69, 0xc5, 0x12, + 0x4c, 0x0a, 0xcc, 0xe8, 0x5a, 0x42, 0xa0, 0x92, 0x41, 0x08, 0x65, 0x42, 0xa6, 0x5c, 0x3c, 0x29, + 0xa9, 0x05, 0xa9, 0x79, 0x29, 0xa9, 0x79, 0xc9, 0x99, 0x40, 0x6d, 0xcc, 0x60, 0x6d, 0x82, 0xc8, + 0xda, 0xc0, 0xce, 0x09, 0x42, 0x51, 0x26, 0xa4, 0xc5, 0xc5, 0x56, 0x96, 0x98, 0x53, 0x0a, 0xd4, + 0xc0, 0x02, 0x76, 0x9a, 0x10, 0x8a, 0x06, 0x70, 0x30, 0x04, 0x41, 0x55, 0x38, 0xb1, 0x47, 0xb1, + 0x82, 0xc5, 0x93, 0xd8, 0xc0, 0x5e, 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xb5, 0xff, 0x0f, + 0xec, 0x57, 0x01, 0x00, 0x00, } diff --git a/pkg/proto/hapi/chart/template.pb.go b/pkg/proto/hapi/chart/template.pb.go index f5b6b3704..115bc945e 100644 --- a/pkg/proto/hapi/chart/template.pb.go +++ b/pkg/proto/hapi/chart/template.pb.go @@ -13,55 +13,33 @@ var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +// Template represents a template as a name/value pair. // -// Template: -// -// TODO -// -type Templates struct { - // TODO - Templates []*Template `protobuf:"bytes,1,rep,name=templates" json:"templates,omitempty"` -} - -func (m *Templates) Reset() { *m = Templates{} } -func (m *Templates) String() string { return proto.CompactTextString(m) } -func (*Templates) ProtoMessage() {} -func (*Templates) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } - -func (m *Templates) GetTemplates() []*Template { - if m != nil { - return m.Templates - } - return nil -} - +// By convention, name is a relative path within the scope of the chart's +// base directory. type Template struct { - // TODO - TemplateName string `protobuf:"bytes,1,opt,name=template_name,json=templateName" json:"template_name,omitempty"` - // TODO - TemplateData []byte `protobuf:"bytes,2,opt,name=template_data,json=templateData,proto3" json:"template_data,omitempty"` + // Name is the path-like name of the template. + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + // Data is the template as byte data. + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` } func (m *Template) Reset() { *m = Template{} } func (m *Template) String() string { return proto.CompactTextString(m) } func (*Template) ProtoMessage() {} -func (*Template) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{1} } +func (*Template) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } func init() { - proto.RegisterType((*Templates)(nil), "hapi.chart.Templates") proto.RegisterType((*Template)(nil), "hapi.chart.Template") } var fileDescriptor3 = []byte{ - // 146 bytes of a gzipped FileDescriptorProto + // 106 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0xcc, 0x48, 0x2c, 0xc8, 0xd4, 0x4f, 0xce, 0x48, 0x2c, 0x2a, 0xd1, 0x2f, 0x49, 0xcd, 0x2d, 0xc8, 0x49, 0x2c, 0x49, 0xd5, - 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x02, 0x49, 0xe9, 0x81, 0xa5, 0x94, 0xec, 0xb9, 0x38, - 0x43, 0xa0, 0xb2, 0xc5, 0x42, 0x46, 0x5c, 0x9c, 0x30, 0xa5, 0xc5, 0x12, 0x8c, 0x0a, 0xcc, 0x1a, - 0xdc, 0x46, 0x22, 0x7a, 0x08, 0xc5, 0x7a, 0x30, 0x95, 0x41, 0x08, 0x65, 0x4a, 0x21, 0x5c, 0x1c, - 0x30, 0x61, 0x21, 0x65, 0x2e, 0x5e, 0x98, 0x44, 0x7c, 0x5e, 0x62, 0x6e, 0x2a, 0xd0, 0x0c, 0x46, - 0x0d, 0xce, 0x20, 0x1e, 0x98, 0xa0, 0x1f, 0x50, 0x0c, 0x45, 0x51, 0x4a, 0x62, 0x49, 0xa2, 0x04, - 0x13, 0x50, 0x11, 0x0f, 0x42, 0x91, 0x0b, 0x50, 0xcc, 0x89, 0x3d, 0x8a, 0x15, 0x6c, 0x65, 0x12, - 0x1b, 0xd8, 0xc9, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x48, 0xda, 0x77, 0x0e, 0xcf, 0x00, - 0x00, 0x00, + 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x02, 0x49, 0xe9, 0x81, 0xa5, 0x94, 0x8c, 0xb8, 0x38, + 0x42, 0xa0, 0xb2, 0x42, 0x42, 0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, + 0x9c, 0x41, 0x60, 0x36, 0x48, 0x2c, 0x25, 0xb1, 0x24, 0x51, 0x82, 0x09, 0x28, 0xc6, 0x13, 0x04, + 0x66, 0x3b, 0xb1, 0x47, 0xb1, 0x82, 0x35, 0x27, 0xb1, 0x81, 0xcd, 0x33, 0x06, 0x04, 0x00, 0x00, + 0xff, 0xff, 0x53, 0xee, 0x0e, 0x67, 0x6c, 0x00, 0x00, 0x00, }