mirror of https://github.com/kubernetes/kops.git
				
				
				
			
		
			
				
	
	
		
			225 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
| Copyright 2016 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package model
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"text/template"
 | |
| 
 | |
| 	"github.com/ghodss/yaml"
 | |
| 
 | |
| 	"k8s.io/kops/pkg/apis/kops"
 | |
| 	"k8s.io/kops/pkg/apis/nodeup"
 | |
| 	"k8s.io/kops/pkg/model/resources"
 | |
| 	"k8s.io/kops/upup/pkg/fi"
 | |
| )
 | |
| 
 | |
| // BootstrapScript creates the bootstrap script
 | |
| type BootstrapScript struct {
 | |
| 	NodeUpSource        string
 | |
| 	NodeUpSourceHash    string
 | |
| 	NodeUpConfigBuilder func(ig *kops.InstanceGroup) (*nodeup.Config, error)
 | |
| }
 | |
| 
 | |
| // ResourceNodeUp generates and returns a nodeup (bootstrap) script from a
 | |
| // template file, substituting in specific env vars & cluster spec configuration
 | |
| func (b *BootstrapScript) ResourceNodeUp(ig *kops.InstanceGroup, cs *kops.ClusterSpec) (*fi.ResourceHolder, error) {
 | |
| 	if ig.Spec.Role == kops.InstanceGroupRoleBastion {
 | |
| 		// Bastions are just bare machines (currently), used as SSH jump-hosts
 | |
| 		return nil, nil
 | |
| 	}
 | |
| 
 | |
| 	functions := template.FuncMap{
 | |
| 		"NodeUpSource": func() string {
 | |
| 			return b.NodeUpSource
 | |
| 		},
 | |
| 		"NodeUpSourceHash": func() string {
 | |
| 			return b.NodeUpSourceHash
 | |
| 		},
 | |
| 		"KubeEnv": func() (string, error) {
 | |
| 			config, err := b.NodeUpConfigBuilder(ig)
 | |
| 			if err != nil {
 | |
| 				return "", err
 | |
| 			}
 | |
| 
 | |
| 			data, err := kops.ToRawYaml(config)
 | |
| 			if err != nil {
 | |
| 				return "", err
 | |
| 			}
 | |
| 
 | |
| 			return string(data), nil
 | |
| 		},
 | |
| 
 | |
| 		// Pass in extra environment variables for user-defined S3 service
 | |
| 		"S3Env": func() string {
 | |
| 			if os.Getenv("S3_ENDPOINT") != "" {
 | |
| 				return fmt.Sprintf("export S3_ENDPOINT=%s\nexport S3_REGION=%s\nexport S3_ACCESS_KEY_ID=%s\nexport S3_SECRET_ACCESS_KEY=%s\n",
 | |
| 					os.Getenv("S3_ENDPOINT"),
 | |
| 					os.Getenv("S3_REGION"),
 | |
| 					os.Getenv("S3_ACCESS_KEY_ID"),
 | |
| 					os.Getenv("S3_SECRET_ACCESS_KEY"))
 | |
| 			}
 | |
| 			return ""
 | |
| 		},
 | |
| 
 | |
| 		"ProxyEnv": func() string {
 | |
| 			return b.createProxyEnv(cs.EgressProxy)
 | |
| 		},
 | |
| 		"AWS_REGION": func() string {
 | |
| 			if os.Getenv("AWS_REGION") != "" {
 | |
| 				return fmt.Sprintf("export AWS_REGION=%s\n",
 | |
| 					os.Getenv("AWS_REGION"))
 | |
| 			}
 | |
| 			return ""
 | |
| 		},
 | |
| 
 | |
| 		"ClusterSpec": func() (string, error) {
 | |
| 			spec := make(map[string]interface{})
 | |
| 			spec["cloudConfig"] = cs.CloudConfig
 | |
| 			spec["docker"] = cs.Docker
 | |
| 			spec["kubelet"] = cs.Kubelet
 | |
| 			spec["kubeProxy"] = cs.KubeProxy
 | |
| 
 | |
| 			if ig.IsMaster() {
 | |
| 				spec["kubeAPIServer"] = cs.KubeAPIServer
 | |
| 				spec["kubeControllerManager"] = cs.KubeControllerManager
 | |
| 				spec["kubeScheduler"] = cs.KubeScheduler
 | |
| 				spec["masterKubelet"] = cs.MasterKubelet
 | |
| 			}
 | |
| 
 | |
| 			hooks := b.getRelevantHooks(cs.Hooks, ig.Spec.Role)
 | |
| 			if len(hooks) > 0 {
 | |
| 				spec["hooks"] = hooks
 | |
| 			}
 | |
| 
 | |
| 			content, err := yaml.Marshal(spec)
 | |
| 			if err != nil {
 | |
| 				return "", fmt.Errorf("error converting cluster spec to yaml for inclusion within bootstrap script: %v", err)
 | |
| 			}
 | |
| 			return string(content), nil
 | |
| 		},
 | |
| 
 | |
| 		"IGSpec": func() (string, error) {
 | |
| 			spec := make(map[string]interface{})
 | |
| 			spec["kubelet"] = ig.Spec.Kubelet
 | |
| 			spec["nodeLabels"] = ig.Spec.NodeLabels
 | |
| 			spec["taints"] = ig.Spec.Taints
 | |
| 			hooks := b.getRelevantHooks(ig.Spec.Hooks, ig.Spec.Role)
 | |
| 			if len(hooks) > 0 {
 | |
| 				spec["hooks"] = hooks
 | |
| 			}
 | |
| 
 | |
| 			content, err := yaml.Marshal(spec)
 | |
| 			if err != nil {
 | |
| 				return "", fmt.Errorf("error converting instancegroup spec to yaml for inclusion within bootstrap script: %v", err)
 | |
| 			}
 | |
| 			return string(content), nil
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	templateResource, err := NewTemplateResource("nodeup", resources.AWSNodeUpTemplate, functions, nil)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return fi.WrapResource(templateResource), nil
 | |
| }
 | |
| 
 | |
| // getRelevantHooks returns a list of hooks to be applied to the instance group
 | |
| func (b *BootstrapScript) getRelevantHooks(hooks []kops.HookSpec, role kops.InstanceGroupRole) []kops.HookSpec {
 | |
| 	relevantHooks := []kops.HookSpec{}
 | |
| 	for _, hook := range hooks {
 | |
| 		if len(hook.Roles) == 0 {
 | |
| 			relevantHooks = append(relevantHooks, hook)
 | |
| 			continue
 | |
| 		}
 | |
| 		for _, hookRole := range hook.Roles {
 | |
| 			if role == hookRole {
 | |
| 				relevantHooks = append(relevantHooks, hook)
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return relevantHooks
 | |
| }
 | |
| 
 | |
| func (b *BootstrapScript) createProxyEnv(ps *kops.EgressProxySpec) string {
 | |
| 	var buffer bytes.Buffer
 | |
| 
 | |
| 	if ps != nil && ps.HTTPProxy.Host != "" {
 | |
| 		var httpProxyURL string
 | |
| 
 | |
| 		// TODO double check that all the code does this
 | |
| 		// TODO move this into a validate so we can enforce the string syntax
 | |
| 		if !strings.HasPrefix(ps.HTTPProxy.Host, "http://") {
 | |
| 			httpProxyURL = "http://"
 | |
| 		}
 | |
| 
 | |
| 		if ps.HTTPProxy.Port != 0 {
 | |
| 			httpProxyURL += ps.HTTPProxy.Host + ":" + strconv.Itoa(ps.HTTPProxy.Port)
 | |
| 		} else {
 | |
| 			httpProxyURL += ps.HTTPProxy.Host
 | |
| 		}
 | |
| 
 | |
| 		// Set base env variables
 | |
| 		buffer.WriteString("export http_proxy=" + httpProxyURL + "\n")
 | |
| 		buffer.WriteString("export https_proxy=${http_proxy}\n")
 | |
| 		buffer.WriteString("export no_proxy=" + ps.ProxyExcludes + "\n")
 | |
| 		buffer.WriteString("export NO_PROXY=${no_proxy}\n")
 | |
| 
 | |
| 		// TODO move the rest of this configuration work to nodeup
 | |
| 
 | |
| 		// Set env variables for docker
 | |
| 		buffer.WriteString("echo \"export http_proxy=${http_proxy}\" >> /etc/default/docker\n")
 | |
| 		buffer.WriteString("echo \"export https_proxy=${http_proxy}\" >> /etc/default/docker\n")
 | |
| 		buffer.WriteString("echo \"export no_proxy=${no_proxy}\" >> /etc/default/docker\n")
 | |
| 		buffer.WriteString("echo \"export NO_PROXY=${no_proxy}\" >> /etc/default/docker\n")
 | |
| 
 | |
| 		// Set env variables for base environment
 | |
| 		buffer.WriteString("echo \"export http_proxy=${http_proxy}\" >> /etc/environment\n")
 | |
| 		buffer.WriteString("echo \"export https_proxy=${http_proxy}\" >> /etc/environment\n")
 | |
| 		buffer.WriteString("echo \"export no_proxy=${no_proxy}\" >> /etc/environment\n")
 | |
| 		buffer.WriteString("echo \"export NO_PROXY=${no_proxy}\" >> /etc/environment\n")
 | |
| 
 | |
| 		// Set env variables to systemd
 | |
| 		buffer.WriteString("echo DefaultEnvironment=\\\"http_proxy=${http_proxy}\\\" \\\"https_proxy=${http_proxy}\\\"")
 | |
| 		buffer.WriteString("echo DefaultEnvironment=\\\"http_proxy=${http_proxy}\\\" \\\"https_proxy=${http_proxy}\\\"")
 | |
| 		buffer.WriteString(" \\\"NO_PROXY=${no_proxy}\\\" \\\"no_proxy=${no_proxy}\\\"")
 | |
| 		buffer.WriteString(" >> /etc/systemd/system.conf\n")
 | |
| 
 | |
| 		// source in the environment this step ensures that environment file is correct
 | |
| 		buffer.WriteString("source /etc/environment\n")
 | |
| 
 | |
| 		// Restart stuff
 | |
| 		buffer.WriteString("systemctl daemon-reload\n")
 | |
| 		buffer.WriteString("systemctl daemon-reexec\n")
 | |
| 
 | |
| 		// TODO do we need no_proxy in these as well??
 | |
| 		// TODO handle CoreOS
 | |
| 		// Depending on OS set package manager proxy settings
 | |
| 		buffer.WriteString("if [ -f /etc/lsb-release ] || [ -f /etc/debian_version ]; then\n")
 | |
| 		buffer.WriteString("    echo \"Acquire::http::Proxy \\\"${http_proxy}\\\";\" > /etc/apt/apt.conf.d/30proxy\n")
 | |
| 		buffer.WriteString("elif [ -f /etc/redhat-release ]; then\n")
 | |
| 		buffer.WriteString("  echo \"http_proxy=${http_proxy}\" >> /etc/yum.conf\n")
 | |
| 		buffer.WriteString("fi\n")
 | |
| 	}
 | |
| 	return buffer.String()
 | |
| }
 |