From 498ae2af64c9c9480b05fa7a41856057b34f2f49 Mon Sep 17 00:00:00 2001 From: Dave Cunningham Date: Wed, 16 Mar 2016 18:07:52 -0400 Subject: [PATCH] Made helm client & expandyservice build --- cmd/expandybird/expander/expander.go | 50 ++++++++++++++++++++++++---- cmd/helm/deploy.go | 50 +++++++++++----------------- pkg/client/client.go | 36 ++++++++++++++++++++ 3 files changed, 99 insertions(+), 37 deletions(-) diff --git a/cmd/expandybird/expander/expander.go b/cmd/expandybird/expander/expander.go index 8fda42f3e..ab42b1bd4 100644 --- a/cmd/expandybird/expander/expander.go +++ b/cmd/expandybird/expander/expander.go @@ -19,8 +19,8 @@ package expander import ( "bytes" "fmt" + "encoding/json" "log" - "os" "os/exec" "github.com/ghodss/yaml" @@ -119,9 +119,29 @@ func (eResponse *ExpansionResponse) Unmarshal() (*ExpansionResult, error) { // ExpandTemplate passes the given configuration to the expander and returns the // expanded configuration as a string on success. func (e *expander) ExpandTemplate(template *common.Template) (string, error) { + chartInv := template.ChartInvocation + chart := template.Chart + + if chart.Expander.Name != "Expandybird" { + message := fmt.Sprintf("Expandybird cannot do this kind of expansion: ", chart.Expander) + return "", fmt.Errorf("error expanding template %s: %s", chartInv.Name, message) + } + if e.ExpansionBinary == "" { message := fmt.Sprintf("expansion binary cannot be empty") - return "", fmt.Errorf("error expanding template %s: %s", template.Name, message) + return "", fmt.Errorf("error expanding chart %s: %s", chartInv.Name, message) + } + + if len(chart.Files) != 1 { + message := fmt.Sprintf("Expandybird can only process a chart containing 1 file, got %d", len(chart.Files)) + return "", fmt.Errorf("error expanding template %s: %s", chartInv.Name, message) + } + + entrypoint_file := chart.Files[0] + + if entrypoint_file.Path != chart.Expander.Entrypoint { + message := fmt.Sprintf("The entrypoint in the chart.yaml canont be found %s", chart.Expander.Entrypoint) + return "", fmt.Errorf("error expanding template %s: %s", chartInv.Name, message) } // Those are automatically increasing buffers, so writing arbitrary large @@ -129,20 +149,36 @@ func (e *expander) ExpandTemplate(template *common.Template) (string, error) { var stdout bytes.Buffer var stderr bytes.Buffer + // Now we convert the new chart representation into the form that classic Expandybird takes. + + chartInvJson, err := json.Marshal(chartInv) + if err != nil { + return "", fmt.Errorf("error marshalling chart invocation %s: %s", chartInv.Name, err) + } + content := "{ \"resources\": [" + string(chartInvJson) + "] }" + cmd := &exec.Cmd{ Path: e.ExpansionBinary, // Note, that binary name still has to be passed argv[0]. - Args: []string{e.ExpansionBinary, template.Content}, + Args: []string{e.ExpansionBinary, content}, // TODO(vagababov): figure out whether do we even need "PROJECT" and // "DEPLOYMENT_NAME" variables here. - Env: append(os.Environ(), "PROJECT="+template.Name, "DEPLOYMENT_NAME="+template.Name), + // [dcunnin]: Assuming we won't need this, at least for now. + // Env: append(os.Environ(), "PROJECT="+chartInv.Name, "DEPLOYMENT_NAME="+chartInv.Name), Stdout: &stdout, Stderr: &stderr, } - for _, imp := range template.Imports { - cmd.Args = append(cmd.Args, imp.Name, imp.Path, imp.Content) + // Add entrypoint file (currently only 1 is supported). + cmd.Args = append(cmd.Args, chart.Name, entrypoint_file.Path, entrypoint_file.Content) + + // Add schema file + schema_name := chart.Name + ".schema" + schemaJson, err := json.Marshal(chart.Schema) + if err != nil { + return "", fmt.Errorf("error marshalling schema %s: %s", chartInv.Name, err) } + cmd.Args = append(cmd.Args, schema_name, schema_name, string(schemaJson)) if err := cmd.Start(); err != nil { log.Printf("error starting expansion process: %s", err) @@ -154,7 +190,7 @@ func (e *expander) ExpandTemplate(template *common.Template) (string, error) { log.Printf("Expansion process: pid: %d SysTime: %v UserTime: %v", cmd.ProcessState.Pid(), cmd.ProcessState.SystemTime(), cmd.ProcessState.UserTime()) if stderr.String() != "" { - return "", fmt.Errorf("error expanding template %s: %s", template.Name, stderr.String()) + return "", fmt.Errorf("error expanding chart %s: %s", chartInv.Name, stderr.String()) } return stdout.String(), nil diff --git a/cmd/helm/deploy.go b/cmd/helm/deploy.go index e1cef8747..5fafdfe4b 100644 --- a/cmd/helm/deploy.go +++ b/cmd/helm/deploy.go @@ -17,6 +17,7 @@ limitations under the License. package main import ( + "fmt" "io/ioutil" "os" @@ -55,40 +56,29 @@ func deployCmd() cli.Command { func deploy(c *cli.Context) error { - // If there is a configuration file, use it. - cfg := &common.Configuration{} + res := &common.Resource{ + // By default + Properties: map[string]interface{}{}, + } + if c.String("config") != "" { - if err := loadConfig(cfg, c.String("config")); err != nil { + // If there is a configuration file, use it. + err := loadConfig(c.String("config"), &res.Properties); + if err != nil { return err } - } else { - cfg.Resources = []*common.Resource{ - { - Properties: map[string]interface{}{}, - }, - } } - // If there is a chart specified on the commandline, override the config - // file with it. args := c.Args() - if len(args) > 0 { - cname := args[0] - if isLocalChart(cname) { - // If we get here, we need to first package then upload the chart. - loc, err := doUpload(cname, "", c) - if err != nil { - return err - } - cfg.Resources[0].Name = loc - } else { - cfg.Resources[0].Type = cname - } + if len(args) == 0 { + return fmt.Errorf("Need chart name on commandline") } + res.Type = args[0] - // Override the name if one is passed in. if name := c.String("name"); len(name) > 0 { - cfg.Resources[0].Name = name + res.Name = name + } else { + return fmt.Errorf("Need deployed name on commandline") } if props, err := parseProperties(c.String("properties")); err != nil { @@ -98,11 +88,11 @@ func deploy(c *cli.Context) error { // knowing which resource the properties are supposed to be part // of. for n, v := range props { - cfg.Resources[0].Properties[n] = v + res.Properties[n] = v } } - return NewClient(c).PostDeployment(cfg.Resources[0].Name, cfg) + return NewClient(c).PostDeployment(res) } // isLocalChart returns true if the given path can be statted. @@ -111,11 +101,11 @@ func isLocalChart(path string) bool { return err == nil } -// loadConfig loads a file into a common.Configuration. -func loadConfig(c *common.Configuration, filename string) error { +// loadConfig loads chart arguments into c +func loadConfig(filename string, dest *map[string]interface{}) error { data, err := ioutil.ReadFile(filename) if err != nil { return err } - return yaml.Unmarshal(data, c) + return yaml.Unmarshal(data, dest) } diff --git a/pkg/client/client.go b/pkg/client/client.go index 445160127..33d8b6850 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -192,3 +192,39 @@ func (e *HTTPError) Error() string { func (e *HTTPError) String() string { return e.Error() } + +// GetDeployment retrieves the supplied deployment +func (c *Client) GetDeployment(name string) (*common.Deployment, error) { + var deployment *common.Deployment + if err := c.CallService(fancypath.Join("deployments", name), "GET", "get deployment", &deployment, nil); err != nil { + return nil, err + } + return deployment, nil +} + +// DeleteDeployment deletes the supplied deployment +func (c *Client) DeleteDeployment(name string) (*common.Deployment, error) { + var deployment *common.Deployment + if err := c.CallService(filepath.Join("deployments", name), "DELETE", "delete deployment", &deployment, nil); err != nil { + return nil, err + } + return deployment, nil +} + +// PostDeployment posts a deployment object to the manager service. +func (c *Client) PostDeployment(res *common.Resource) error { + // This is a stop-gap until we get this API cleaned up. + t := common.Template{ + ChartInvocation: res, + } + + data, err := json.Marshal(t) + if err != nil { + return err + } + + var out struct{} + + b := bytes.NewBuffer(data) + return c.CallService("/deployments", "POST", "post deployment", &out, b) +}