Jun Hu | 9e45abc | 2018-01-17 17:07:36 -0500 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | # ============LICENSE_START========================================== |
| 4 | # =================================================================== |
Jun (Nicolas) Hu | 8cbcb30 | 2018-02-21 14:18:44 -0500 | [diff] [blame] | 5 | # Copyright (c) 2017 AT&T |
Jun Hu | 9e45abc | 2018-01-17 17:07:36 -0500 | [diff] [blame] | 6 | # |
| 7 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 8 | # you may not use this file except in compliance with the License. |
| 9 | # You may obtain a copy of the License at |
| 10 | # |
| 11 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | # |
| 13 | # Unless required by applicable law or agreed to in writing, software |
| 14 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | # See the License for the specific language governing permissions and |
| 17 | # limitations under the License. |
| 18 | #============LICENSE_END============================================ |
| 19 | |
| 20 | # This script will be executed on Kubernetes master host. It will initialize the master, and install a pod network. |
| 21 | |
| 22 | import pwd |
| 23 | import grp |
| 24 | import os |
| 25 | import re |
| 26 | import getpass |
| 27 | import subprocess |
| 28 | from cloudify import ctx |
| 29 | from cloudify.exceptions import OperationRetry |
| 30 | from cloudify_rest_client.exceptions import CloudifyClientError |
| 31 | |
| 32 | JOIN_COMMAND_REGEX = '^kubeadm join[\sA-Za-z0-9\.\:\-\_]*' |
| 33 | BOOTSTRAP_TOKEN_REGEX = '[a-z0-9]{6}.[a-z0-9]{16}' |
| 34 | IP_PORT_REGEX = '[0-9]+(?:\.[0-9]+){3}:[0-9]+' |
| 35 | NOT_SHA_REGEX='^(?!.*sha256)' |
| 36 | JCRE_COMPILED = re.compile(JOIN_COMMAND_REGEX) |
| 37 | BTRE_COMPILED = re.compile(BOOTSTRAP_TOKEN_REGEX) |
| 38 | IPRE_COMPILED = re.compile(IP_PORT_REGEX) |
| 39 | SHA_COMPILED=re.compile(NOT_SHA_REGEX) |
| 40 | |
| 41 | def execute_command(_command): |
| 42 | |
| 43 | ctx.logger.debug('_command {0}.'.format(_command)) |
| 44 | |
| 45 | subprocess_args = { |
| 46 | 'args': _command.split(), |
| 47 | 'stdout': subprocess.PIPE, |
| 48 | 'stderr': subprocess.PIPE |
| 49 | } |
| 50 | |
| 51 | ctx.logger.debug('subprocess_args {0}.'.format(subprocess_args)) |
| 52 | |
| 53 | process = subprocess.Popen(**subprocess_args) |
| 54 | output, error = process.communicate() |
| 55 | |
| 56 | ctx.logger.debug('command: {0} '.format(_command)) |
| 57 | ctx.logger.debug('output: {0} '.format(output)) |
| 58 | ctx.logger.debug('error: {0} '.format(error)) |
| 59 | ctx.logger.debug('process.returncode: {0} '.format(process.returncode)) |
| 60 | |
| 61 | if process.returncode: |
| 62 | ctx.logger.error('Running `{0}` returns error.'.format(_command)) |
| 63 | return False |
| 64 | |
| 65 | return output |
| 66 | |
| 67 | |
| 68 | def cleanup_and_retry(): |
| 69 | reset_cluster_command = 'sudo kubeadm reset' |
| 70 | output = execute_command(reset_cluster_command) |
| 71 | ctx.logger.info('reset_cluster_command {1}'.format(reset_cluster_command, output)) |
| 72 | raise OperationRetry('Restarting kubernetes because of a problem.') |
| 73 | |
| 74 | |
| 75 | def configure_admin_conf(): |
| 76 | # Add the kubeadmin config to environment |
| 77 | agent_user = getpass.getuser() |
| 78 | uid = pwd.getpwnam(agent_user).pw_uid |
| 79 | gid = grp.getgrnam('docker').gr_gid |
| 80 | admin_file_dest = os.path.join(os.path.expanduser('~'), 'admin.conf') |
| 81 | |
| 82 | execute_command('sudo cp {0} {1}'.format('/etc/kubernetes/admin.conf', admin_file_dest)) |
| 83 | execute_command('sudo chown {0}:{1} {2}'.format(uid, gid, admin_file_dest)) |
| 84 | |
| 85 | with open(os.path.join(os.path.expanduser('~'), '.bashrc'), 'a') as outfile: |
| 86 | outfile.write('export KUBECONFIG=$HOME/admin.conf') |
| 87 | os.environ['KUBECONFIG'] = admin_file_dest |
| 88 | |
| 89 | |
| 90 | def setup_secrets(_split_master_port, _bootstrap_token): |
| 91 | master_ip = split_master_port[0] |
| 92 | master_port = split_master_port[1] |
| 93 | ctx.instance.runtime_properties['master_ip'] = _split_master_port[0] |
| 94 | ctx.instance.runtime_properties['master_port'] = _split_master_port[1] |
| 95 | ctx.instance.runtime_properties['bootstrap_token'] = _bootstrap_token |
| 96 | from cloudify import manager |
| 97 | cfy_client = manager.get_rest_client() |
| 98 | |
| 99 | _secret_key = 'kubernetes_master_ip' |
| 100 | if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: |
| 101 | cfy_client.secrets.create(key=_secret_key, value=master_ip) |
| 102 | else: |
| 103 | cfy_client.secrets.update(key=_secret_key, value=master_ip) |
| 104 | ctx.logger.info('Set secret: {0}.'.format(_secret_key)) |
| 105 | |
| 106 | _secret_key = 'kubernetes_master_port' |
| 107 | if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: |
| 108 | cfy_client.secrets.create(key=_secret_key, value=master_port) |
| 109 | else: |
| 110 | cfy_client.secrets.update(key=_secret_key, value=master_port) |
| 111 | ctx.logger.info('Set secret: {0}.'.format(_secret_key)) |
| 112 | |
| 113 | _secret_key = 'bootstrap_token' |
| 114 | if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: |
| 115 | cfy_client.secrets.create(key=_secret_key, value=_bootstrap_token) |
| 116 | else: |
| 117 | cfy_client.secrets.update(key=_secret_key, value=_bootstrap_token) |
| 118 | ctx.logger.info('Set secret: {0}.'.format(_secret_key)) |
| 119 | |
| 120 | |
| 121 | if __name__ == '__main__': |
| 122 | |
| 123 | ctx.instance.runtime_properties['KUBERNETES_MASTER'] = True |
| 124 | cniCommand1=subprocess.Popen(["sudo", "sysctl", 'net.bridge.bridge-nf-call-iptables=1'], stdout=subprocess.PIPE) |
| 125 | # Start Kubernetes Master |
| 126 | ctx.logger.info('Attempting to start Kubernetes master.') |
| 127 | start_master_command = 'sudo kubeadm init' |
| 128 | start_output = execute_command(start_master_command) |
| 129 | ctx.logger.debug('start_master_command output: {0}'.format(start_output)) |
| 130 | # Check if start succeeded. |
| 131 | if start_output is False or not isinstance(start_output, basestring): |
| 132 | ctx.logger.error('Kubernetes master failed to start.') |
| 133 | cleanup_and_retry() |
| 134 | ctx.logger.info('Kubernetes master started successfully.') |
| 135 | |
| 136 | # Slice and dice the start_master_command start_output. |
| 137 | ctx.logger.info('Attempting to retrieve Kubernetes cluster information.') |
| 138 | split_start_output = \ |
| 139 | [line.strip() for line in start_output.split('\n') if line.strip()] |
| 140 | del line |
| 141 | |
| 142 | ctx.logger.debug( |
| 143 | 'Kubernetes master start output, split and stripped: {0}'.format( |
| 144 | split_start_output)) |
| 145 | split_join_command = '' |
| 146 | for li in split_start_output: |
| 147 | ctx.logger.debug('li in split_start_output: {0}'.format(li)) |
| 148 | if re.match(JCRE_COMPILED, li): |
| 149 | split_join_command = re.split('\s', li) |
| 150 | del li |
| 151 | ctx.logger.info('split_join_command: {0}'.format(split_join_command)) |
| 152 | |
| 153 | if not split_join_command: |
| 154 | ctx.logger.error('No join command in split_start_output: {0}'.format(split_join_command)) |
| 155 | cleanup_and_retry() |
| 156 | |
| 157 | for li in split_join_command: |
| 158 | ctx.logger.info('Sorting bits and pieces: li: {0}'.format(li)) |
| 159 | if (re.match(BTRE_COMPILED, li) and re.match(SHA_COMPILED, li)): |
| 160 | bootstrap_token = li |
| 161 | elif re.match(IPRE_COMPILED, li): |
| 162 | split_master_port = li.split(':') |
| 163 | setup_secrets(split_master_port, bootstrap_token) |
| 164 | configure_admin_conf() |
| 165 | |
| 166 | weaveCommand1=subprocess.Popen(["kubectl", "version"], stdout=subprocess.PIPE) |
| 167 | weaveCommand2=subprocess.Popen(["base64"],stdin=weaveCommand1.stdout, stdout=subprocess.PIPE) |
| 168 | kubever = weaveCommand2.communicate()[0] |
| 169 | kubever = kubever.replace('\n', '').replace('\r', '') |
| 170 | ctx.logger.info("kubever :"+kubever) |
| 171 | weaveURL=('https://cloud.weave.works/k8s/net?k8s-version={0}'.format(kubever)) |
| 172 | ctx.logger.info("weaveURL:" + weaveURL) |
| 173 | weaveCommand4=subprocess.Popen(["kubectl","apply","-f",weaveURL],stdout=subprocess.PIPE) |
| 174 | weaveResult= weaveCommand4.communicate()[0] |
| 175 | ctx.logger.info("weaveResult :"+weaveResult) |