diff options
author | Jun Hu <jh245g@att.com> | 2018-01-17 17:07:36 -0500 |
---|---|---|
committer | Jun (Nicolas) Hu <jh245g@att.com> | 2018-02-15 15:19:32 +0000 |
commit | 9e45abcba88ce805260cf16ccebd2fe5e3885822 (patch) | |
tree | 83f211e8468db2208115d98c76c42ca42e3bc636 /TOSCA/kubernetes-cluster-TOSCA/scripts | |
parent | d9f6ecd1c5b5296d8bb198b13430d437a6f7a54a (diff) |
create K8S cluster by TOSCA
Issue-ID: OOM-63
Change-Id: I1506e856328c5fd973a0de140982d8b1bbbac546
Signed-off-by: Nicolas Hu <jh245g@att.com>
Diffstat (limited to 'TOSCA/kubernetes-cluster-TOSCA/scripts')
6 files changed, 581 insertions, 0 deletions
diff --git a/TOSCA/kubernetes-cluster-TOSCA/scripts/create.py b/TOSCA/kubernetes-cluster-TOSCA/scripts/create.py new file mode 100644 index 0000000000..4bb3710f06 --- /dev/null +++ b/TOSCA/kubernetes-cluster-TOSCA/scripts/create.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T +# +# 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. +#============LICENSE_END============================================ + +# This tack will be triggered after VM created. It will check whether docker is up and running. + +import subprocess +from cloudify import ctx +from cloudify.exceptions import OperationRetry + + +def check_command(command): + + try: + process = subprocess.Popen( + command.split() + ) + except OSError: + return False + + output, error = process.communicate() + + ctx.logger.debug('command: {0} '.format(command)) + ctx.logger.debug('output: {0} '.format(output)) + ctx.logger.debug('error: {0} '.format(error)) + ctx.logger.debug('process.returncode: {0} '.format(process.returncode)) + + if process.returncode: + ctx.logger.error('Running `{0}` returns error.'.format(command)) + return False + + return True + + +def execute_command(_command): + + ctx.logger.debug('_command {0}.'.format(_command)) + + subprocess_args = { + 'args': _command.split(), + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE + } + + ctx.logger.debug('subprocess_args {0}.'.format(subprocess_args)) + + process = subprocess.Popen(**subprocess_args) + output, error = process.communicate() + + ctx.logger.debug('command: {0} '.format(_command)) + ctx.logger.debug('error: {0} '.format(error)) + ctx.logger.debug('process.returncode: {0} '.format(process.returncode)) + + if process.returncode: + ctx.logger.error('Running `{0}` returns error.'.format(_command)) + return False + + return output + + +if __name__ == '__main__': + + # Check if Docker PS works + docker = check_command('docker ps') + if not docker: + raise OperationRetry( + 'Docker is not present on the system.') + ctx.logger.info('Docker is present on the system.') + + # Next check if Cloud Init is running. + finished = False + ps = execute_command('ps -ef') + for line in ps.split('\n'): + if '/usr/bin/python /usr/bin/cloud-init modules' in line: + raise OperationRetry( + 'You provided a Cloud-init Cloud Config to configure instances. ' + 'Waiting for Cloud-init to complete.') + ctx.logger.info('Cloud-init finished.') diff --git a/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_master/configure.py b/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_master/configure.py new file mode 100644 index 0000000000..7d5dffcc57 --- /dev/null +++ b/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_master/configure.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python + +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T +# +# 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. +#============LICENSE_END============================================ + +# This script will be executed on Kubernetes master host. It will initialize the master, and install a pod network. + +import pwd +import grp +import os +import re +import getpass +import subprocess +from cloudify import ctx +from cloudify.exceptions import OperationRetry +from cloudify_rest_client.exceptions import CloudifyClientError + +JOIN_COMMAND_REGEX = '^kubeadm join[\sA-Za-z0-9\.\:\-\_]*' +BOOTSTRAP_TOKEN_REGEX = '[a-z0-9]{6}.[a-z0-9]{16}' +IP_PORT_REGEX = '[0-9]+(?:\.[0-9]+){3}:[0-9]+' +NOT_SHA_REGEX='^(?!.*sha256)' +JCRE_COMPILED = re.compile(JOIN_COMMAND_REGEX) +BTRE_COMPILED = re.compile(BOOTSTRAP_TOKEN_REGEX) +IPRE_COMPILED = re.compile(IP_PORT_REGEX) +SHA_COMPILED=re.compile(NOT_SHA_REGEX) + +def execute_command(_command): + + ctx.logger.debug('_command {0}.'.format(_command)) + + subprocess_args = { + 'args': _command.split(), + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE + } + + ctx.logger.debug('subprocess_args {0}.'.format(subprocess_args)) + + process = subprocess.Popen(**subprocess_args) + output, error = process.communicate() + + ctx.logger.debug('command: {0} '.format(_command)) + ctx.logger.debug('output: {0} '.format(output)) + ctx.logger.debug('error: {0} '.format(error)) + ctx.logger.debug('process.returncode: {0} '.format(process.returncode)) + + if process.returncode: + ctx.logger.error('Running `{0}` returns error.'.format(_command)) + return False + + return output + + +def cleanup_and_retry(): + reset_cluster_command = 'sudo kubeadm reset' + output = execute_command(reset_cluster_command) + ctx.logger.info('reset_cluster_command {1}'.format(reset_cluster_command, output)) + raise OperationRetry('Restarting kubernetes because of a problem.') + + +def configure_admin_conf(): + # Add the kubeadmin config to environment + agent_user = getpass.getuser() + uid = pwd.getpwnam(agent_user).pw_uid + gid = grp.getgrnam('docker').gr_gid + admin_file_dest = os.path.join(os.path.expanduser('~'), 'admin.conf') + + execute_command('sudo cp {0} {1}'.format('/etc/kubernetes/admin.conf', admin_file_dest)) + execute_command('sudo chown {0}:{1} {2}'.format(uid, gid, admin_file_dest)) + + with open(os.path.join(os.path.expanduser('~'), '.bashrc'), 'a') as outfile: + outfile.write('export KUBECONFIG=$HOME/admin.conf') + os.environ['KUBECONFIG'] = admin_file_dest + + +def setup_secrets(_split_master_port, _bootstrap_token): + master_ip = split_master_port[0] + master_port = split_master_port[1] + ctx.instance.runtime_properties['master_ip'] = _split_master_port[0] + ctx.instance.runtime_properties['master_port'] = _split_master_port[1] + ctx.instance.runtime_properties['bootstrap_token'] = _bootstrap_token + from cloudify import manager + cfy_client = manager.get_rest_client() + + _secret_key = 'kubernetes_master_ip' + if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: + cfy_client.secrets.create(key=_secret_key, value=master_ip) + else: + cfy_client.secrets.update(key=_secret_key, value=master_ip) + ctx.logger.info('Set secret: {0}.'.format(_secret_key)) + + _secret_key = 'kubernetes_master_port' + if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: + cfy_client.secrets.create(key=_secret_key, value=master_port) + else: + cfy_client.secrets.update(key=_secret_key, value=master_port) + ctx.logger.info('Set secret: {0}.'.format(_secret_key)) + + _secret_key = 'bootstrap_token' + if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: + cfy_client.secrets.create(key=_secret_key, value=_bootstrap_token) + else: + cfy_client.secrets.update(key=_secret_key, value=_bootstrap_token) + ctx.logger.info('Set secret: {0}.'.format(_secret_key)) + + +if __name__ == '__main__': + + ctx.instance.runtime_properties['KUBERNETES_MASTER'] = True + cniCommand1=subprocess.Popen(["sudo", "sysctl", 'net.bridge.bridge-nf-call-iptables=1'], stdout=subprocess.PIPE) + # Start Kubernetes Master + ctx.logger.info('Attempting to start Kubernetes master.') + start_master_command = 'sudo kubeadm init' + start_output = execute_command(start_master_command) + ctx.logger.debug('start_master_command output: {0}'.format(start_output)) + # Check if start succeeded. + if start_output is False or not isinstance(start_output, basestring): + ctx.logger.error('Kubernetes master failed to start.') + cleanup_and_retry() + ctx.logger.info('Kubernetes master started successfully.') + + # Slice and dice the start_master_command start_output. + ctx.logger.info('Attempting to retrieve Kubernetes cluster information.') + split_start_output = \ + [line.strip() for line in start_output.split('\n') if line.strip()] + del line + + ctx.logger.debug( + 'Kubernetes master start output, split and stripped: {0}'.format( + split_start_output)) + split_join_command = '' + for li in split_start_output: + ctx.logger.debug('li in split_start_output: {0}'.format(li)) + if re.match(JCRE_COMPILED, li): + split_join_command = re.split('\s', li) + del li + ctx.logger.info('split_join_command: {0}'.format(split_join_command)) + + if not split_join_command: + ctx.logger.error('No join command in split_start_output: {0}'.format(split_join_command)) + cleanup_and_retry() + + for li in split_join_command: + ctx.logger.info('Sorting bits and pieces: li: {0}'.format(li)) + if (re.match(BTRE_COMPILED, li) and re.match(SHA_COMPILED, li)): + bootstrap_token = li + elif re.match(IPRE_COMPILED, li): + split_master_port = li.split(':') + setup_secrets(split_master_port, bootstrap_token) + configure_admin_conf() + + weaveCommand1=subprocess.Popen(["kubectl", "version"], stdout=subprocess.PIPE) + weaveCommand2=subprocess.Popen(["base64"],stdin=weaveCommand1.stdout, stdout=subprocess.PIPE) + kubever = weaveCommand2.communicate()[0] + kubever = kubever.replace('\n', '').replace('\r', '') + ctx.logger.info("kubever :"+kubever) + weaveURL=('https://cloud.weave.works/k8s/net?k8s-version={0}'.format(kubever)) + ctx.logger.info("weaveURL:" + weaveURL) + weaveCommand4=subprocess.Popen(["kubectl","apply","-f",weaveURL],stdout=subprocess.PIPE) + weaveResult= weaveCommand4.communicate()[0] + ctx.logger.info("weaveResult :"+weaveResult) diff --git a/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_master/start.py b/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_master/start.py new file mode 100644 index 0000000000..bbc166b134 --- /dev/null +++ b/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_master/start.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python + +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T +# +# 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. +#============LICENSE_END============================================ + +#This script will be execute on master host. This script will check whether Kube-DNS is running, and set secrets in cloudify. + +import os +import subprocess +import pip +try: + import yaml +except ImportError: + pip.main(['install', 'pyyaml']) + import yaml + +from cloudify import ctx +from cloudify.exceptions import RecoverableError +from cloudify import manager + + +def execute_command(_command): + + ctx.logger.debug('_command {0}.'.format(_command)) + + subprocess_args = { + 'args': _command.split(), + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE + } + + ctx.logger.debug('subprocess_args {0}.'.format(subprocess_args)) + + process = subprocess.Popen(**subprocess_args) + output, error = process.communicate() + + ctx.logger.debug('command: {0} '.format(_command)) + ctx.logger.debug('output: {0} '.format(output)) + ctx.logger.debug('error: {0} '.format(error)) + ctx.logger.debug('process.returncode: {0} '.format(process.returncode)) + + if process.returncode: + ctx.logger.error('Running `{0}` returns error.'.format(_command)) + return False + + return output + + +def check_kubedns_status(_get_pods): + + ctx.logger.debug('get_pods: {0} '.format(_get_pods)) + + for pod_line in _get_pods.split('\n'): + ctx.logger.debug('pod_line: {0} '.format(pod_line)) + try: + _namespace, _name, _ready, _status, _restarts, _age = pod_line.split() + except ValueError: + pass + else: + if 'kube-dns' in _name and 'Running' not in _status: + return False + elif 'kube-dns' in _name and 'Running' in _status: + return True + return False + + +if __name__ == '__main__': + + cfy_client = manager.get_rest_client() + + # Checking if the Kubernetes DNS service is running (last step). + admin_file_dest = os.path.join(os.path.expanduser('~'), 'admin.conf') + os.environ['KUBECONFIG'] = admin_file_dest + get_pods = execute_command('kubectl get pods --all-namespaces') + if not check_kubedns_status(get_pods): + raise RecoverableError('kube-dns not Running') + + # Storing the K master configuration. + kubernetes_master_config = {} + with open(admin_file_dest, 'r') as outfile: + try: + kubernetes_master_config = yaml.load(outfile) + except yaml.YAMLError as e: + RecoverableError( + 'Unable to read Kubernetes Admin file: {0}: {1}'.format( + admin_file_dest, str(e))) + ctx.instance.runtime_properties['configuration_file_content'] = \ + kubernetes_master_config + + clusters = kubernetes_master_config.get('clusters') + _clusters = {} + for cluster in clusters: + __name = cluster.get('name') + _cluster = cluster.get('cluster', {}) + _secret_key = '%s_certificate_authority_data' % __name + if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: + cfy_client.secrets.create(key=_secret_key, value=_cluster.get('certificate-authority-data')) + ctx.logger.info('Set secret: {0}.'.format(_secret_key)) + else: + cfy_client.secrets.update(key=_secret_key, value=_cluster.get('certificate-authority-data')) + ctx.instance.runtime_properties['%s_certificate_authority_data' % __name] = _cluster.get('certificate-authority-data') + _clusters[__name] = _cluster + del __name + + contexts = kubernetes_master_config.get('contexts') + _contexts = {} + for context in contexts: + __name = context.get('name') + _context = context.get('context', {}) + _contexts[__name] = _context + del __name + + users = kubernetes_master_config.get('users') + _users = {} + for user in users: + __name = user.get('name') + _user = user.get('user', {}) + _secret_key = '%s_client_certificate_data' % __name + if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: + cfy_client.secrets.create(key=_secret_key, value=_user.get('client-certificate-data')) + ctx.logger.info('Set secret: {0}.'.format(_secret_key)) + else: + cfy_client.secrets.update(key=_secret_key, value=_user.get('client-certificate-data')) + _secret_key = '%s_client_key_data' % __name + if cfy_client and not len(cfy_client.secrets.list(key=_secret_key)) == 1: + cfy_client.secrets.create(key=_secret_key, value=_user.get('client-key-data')) + ctx.logger.info('Set secret: {0}.'.format(_secret_key)) + else: + cfy_client.secrets.update(key=_secret_key, value=_user.get('client-key-data')) + ctx.instance.runtime_properties['%s_client_certificate_data' % __name] = _user.get('client-certificate-data') + ctx.instance.runtime_properties['%s_client_key_data' % __name] = _user.get('client-key-data') + _users[__name] = _user + del __name + + ctx.instance.runtime_properties['kubernetes'] = { + 'clusters': _clusters, + 'contexts': _contexts, + 'users': _users + } diff --git a/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_node/configure.py b/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_node/configure.py new file mode 100644 index 0000000000..69faaa80d1 --- /dev/null +++ b/TOSCA/kubernetes-cluster-TOSCA/scripts/kubernetes_node/configure.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T +# +# 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. +#============LICENSE_END============================================ + +# Afther K8s master up and running. This script will be triggered in each worker nodes. It will join the nodes, and mount the NFS directory. + +import subprocess +from cloudify import ctx +from cloudify.exceptions import NonRecoverableError + +START_COMMAND = 'sudo kubeadm join --token {0} {1}:{2}' + + +def execute_command(_command): + + ctx.logger.debug('_command {0}.'.format(_command)) + + subprocess_args = { + 'args': _command.split(), + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE + } + + ctx.logger.debug('subprocess_args {0}.'.format(subprocess_args)) + + process = subprocess.Popen(**subprocess_args) + output, error = process.communicate() + + ctx.logger.debug('command: {0} '.format(_command)) + ctx.logger.debug('output: {0} '.format(output)) + ctx.logger.debug('error: {0} '.format(error)) + ctx.logger.debug('process.returncode: {0} '.format(process.returncode)) + + if process.returncode: + ctx.logger.error('Running `{0}` returns error.'.format(_command)) + return False + + return output + + +if __name__ == '__main__': + + hostname = execute_command('hostname') + ctx.instance.runtime_properties['hostname'] = hostname.rstrip('\n') + + # Get the master cluster info. + masters = \ + [x for x in ctx.instance.relationships if + x.target.instance.runtime_properties.get( + 'KUBERNETES_MASTER', False)] + if len(masters) != 1: + raise NonRecoverableError( + 'Currently, a Kubernetes node must have a ' + 'dependency on one Kubernetes master.') + master = masters[0] + bootstrap_token = \ + master.target.instance.runtime_properties['bootstrap_token'] + master_ip = \ + master.target.instance.runtime_properties['master_ip'] + master_port = \ + master.target.instance.runtime_properties['master_port'] + + # Join the cluster. + cniCommand1=subprocess.Popen(["sudo", "sysctl", 'net.bridge.bridge-nf-call-iptables=1'], stdout=subprocess.PIPE) + join_command = \ + 'sudo kubeadm join --token {0} {1}:{2}'.format( + bootstrap_token, master_ip, master_port) + execute_command(join_command) + + #mount + mount_command=\ + 'sudo mount -t nfs -o proto=tcp,port=2049 {0}:/dockerdata-nfs /dockerdata-nfs'.format(master_ip) + execute_command(mount_command)
\ No newline at end of file diff --git a/TOSCA/kubernetes-cluster-TOSCA/scripts/nfs.sh b/TOSCA/kubernetes-cluster-TOSCA/scripts/nfs.sh new file mode 100644 index 0000000000..2d59acd99d --- /dev/null +++ b/TOSCA/kubernetes-cluster-TOSCA/scripts/nfs.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T +# +# 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. +#============LICENSE_END============================================ + +# this script will set the NFS server on k8s master. + +mkdir -p /dockerdata-nfs +chmod 777 /dockerdata-nfs +yum -y install nfs-utils +systemctl enable nfs-server.service +systemctl start nfs-server.service +echo "/dockerdata-nfs *(rw,no_root_squash,no_subtree_check)" |sudo tee --append /etc/exports +echo "/home/centos/dockerdata-nfs /dockerdata-nfs none bind 0 0" |sudo tee --append /etc/fstab +exportfs -a
\ No newline at end of file diff --git a/TOSCA/kubernetes-cluster-TOSCA/scripts/tasks.py b/TOSCA/kubernetes-cluster-TOSCA/scripts/tasks.py new file mode 100644 index 0000000000..7680fac957 --- /dev/null +++ b/TOSCA/kubernetes-cluster-TOSCA/scripts/tasks.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# ============LICENSE_START========================================== +# =================================================================== +# Copyright © 2017 AT&T +# +# 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. +#============LICENSE_END============================================ + +# here we define some tasks + +from fabric.api import run + + +def label_node(labels, hostname): + if labels: + label_list = [] + for key, value in labels.items(): + label_pair_string = '%s=%s' % (key, value) + label_list.append(label_pair_string) + label_string = ' '.join(label_list) + command = 'kubectl label nodes %s %s' % (hostname, label_string) + run(command) + + +def stop_node(hostname): + command = 'kubectl drain %s' % (hostname) + run(command) + + +def delete_node(hostname): + command = 'kubectl delete no %s' % (hostname) + run(command) |