github.com/cloudposse/helm@v2.2.3+incompatible/cmd/helm/installer/install.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package installer // import "k8s.io/helm/cmd/helm/installer" 18 19 import ( 20 "fmt" 21 22 "github.com/ghodss/yaml" 23 24 "k8s.io/kubernetes/pkg/api" 25 kerrors "k8s.io/kubernetes/pkg/api/errors" 26 "k8s.io/kubernetes/pkg/apis/extensions" 27 "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" 28 "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" 29 extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion" 30 "k8s.io/kubernetes/pkg/util/intstr" 31 32 "k8s.io/helm/pkg/version" 33 ) 34 35 const defaultImage = "gcr.io/kubernetes-helm/tiller" 36 37 // Install uses kubernetes client to install tiller 38 // 39 // Returns the string output received from the operation, and an error if the 40 // command failed. 41 // 42 // If verbose is true, this will print the manifest to stdout. 43 func Install(client internalclientset.Interface, namespace, image string, canary, verbose bool) error { 44 if err := createDeployment(client.Extensions(), namespace, image, canary); err != nil { 45 return err 46 } 47 if err := createService(client.Core(), namespace); err != nil { 48 return err 49 } 50 return nil 51 } 52 53 // 54 // Upgrade uses kubernetes client to upgrade tiller to current version 55 // 56 // Returns an error if the command failed. 57 func Upgrade(client internalclientset.Interface, namespace, image string, canary bool) error { 58 obj, err := client.Extensions().Deployments(namespace).Get("tiller-deploy") 59 if err != nil { 60 return err 61 } 62 obj.Spec.Template.Spec.Containers[0].Image = selectImage(image, canary) 63 if _, err := client.Extensions().Deployments(namespace).Update(obj); err != nil { 64 return err 65 } 66 // If the service does not exists that would mean we are upgrading from a tiller version 67 // that didn't deploy the service, so install it. 68 if _, err := client.Core().Services(namespace).Get("tiller-deploy"); err != nil { 69 if !kerrors.IsNotFound(err) { 70 return err 71 } 72 if err := createService(client.Core(), namespace); err != nil { 73 return err 74 } 75 } 76 return nil 77 } 78 79 // createDeployment creates the Tiller deployment reource 80 func createDeployment(client extensionsclient.DeploymentsGetter, namespace, image string, canary bool) error { 81 obj := deployment(namespace, image, canary) 82 _, err := client.Deployments(obj.Namespace).Create(obj) 83 return err 84 } 85 86 // deployment gets the deployment object that installs Tiller. 87 func deployment(namespace, image string, canary bool) *extensions.Deployment { 88 return generateDeployment(namespace, selectImage(image, canary)) 89 } 90 91 // createService creates the Tiller service resource 92 func createService(client internalversion.ServicesGetter, namespace string) error { 93 obj := service(namespace) 94 _, err := client.Services(obj.Namespace).Create(obj) 95 return err 96 } 97 98 // service gets the service object that installs Tiller. 99 func service(namespace string) *api.Service { 100 return generateService(namespace) 101 } 102 103 func selectImage(image string, canary bool) string { 104 switch { 105 case canary: 106 image = defaultImage + ":canary" 107 case image == "": 108 image = fmt.Sprintf("%s:%s", defaultImage, version.Version) 109 } 110 return image 111 } 112 113 // DeploymentManifest gets the manifest (as a string) that describes the Tiller Deployment 114 // resource. 115 func DeploymentManifest(namespace, image string, canary bool) (string, error) { 116 obj := deployment(namespace, image, canary) 117 118 buf, err := yaml.Marshal(obj) 119 return string(buf), err 120 } 121 122 // ServiceManifest gets the manifest (as a string) that describes the Tiller Service 123 // resource. 124 func ServiceManifest(namespace string) (string, error) { 125 obj := service(namespace) 126 127 buf, err := yaml.Marshal(obj) 128 return string(buf), err 129 } 130 131 func generateLabels(labels map[string]string) map[string]string { 132 labels["app"] = "helm" 133 return labels 134 } 135 136 func generateDeployment(namespace, image string) *extensions.Deployment { 137 labels := generateLabels(map[string]string{"name": "tiller"}) 138 d := &extensions.Deployment{ 139 ObjectMeta: api.ObjectMeta{ 140 Namespace: namespace, 141 Name: "tiller-deploy", 142 Labels: labels, 143 }, 144 Spec: extensions.DeploymentSpec{ 145 Replicas: 1, 146 Template: api.PodTemplateSpec{ 147 ObjectMeta: api.ObjectMeta{ 148 Labels: labels, 149 }, 150 Spec: api.PodSpec{ 151 Containers: []api.Container{ 152 { 153 Name: "tiller", 154 Image: image, 155 ImagePullPolicy: "IfNotPresent", 156 Ports: []api.ContainerPort{ 157 {ContainerPort: 44134, Name: "tiller"}, 158 }, 159 Env: []api.EnvVar{ 160 {Name: "TILLER_NAMESPACE", Value: namespace}, 161 }, 162 LivenessProbe: &api.Probe{ 163 Handler: api.Handler{ 164 HTTPGet: &api.HTTPGetAction{ 165 Path: "/liveness", 166 Port: intstr.FromInt(44135), 167 }, 168 }, 169 InitialDelaySeconds: 1, 170 TimeoutSeconds: 1, 171 }, 172 ReadinessProbe: &api.Probe{ 173 Handler: api.Handler{ 174 HTTPGet: &api.HTTPGetAction{ 175 Path: "/readiness", 176 Port: intstr.FromInt(44135), 177 }, 178 }, 179 InitialDelaySeconds: 1, 180 TimeoutSeconds: 1, 181 }, 182 }, 183 }, 184 }, 185 }, 186 }, 187 } 188 return d 189 } 190 191 func generateService(namespace string) *api.Service { 192 labels := generateLabels(map[string]string{"name": "tiller"}) 193 s := &api.Service{ 194 ObjectMeta: api.ObjectMeta{ 195 Namespace: namespace, 196 Name: "tiller-deploy", 197 Labels: labels, 198 }, 199 Spec: api.ServiceSpec{ 200 Type: api.ServiceTypeClusterIP, 201 Ports: []api.ServicePort{ 202 { 203 Name: "tiller", 204 Port: 44134, 205 TargetPort: intstr.FromString("tiller"), 206 }, 207 }, 208 Selector: labels, 209 }, 210 } 211 return s 212 }