diff --git a/_proto/hapi/chart/chart.proto b/_proto/hapi/chart/chart.proto index 4529b440f..90e4938cc 100644 --- a/_proto/hapi/chart/chart.proto +++ b/_proto/hapi/chart/chart.proto @@ -23,7 +23,7 @@ message Chart { // Charts that this chart depends on. repeated Chart dependencies = 3; - // Default config for this template. - hapi.chart.Config values = 4; + // Default config for this template. + hapi.chart.Config values = 4; } diff --git a/_proto/hapi/chart/config.proto b/_proto/hapi/chart/config.proto index 541564268..0829632ac 100644 --- a/_proto/hapi/chart/config.proto +++ b/_proto/hapi/chart/config.proto @@ -11,4 +11,15 @@ option go_package = "chart"; // message Config { string raw = 1; + + map values = 2; +} + +// +// Value: +// +// TODO +// +message Value { + string value = 1; } diff --git a/_proto/hapi/chart/metadata.proto b/_proto/hapi/chart/metadata.proto index 3068aa452..08e03985d 100644 --- a/_proto/hapi/chart/metadata.proto +++ b/_proto/hapi/chart/metadata.proto @@ -33,7 +33,7 @@ message Metadata { string home = 2; // Source is the URL to the source code of this chart - string source = 3; + repeated string sources = 3; // A SemVer 2 conformant version string of the chart string version = 4; diff --git a/cmd/helm/init.go b/cmd/helm/init.go index ec6f284fc..674e0d904 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -12,7 +12,7 @@ import ( "github.com/spf13/cobra" ) -const installDesc = ` +const initDesc = ` This command installs Tiller (the helm server side component) onto your Kubernetes Cluster and sets up local configuration in $HELM_HOME (default: ~/.helm/) ` diff --git a/cmd/helm/install.go b/cmd/helm/install.go new file mode 100644 index 000000000..073edfd97 --- /dev/null +++ b/cmd/helm/install.go @@ -0,0 +1,65 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/spf13/cobra" + + "github.com/deis/tiller/pkg/chart" + "github.com/deis/tiller/pkg/helm" +) + +const installDesc = ` +This command installs a chart archive. +` + +func init() { + RootCommand.Flags() + RootCommand.AddCommand(installCmd) +} + +var installCmd = &cobra.Command{ + Use: "install [CHART]", + Short: "install a chart archive.", + Long: installDesc, + RunE: runInstall, +} + +func runInstall(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return fmt.Errorf("This command needs at least one argument, the name of the chart.") + } + + ch, err := loadChart(args[0]) + if err != nil { + return err + } + + res, err := helm.InstallRelease(ch) + if err != nil { + return err + } + + fmt.Printf("release.name: %s\n", res.Release.Name) + fmt.Printf("release.chart: %s\n", res.Release.Chart.Metadata.Name) + fmt.Printf("release.status: %s\n", res.Release.Info.Status.Code) + + return nil +} + +func loadChart(path string) (*chart.Chart, error) { + path, err := filepath.Abs(path) + if err != nil { + return nil, err + } + + if fi, err := os.Stat(path); err != nil { + return nil, err + } else if fi.IsDir() { + return chart.LoadDir(path) + } + + return chart.Load(path) +} diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index 964f8490b..73b948e26 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -93,6 +93,11 @@ func (c *Chart) ChartsDir() string { return filepath.Join(c.loader.dir(), preCharts) } +// LoadValues loads the contents of values.toml into a map +func (c *Chart) LoadValues() (Values, error) { + return ReadValuesFile(filepath.Join(c.loader.dir(), preValues)) +} + // chartLoader provides load, close, and save implementations for a chart. type chartLoader interface { // Chartfile resturns a *Chartfile for this chart. diff --git a/pkg/helm/client.go b/pkg/helm/client.go new file mode 100644 index 000000000..a68a1efb4 --- /dev/null +++ b/pkg/helm/client.go @@ -0,0 +1,34 @@ +package helm + +import ( + "golang.org/x/net/context" + "google.golang.org/grpc" + + "github.com/deis/tiller/pkg/proto/hapi/services" +) + +type client struct { + cfg *config + conn *grpc.ClientConn + impl services.ReleaseServiceClient +} + +func (c *client) dial() (err error) { + c.conn, err = grpc.Dial(c.cfg.ServAddr, c.cfg.DialOpts()...) + c.impl = services.NewReleaseServiceClient(c.conn) + return +} + +func (c *client) install(req *services.InstallReleaseRequest) (res *services.InstallReleaseResponse, err error) { + if err = c.dial(); err != nil { + return + } + + defer c.Close() + + return c.impl.InstallRelease(context.TODO(), req, c.cfg.CallOpts()...) +} + +func (c *client) Close() error { + return c.conn.Close() +} diff --git a/pkg/helm/config.go b/pkg/helm/config.go new file mode 100644 index 000000000..0e515a112 --- /dev/null +++ b/pkg/helm/config.go @@ -0,0 +1,28 @@ +package helm + +import ( + "google.golang.org/grpc" +) + +type config struct { + ServAddr string + Insecure bool +} + +func (cfg *config) DialOpts() (opts []grpc.DialOption) { + if cfg.Insecure { + opts = append(opts, grpc.WithInsecure()) + } else { + // TODO: handle transport credentials + } + + return +} + +func (cfg *config) CallOpts() (opts []grpc.CallOption) { + return +} + +func (cfg *config) client() *client { + return &client{cfg: cfg} +} diff --git a/pkg/helm/error.go b/pkg/helm/error.go new file mode 100644 index 000000000..8f5a02499 --- /dev/null +++ b/pkg/helm/error.go @@ -0,0 +1,15 @@ +package helm + +const ( + errNotImplemented = Error("helm api not implemented") + errMissingSrvAddr = Error("missing tiller address") + errMissingTpls = Error("missing chart templates") + errMissingChart = Error("missing chart metadata") + errMissingValues = Error("missing chart values") +) + +type Error string + +func (e Error) Error() string { + return string(e) +} diff --git a/pkg/helm/helm.go b/pkg/helm/helm.go new file mode 100644 index 000000000..7e535c1d2 --- /dev/null +++ b/pkg/helm/helm.go @@ -0,0 +1,120 @@ +package helm + +import ( + "github.com/deis/tiller/pkg/chart" + chartpb "github.com/deis/tiller/pkg/proto/hapi/chart" + "github.com/deis/tiller/pkg/proto/hapi/services" +) + +var Config = &config{ + ServAddr: ":44134", + Insecure: true, +} + +func ListReleases(limit, offset int) (<-chan *services.ListReleasesResponse, error) { + return nil, errNotImplemented +} + +func GetReleaseStatus(name string) (*services.GetReleaseStatusResponse, error) { + return nil, errNotImplemented +} + +func GetReleaseContent(name string) (*services.GetReleaseContentResponse, error) { + return nil, errNotImplemented +} + +func UpdateRelease(name string) (*services.UpdateReleaseResponse, error) { + return nil, errNotImplemented +} + +func UninstallRelease(name string) (*services.UninstallReleaseResponse, error) { + return nil, errNotImplemented +} + +func InstallRelease(ch *chart.Chart) (res *services.InstallReleaseResponse, err error) { + chpb := new(chartpb.Chart) + + chpb.Metadata, err = mkProtoMetadata(ch.Chartfile()) + if err != nil { + return + } + + chpb.Templates, err = mkProtoTemplates(ch) + if err != nil { + return + } + + chpb.Dependencies, err = mkProtoChartDeps(ch) + if err != nil { + return + } + + var vals *chartpb.Config + + vals, err = mkProtoConfigValues(ch) + if err != nil { + return + } + + res, err = Config.client().install(&services.InstallReleaseRequest{ + Chart: chpb, + Values: vals, + }) + + return +} + +// pkg/chart to proto/hapi/chart helpers. temporary. +func mkProtoMetadata(ch *chart.Chartfile) (*chartpb.Metadata, error) { + if ch == nil { + return nil, errMissingChart + } + + md := &chartpb.Metadata{ + Name: ch.Name, + Home: ch.Home, + Version: ch.Version, + Description: ch.Description, + } + + md.Sources = make([]string, len(ch.Source)) + copy(md.Sources, ch.Source) + + md.Keywords = make([]string, len(ch.Keywords)) + copy(md.Keywords, ch.Keywords) + + for _, maintainer := range ch.Maintainers { + md.Maintainers = append(md.Maintainers, &chartpb.Maintainer{ + Name: maintainer.Name, + Email: maintainer.Email, + }) + } + + return md, nil +} + +func mkProtoTemplates(ch *chart.Chart) ([]*chartpb.Template, error) { + tpls, err := ch.LoadTemplates() + if err != nil { + return nil, err + } + + _ = tpls + + return nil, nil +} + +func mkProtoChartDeps(ch *chart.Chart) ([]*chartpb.Chart, error) { + return nil, nil +} + +func mkProtoConfigValues(ch *chart.Chart) (*chartpb.Config, error) { + vals, err := ch.LoadValues() + if err != nil { + return nil, errMissingValues + } + + _ = vals + + return nil, nil +} diff --git a/pkg/proto/hapi/chart/chart.pb.go b/pkg/proto/hapi/chart/chart.pb.go index 81937a65e..ee27d39f5 100644 --- a/pkg/proto/hapi/chart/chart.pb.go +++ b/pkg/proto/hapi/chart/chart.pb.go @@ -14,6 +14,7 @@ It is generated from these files: It has these top-level messages: Chart Config + Value Maintainer Metadata Template diff --git a/pkg/proto/hapi/chart/config.pb.go b/pkg/proto/hapi/chart/config.pb.go index decab3377..e4cd27998 100644 --- a/pkg/proto/hapi/chart/config.pb.go +++ b/pkg/proto/hapi/chart/config.pb.go @@ -19,7 +19,8 @@ var _ = math.Inf // A config supplies values to the parametrizable templates of a chart. // type Config struct { - Raw string `protobuf:"bytes,1,opt,name=raw" json:"raw,omitempty"` + Raw string `protobuf:"bytes,1,opt,name=raw" json:"raw,omitempty"` + Values map[string]*Value `protobuf:"bytes,2,rep,name=values" json:"values,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` } func (m *Config) Reset() { *m = Config{} } @@ -27,16 +28,44 @@ func (m *Config) String() string { return proto.CompactTextString(m) func (*Config) ProtoMessage() {} func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } +func (m *Config) GetValues() map[string]*Value { + if m != nil { + return m.Values + } + return nil +} + +// +// Value: +// +// TODO +// +type Value struct { + Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` +} + +func (m *Value) Reset() { *m = Value{} } +func (m *Value) String() string { return proto.CompactTextString(m) } +func (*Value) ProtoMessage() {} +func (*Value) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } + func init() { proto.RegisterType((*Config)(nil), "hapi.chart.Config") + proto.RegisterType((*Value)(nil), "hapi.chart.Value") } var fileDescriptor1 = []byte{ - // 89 bytes of a gzipped FileDescriptorProto + // 179 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0xcf, 0x48, 0x2c, 0xc8, 0xd4, 0x4f, 0xce, 0x48, 0x2c, 0x2a, 0xd1, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, - 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x02, 0x49, 0xe8, 0x81, 0x25, 0x94, 0xa4, 0xb8, 0xd8, 0x9c, 0xc1, - 0x72, 0x42, 0x02, 0x5c, 0xcc, 0x45, 0x89, 0xe5, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x20, - 0xa6, 0x13, 0x7b, 0x14, 0x2b, 0x58, 0x51, 0x12, 0x1b, 0x58, 0x9f, 0x31, 0x20, 0x00, 0x00, 0xff, - 0xff, 0xfe, 0xa0, 0x78, 0x2a, 0x52, 0x00, 0x00, 0x00, + 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x02, 0x49, 0xe8, 0x81, 0x25, 0x94, 0x16, 0x30, 0x72, 0xb1, 0x39, + 0x83, 0x25, 0x85, 0x04, 0xb8, 0x98, 0x8b, 0x12, 0xcb, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, + 0x40, 0x4c, 0x21, 0x33, 0x2e, 0xb6, 0xb2, 0xc4, 0x9c, 0xd2, 0xd4, 0x62, 0x09, 0x26, 0x05, 0x66, + 0x0d, 0x6e, 0x23, 0x39, 0x3d, 0x84, 0x4e, 0x3d, 0x88, 0x2e, 0xbd, 0x30, 0xb0, 0x02, 0xd7, 0xbc, + 0x92, 0xa2, 0xca, 0x20, 0xa8, 0x6a, 0x29, 0x1f, 0x2e, 0x6e, 0x24, 0x61, 0x90, 0xc1, 0xd9, 0xa9, + 0x95, 0x30, 0x83, 0x81, 0x4c, 0x21, 0x75, 0x2e, 0x56, 0xb0, 0x52, 0xa0, 0xb9, 0x8c, 0x40, 0x73, + 0x05, 0x91, 0xcd, 0x05, 0xeb, 0x0c, 0x82, 0xc8, 0x5b, 0x31, 0x59, 0x30, 0x2a, 0xc9, 0x72, 0xb1, + 0x82, 0xc5, 0x84, 0x44, 0x60, 0xba, 0x20, 0x26, 0x41, 0x38, 0x4e, 0xec, 0x51, 0xac, 0x60, 0x8d, + 0x49, 0x6c, 0x60, 0xdf, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe1, 0x12, 0x60, 0xda, 0xf8, + 0x00, 0x00, 0x00, } diff --git a/pkg/proto/hapi/chart/metadata.pb.go b/pkg/proto/hapi/chart/metadata.pb.go index 56ee4e021..42f16e125 100644 --- a/pkg/proto/hapi/chart/metadata.pb.go +++ b/pkg/proto/hapi/chart/metadata.pb.go @@ -44,7 +44,7 @@ type Metadata struct { // The URL to a relecant project page, git repo, or contact person Home string `protobuf:"bytes,2,opt,name=home" json:"home,omitempty"` // Source is the URL to the source code of this chart - Source string `protobuf:"bytes,3,opt,name=source" json:"source,omitempty"` + Sources []string `protobuf:"bytes,3,rep,name=sources" json:"sources,omitempty"` // A SemVer 2 conformant version string of the chart Version string `protobuf:"bytes,4,opt,name=version" json:"version,omitempty"` // A one-sentence description of the chart @@ -74,18 +74,18 @@ func init() { var fileDescriptor2 = []byte{ // 224 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0xb1, 0x4e, 0xc3, 0x30, - 0x10, 0x86, 0x15, 0xda, 0x24, 0xe5, 0xb2, 0x9d, 0x50, 0x65, 0x98, 0xa2, 0x4e, 0x4c, 0xae, 0x04, - 0x12, 0x62, 0x66, 0xef, 0xd2, 0x91, 0xed, 0x48, 0x4e, 0x8a, 0x05, 0x8e, 0x23, 0xdb, 0x80, 0x78, - 0x57, 0x1e, 0x06, 0xf7, 0x1a, 0x92, 0x0c, 0x1d, 0x22, 0xdd, 0xff, 0x7d, 0x77, 0x91, 0x7e, 0xc3, - 0x6d, 0x47, 0x83, 0xd9, 0x37, 0x1d, 0xf9, 0xb8, 0xb7, 0x1c, 0xa9, 0xa5, 0x48, 0x7a, 0xf0, 0x2e, - 0x3a, 0x84, 0x93, 0xd2, 0xa2, 0x76, 0x4f, 0x00, 0x07, 0x32, 0x7d, 0x4c, 0x1f, 0x7b, 0x44, 0x58, - 0xf7, 0x64, 0x59, 0x65, 0x75, 0x76, 0x7f, 0x7d, 0x94, 0x19, 0x6f, 0x20, 0x67, 0x4b, 0xe6, 0x43, - 0x5d, 0x09, 0x3c, 0x87, 0xdd, 0x6f, 0x06, 0x9b, 0xc3, 0xf8, 0xdb, 0x8b, 0x67, 0x89, 0x75, 0x2e, - 0xb1, 0xf3, 0x95, 0xcc, 0xb8, 0x85, 0x22, 0xb8, 0x4f, 0xdf, 0xb0, 0x5a, 0x09, 0x1d, 0x13, 0x2a, - 0x28, 0xbf, 0xd8, 0x07, 0xe3, 0x7a, 0xb5, 0x16, 0xf1, 0x1f, 0xb1, 0x86, 0xaa, 0xe5, 0xd0, 0x78, - 0x33, 0xc4, 0x93, 0xcd, 0xc5, 0x2e, 0x11, 0xde, 0xc1, 0xe6, 0x9d, 0x7f, 0xbe, 0x9d, 0x6f, 0x83, - 0x2a, 0xea, 0x55, 0xd2, 0x53, 0xc6, 0x67, 0xa8, 0xec, 0x54, 0x2e, 0xa8, 0x32, 0xe9, 0xea, 0x61, - 0xab, 0xe7, 0xfa, 0x7a, 0xee, 0x7e, 0x5c, 0xae, 0xbe, 0x94, 0xaf, 0xb9, 0x2c, 0xbc, 0x15, 0xf2, - 0x64, 0x8f, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x23, 0x79, 0xfc, 0xf8, 0x4f, 0x01, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0x3f, 0x4f, 0xc4, 0x30, + 0x0c, 0xc5, 0x55, 0xee, 0x7a, 0x3d, 0xdc, 0xcd, 0x42, 0x28, 0x30, 0x55, 0x37, 0x31, 0xe5, 0x24, + 0x90, 0x10, 0x33, 0xfb, 0x2d, 0x37, 0xb2, 0x99, 0xd6, 0x52, 0x23, 0x48, 0x53, 0x25, 0x01, 0xc4, + 0x97, 0xe5, 0xb3, 0x90, 0xba, 0xf4, 0xcf, 0xc0, 0x60, 0xc9, 0xef, 0xfd, 0xfc, 0x2c, 0xd9, 0x70, + 0xd3, 0x52, 0x6f, 0x8e, 0x75, 0x4b, 0x3e, 0x1e, 0x2d, 0x47, 0x6a, 0x28, 0x92, 0xee, 0xbd, 0x8b, + 0x0e, 0x61, 0x40, 0x5a, 0xd0, 0xe1, 0x11, 0xe0, 0x44, 0xa6, 0x8b, 0xa9, 0xd8, 0x23, 0xc2, 0xb6, + 0x23, 0xcb, 0x2a, 0xab, 0xb2, 0xbb, 0xcb, 0xb3, 0xf4, 0x78, 0x05, 0x39, 0x5b, 0x32, 0xef, 0xea, + 0x42, 0xcc, 0x51, 0x1c, 0x7e, 0x32, 0xd8, 0x9f, 0xfe, 0xd6, 0xfe, 0x1b, 0x4b, 0x5e, 0xeb, 0x92, + 0x37, 0xa6, 0xa4, 0x47, 0x05, 0x45, 0x70, 0x1f, 0xbe, 0xe6, 0xa0, 0x36, 0xd5, 0x26, 0xd9, 0x93, + 0x1c, 0xc8, 0x27, 0xfb, 0x60, 0x5c, 0xa7, 0xb6, 0x12, 0x98, 0x24, 0x56, 0x50, 0x36, 0x1c, 0x6a, + 0x6f, 0xfa, 0x38, 0xd0, 0x5c, 0xe8, 0xda, 0xc2, 0x5b, 0xd8, 0xbf, 0xf1, 0xf7, 0x97, 0xf3, 0x4d, + 0x50, 0x3b, 0x59, 0x3b, 0x6b, 0x7c, 0x82, 0xd2, 0xce, 0xe7, 0x05, 0x55, 0x24, 0x5c, 0xde, 0x5f, + 0xeb, 0xe5, 0x01, 0x7a, 0xb9, 0xfe, 0xbc, 0x1e, 0x7d, 0x2e, 0x5e, 0x72, 0x19, 0x78, 0xdd, 0xc9, + 0xd3, 0x1e, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xaf, 0x44, 0xa7, 0x51, 0x01, 0x00, 0x00, }