diff --git a/cmd/helm/init.go b/cmd/helm/init.go index af7fc5b20..65d63ba4d 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -26,6 +26,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/client-go/kubernetes" + "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/helm/cmd/helm/installer" "k8s.io/helm/pkg/getter" "k8s.io/helm/pkg/helm/helmpath" @@ -120,6 +121,9 @@ func newInitCmd(out io.Writer) *cobra.Command { f.BoolVar(&i.opts.EnableHostNetwork, "net-host", false, "install Tiller with net=host") f.StringVar(&i.serviceAccount, "service-account", "", "name of service account") + f.StringVar(&i.opts.NodeSelectors, "node-selectors", "", "labels to select which node tiller lands on") + f.StringVarP(&i.opts.Output, "output", "o", "", "skip installation and output tiller's manifest in specified format") + return cmd } @@ -159,31 +163,52 @@ func (i *initCmd) run() error { i.opts.ImageSpec = i.image i.opts.ServiceAccount = i.serviceAccount - if settings.Debug { - writeYAMLManifest := func(apiVersion, kind, body string, first, last bool) error { - w := i.out - if !first { - // YAML starting document boundary marker - if _, err := fmt.Fprintln(w, "---"); err != nil { - return err - } - } - if _, err := fmt.Fprintln(w, "apiVersion:", apiVersion); err != nil { + writeYAMLManifest := func(apiVersion, kind, body string, first, last bool) error { + w := i.out + if !first { + // YAML starting document boundary marker + if _, err := fmt.Fprintln(w, "---"); err != nil { return err } - if _, err := fmt.Fprintln(w, "kind:", kind); err != nil { + } + if _, err := fmt.Fprintln(w, "apiVersion:", apiVersion); err != nil { + return err + } + if _, err := fmt.Fprintln(w, "kind:", kind); err != nil { + return err + } + if _, err := fmt.Fprint(w, body); err != nil { + return err + } + if !last { + return nil + } + // YAML ending document boundary marker + _, err := fmt.Fprintln(w, "...") + return err + } + if len(i.opts.Output) > 0 { + switch i.opts.Output { + case "json": + var body string + var err error + if body, err = installer.DeploymentManifest(&i.opts); err != nil { return err } - if _, err := fmt.Fprint(w, body); err != nil { + jsonb, err := yaml.ToJSON([]byte(body)) + if err != nil { return err } - if !last { - return nil - } - // YAML ending document boundary marker - _, err := fmt.Fprintln(w, "...") - return err + jsons := string(jsonb) + jsons = "{\"apiVersion\":\"extensions/v1beta1\",\"kind\":\"Deployment\"," + jsons[1:] + fmt.Fprint(i.out, jsons) + + return nil + default: + return fmt.Errorf("Unknown output format: %s", i.opts.Output) } + } + if settings.Debug { var body string var err error diff --git a/cmd/helm/installer/install.go b/cmd/helm/installer/install.go index 7e8707fc8..826d49496 100644 --- a/cmd/helm/installer/install.go +++ b/cmd/helm/installer/install.go @@ -19,6 +19,8 @@ package installer // import "k8s.io/helm/cmd/helm/installer" import ( "io/ioutil" + "strings" + "github.com/ghodss/yaml" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -116,8 +118,26 @@ func generateLabels(labels map[string]string) map[string]string { return labels } +// parseNodeSelectors takes a comma delimited list of key=values pairs and returns a map +func parseNodeSelectors(labels string) map[string]string { + kv := strings.Split(labels, ",") + nodeSelectors := map[string]string{} + for _, v := range kv { + el := strings.Split(v, "=") + if len(el) == 2 { + nodeSelectors[el[0]] = el[1] + } + } + + return nodeSelectors +} + func generateDeployment(opts *Options) *v1beta1.Deployment { labels := generateLabels(map[string]string{"name": "tiller"}) + nodeSelectors := map[string]string{} + if len(opts.NodeSelectors) > 0 { + nodeSelectors = parseNodeSelectors(opts.NodeSelectors) + } d := &v1beta1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: opts.Namespace, @@ -164,10 +184,8 @@ func generateDeployment(opts *Options) *v1beta1.Deployment { }, }, }, - HostNetwork: opts.EnableHostNetwork, - NodeSelector: map[string]string{ - "beta.kubernetes.io/os": "linux", - }, + HostNetwork: opts.EnableHostNetwork, + NodeSelector: nodeSelectors, }, }, }, @@ -203,6 +221,7 @@ func generateDeployment(opts *Options) *v1beta1.Deployment { }, }) } + return d } diff --git a/cmd/helm/installer/options.go b/cmd/helm/installer/options.go index ddb7706f8..bd08badd5 100644 --- a/cmd/helm/installer/options.go +++ b/cmd/helm/installer/options.go @@ -71,6 +71,12 @@ type Options struct { // EnableHostNetwork installs Tiller with net=host. EnableHostNetwork bool + + // NodeSelectors determine which nodes Tiller can land on + NodeSelectors string + + // Output dumps the Tiller manifest in the specified format (e.g. json) but skips Helm/Tiller installation + Output string } func (opts *Options) selectImage() string {