github.com/pensu/helm@v2.6.1+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 "io/ioutil" 21 22 "github.com/ghodss/yaml" 23 apierrors "k8s.io/apimachinery/pkg/api/errors" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/util/intstr" 26 "k8s.io/client-go/kubernetes" 27 corev1 "k8s.io/client-go/kubernetes/typed/core/v1" 28 extensionsclient "k8s.io/client-go/kubernetes/typed/extensions/v1beta1" 29 "k8s.io/client-go/pkg/api/v1" 30 "k8s.io/client-go/pkg/apis/extensions/v1beta1" 31 ) 32 33 // Install uses Kubernetes client to install Tiller. 34 // 35 // Returns an error if the command failed. 36 func Install(client kubernetes.Interface, opts *Options) error { 37 if err := createDeployment(client.Extensions(), opts); err != nil { 38 return err 39 } 40 if err := createService(client.Core(), opts.Namespace); err != nil { 41 return err 42 } 43 if opts.tls() { 44 if err := createSecret(client.Core(), opts); err != nil { 45 return err 46 } 47 } 48 return nil 49 } 50 51 // Upgrade uses Kubernetes client to upgrade Tiller to current version. 52 // 53 // Returns an error if the command failed. 54 func Upgrade(client kubernetes.Interface, opts *Options) error { 55 obj, err := client.Extensions().Deployments(opts.Namespace).Get(deploymentName, metav1.GetOptions{}) 56 if err != nil { 57 return err 58 } 59 obj.Spec.Template.Spec.Containers[0].Image = opts.selectImage() 60 obj.Spec.Template.Spec.Containers[0].ImagePullPolicy = opts.pullPolicy() 61 obj.Spec.Template.Spec.ServiceAccountName = opts.ServiceAccount 62 if _, err := client.Extensions().Deployments(opts.Namespace).Update(obj); err != nil { 63 return err 64 } 65 // If the service does not exists that would mean we are upgrading from a Tiller version 66 // that didn't deploy the service, so install it. 67 _, err = client.Core().Services(opts.Namespace).Get(serviceName, metav1.GetOptions{}) 68 if apierrors.IsNotFound(err) { 69 return createService(client.Core(), opts.Namespace) 70 } 71 return err 72 } 73 74 // createDeployment creates the Tiller Deployment resource. 75 func createDeployment(client extensionsclient.DeploymentsGetter, opts *Options) error { 76 obj := deployment(opts) 77 _, err := client.Deployments(obj.Namespace).Create(obj) 78 return err 79 } 80 81 // deployment gets the deployment object that installs Tiller. 82 func deployment(opts *Options) *v1beta1.Deployment { 83 return generateDeployment(opts) 84 } 85 86 // createService creates the Tiller service resource 87 func createService(client corev1.ServicesGetter, namespace string) error { 88 obj := service(namespace) 89 _, err := client.Services(obj.Namespace).Create(obj) 90 return err 91 } 92 93 // service gets the service object that installs Tiller. 94 func service(namespace string) *v1.Service { 95 return generateService(namespace) 96 } 97 98 // DeploymentManifest gets the manifest (as a string) that describes the Tiller Deployment 99 // resource. 100 func DeploymentManifest(opts *Options) (string, error) { 101 obj := deployment(opts) 102 buf, err := yaml.Marshal(obj) 103 return string(buf), err 104 } 105 106 // ServiceManifest gets the manifest (as a string) that describes the Tiller Service 107 // resource. 108 func ServiceManifest(namespace string) (string, error) { 109 obj := service(namespace) 110 buf, err := yaml.Marshal(obj) 111 return string(buf), err 112 } 113 114 func generateLabels(labels map[string]string) map[string]string { 115 labels["app"] = "helm" 116 return labels 117 } 118 119 func generateDeployment(opts *Options) *v1beta1.Deployment { 120 labels := generateLabels(map[string]string{"name": "tiller"}) 121 d := &v1beta1.Deployment{ 122 ObjectMeta: metav1.ObjectMeta{ 123 Namespace: opts.Namespace, 124 Name: deploymentName, 125 Labels: labels, 126 }, 127 Spec: v1beta1.DeploymentSpec{ 128 Template: v1.PodTemplateSpec{ 129 ObjectMeta: metav1.ObjectMeta{ 130 Labels: labels, 131 }, 132 Spec: v1.PodSpec{ 133 ServiceAccountName: opts.ServiceAccount, 134 Containers: []v1.Container{ 135 { 136 Name: "tiller", 137 Image: opts.selectImage(), 138 ImagePullPolicy: opts.pullPolicy(), 139 Ports: []v1.ContainerPort{ 140 {ContainerPort: 44134, Name: "tiller"}, 141 }, 142 Env: []v1.EnvVar{ 143 {Name: "TILLER_NAMESPACE", Value: opts.Namespace}, 144 }, 145 LivenessProbe: &v1.Probe{ 146 Handler: v1.Handler{ 147 HTTPGet: &v1.HTTPGetAction{ 148 Path: "/liveness", 149 Port: intstr.FromInt(44135), 150 }, 151 }, 152 InitialDelaySeconds: 1, 153 TimeoutSeconds: 1, 154 }, 155 ReadinessProbe: &v1.Probe{ 156 Handler: v1.Handler{ 157 HTTPGet: &v1.HTTPGetAction{ 158 Path: "/readiness", 159 Port: intstr.FromInt(44135), 160 }, 161 }, 162 InitialDelaySeconds: 1, 163 TimeoutSeconds: 1, 164 }, 165 }, 166 }, 167 HostNetwork: opts.EnableHostNetwork, 168 NodeSelector: map[string]string{ 169 "beta.kubernetes.io/os": "linux", 170 }, 171 }, 172 }, 173 }, 174 } 175 176 if opts.tls() { 177 const certsDir = "/etc/certs" 178 179 var tlsVerify, tlsEnable = "", "1" 180 if opts.VerifyTLS { 181 tlsVerify = "1" 182 } 183 184 // Mount secret to "/etc/certs" 185 d.Spec.Template.Spec.Containers[0].VolumeMounts = append(d.Spec.Template.Spec.Containers[0].VolumeMounts, v1.VolumeMount{ 186 Name: "tiller-certs", 187 ReadOnly: true, 188 MountPath: certsDir, 189 }) 190 // Add environment variable required for enabling TLS 191 d.Spec.Template.Spec.Containers[0].Env = append(d.Spec.Template.Spec.Containers[0].Env, []v1.EnvVar{ 192 {Name: "TILLER_TLS_VERIFY", Value: tlsVerify}, 193 {Name: "TILLER_TLS_ENABLE", Value: tlsEnable}, 194 {Name: "TILLER_TLS_CERTS", Value: certsDir}, 195 }...) 196 // Add secret volume to deployment 197 d.Spec.Template.Spec.Volumes = append(d.Spec.Template.Spec.Volumes, v1.Volume{ 198 Name: "tiller-certs", 199 VolumeSource: v1.VolumeSource{ 200 Secret: &v1.SecretVolumeSource{ 201 SecretName: "tiller-secret", 202 }, 203 }, 204 }) 205 } 206 return d 207 } 208 209 func generateService(namespace string) *v1.Service { 210 labels := generateLabels(map[string]string{"name": "tiller"}) 211 s := &v1.Service{ 212 ObjectMeta: metav1.ObjectMeta{ 213 Namespace: namespace, 214 Name: serviceName, 215 Labels: labels, 216 }, 217 Spec: v1.ServiceSpec{ 218 Type: v1.ServiceTypeClusterIP, 219 Ports: []v1.ServicePort{ 220 { 221 Name: "tiller", 222 Port: 44134, 223 TargetPort: intstr.FromString("tiller"), 224 }, 225 }, 226 Selector: labels, 227 }, 228 } 229 return s 230 } 231 232 // SecretManifest gets the manifest (as a string) that describes the Tiller Secret resource. 233 func SecretManifest(opts *Options) (string, error) { 234 o, err := generateSecret(opts) 235 if err != nil { 236 return "", err 237 } 238 buf, err := yaml.Marshal(o) 239 return string(buf), err 240 } 241 242 // createSecret creates the Tiller secret resource. 243 func createSecret(client corev1.SecretsGetter, opts *Options) error { 244 o, err := generateSecret(opts) 245 if err != nil { 246 return err 247 } 248 _, err = client.Secrets(o.Namespace).Create(o) 249 return err 250 } 251 252 // generateSecret builds the secret object that hold Tiller secrets. 253 func generateSecret(opts *Options) (*v1.Secret, error) { 254 255 labels := generateLabels(map[string]string{"name": "tiller"}) 256 secret := &v1.Secret{ 257 Type: v1.SecretTypeOpaque, 258 Data: make(map[string][]byte), 259 ObjectMeta: metav1.ObjectMeta{ 260 Name: secretName, 261 Labels: labels, 262 Namespace: opts.Namespace, 263 }, 264 } 265 var err error 266 if secret.Data["tls.key"], err = read(opts.TLSKeyFile); err != nil { 267 return nil, err 268 } 269 if secret.Data["tls.crt"], err = read(opts.TLSCertFile); err != nil { 270 return nil, err 271 } 272 if opts.VerifyTLS { 273 if secret.Data["ca.crt"], err = read(opts.TLSCaCertFile); err != nil { 274 return nil, err 275 } 276 } 277 return secret, nil 278 } 279 280 func read(path string) (b []byte, err error) { return ioutil.ReadFile(path) }