def init(ctx, kube_context, submodules, repopath): """Init the platform by doing submodule init and checkout all submodules on master""" # Get the repo from arguments defaults to cwd repo = get_repo(repopath) submodules = get_submodules(repo, submodules) with click_spinner.spinner(): repo.submodule_update() logger.info('Platform initialized.')
def status(ctx, kube_context): """Check the status of the k3d cluster""" # Check if the cluster exists kube_context = ctx.kube_context if k3d.k3d_get(kube_context): if kube.kubectl_info(kube_context): logger.info('K3D cluster \'' + kube_context + '\' is running') else: logger.error('Cluster not running. Please start the cluster') raise click.Abort() else: logger.error('K3D cluster \'' + kube_context + '\' does not exist.')
def info(ctx, kube_context): """Get info on accessing the platform""" kube_context = ctx.kube_context try: k1s_host = s.run([ 'kubectl', '--context', 'k3d-' + kube_context, '-n', 'k1s', 'get', 'ingressroute', 'ui', '-o', 'jsonpath={.spec.routes[0].match}' ], capture_output=True, check=True) k1s_host = k1s_host.stdout.decode('utf-8') k1s_host = k1s_host.split('`') k1s_url = k1s_host[1] logger.info('K1S can be accessed through the URL:') logger.info('https://' + k1s_url + '/') except s.CalledProcessError as error: logger.debug(error.stderr.decode('utf-8')) raise click.Abort()
def token(ctx, kube_context): """Get the platform token required by Kubernetes Dashboard""" kube_context = ctx.kube_context try: proc1 = s.Popen([ 'kubectl', '--context', 'k3d-' + kube_context, '-n', 'monitoring', 'describe', 'secret', 'k1s-admin' ], stdout=s.PIPE) proc2 = s.Popen(['grep', 'token:'], stdin=proc1.stdout, stdout=s.PIPE, universal_newlines=True) proc1.stdout.close() out = proc2.communicate()[0] logger.info('The platform token is:\n') logger.info(out) except s.CalledProcessError as error: logger.debug(error.stderr.decode('utf-8')) raise click.Abort()
def stop(ctx, kube_context): """Stop k3d cluster""" # Check the cluster status kube_context = ctx.kube_context if k3d.k3d_get(kube_context): if not kube.kubectl_info(kube_context): logger.info('K3D cluster \'' + kube_context + '\' is already stopped') raise click.Abort() elif not k3d.k3d_get(kube_context): logger.error('K3D cluster \'' + kube_context + '\' doesn\'t exist') raise click.Abort() # Stop the k3d cluster try: logger.debug('Running: `k3d cluster stop`') _stop_cluster = s.run(['k3d', 'cluster', 'stop', kube_context], capture_output=False, check=True) except s.CalledProcessError as error: logger.critical('Could not stop k3d cluster' + error.stderr.decode('utf-8'))
def ns(ctx, kube_context, name): """Create a namespace""" kube_context = ctx.kube_context # Create a namespace in kubernetes ns_exists = s.run( ['kubectl', 'get', 'ns', name, '--context', 'k3d-' + kube_context], capture_output=True) if ns_exists.returncode != 0: try: _app_ns = s.run([ 'kubectl', 'create', 'ns', name, '--context', 'k3d-' + kube_context ], capture_output=True, check=True) logger.info('Created a namespace for ' + name) except s.CalledProcessError as error: logger.error('Something went wrong with namespace: ' + error.stderr.decode('utf-8')) raise click.Abort() else: logger.info('Skipping creation of ' + name + ' namespace ' 'since it already exists.')
def init(ctx, kube_context): """Download binaries for all dependencies""" # Figure out what kind of OS we are on ostype = os.uname().sysname.lower() # Kubectl parameters kubectl_stable = s.check_output([ 'curl', '-s', 'https://storage.googleapis.com/kubernetes-release/release/stable.txt' ]).decode('utf-8') kubectl_url = 'https://storage.googleapis.com/kubernetes-release/release/{}/bin/linux/arm/kubectl'.format( kubectl_stable.split('\n')[0]) # Helm parameters helm_url = 'https://get.helm.sh/helm-v3.4.2-{}-arm.tar.gz'.format(ostype) # K3D parameters k3d_url = 'https://github.com/rancher/k3d/releases/download/v3.4.0/k3d-{}-arm'.format( ostype) # Skaffold parameters skaffold_url = 'https://github.com/nushkovg/skaffold/releases/download/v1.17.2-arm/skaffold-{}-arm'.format( ostype) with click_spinner.spinner(): # Download kubectl logger.info('Downloading kubectl...') urllib.request.urlretrieve(kubectl_url, 'bin/kubectl') st = os.stat('bin/kubectl') os.chmod('bin/kubectl', st.st_mode | stat.S_IEXEC) logger.info('kubectl downloaded') # Download helm logger.info('Downloading helm...') urllib.request.urlretrieve(helm_url, 'bin/helm.tar.gz') tar = tarfile.open('bin/helm.tar.gz', 'r:gz') helm_file = '{}-arm/helm'.format(ostype) for member in tar.getmembers(): if member.name == helm_file: tar.extract(helm_file, 'bin') os.rename('bin/' + helm_file, 'bin/helm') tar.close() os.remove('bin/helm.tar.gz') os.removedirs('bin/{}-arm'.format(ostype)) logger.info('helm downloaded!') # Download k3d logger.info('Downloading k3d...') urllib.request.urlretrieve(k3d_url, 'bin/k3d') st = os.stat('bin/k3d') os.chmod('bin/k3d', st.st_mode | stat.S_IEXEC) logger.info('k3d downloaded') # Download skaffold logger.info('Downloading skaffold...') urllib.request.urlretrieve(skaffold_url, 'bin/skaffold') st = os.stat('bin/skaffold') os.chmod('bin/skaffold', st.st_mode | stat.S_IEXEC) logger.info('skaffold downloaded') logger.info('All dependencies downloaded to bin/') logger.info('IMPORTANT: Please add the path to your user profile to ' + os.getcwd() + '/bin directory at the beginning of your PATH') logger.info('$ echo export PATH=' + os.getcwd() + '/bin:$PATH >> ~/.profile') logger.info('$ source ~/.profile')
def cli(ctx, kube_context): """Preflight checks to ensure all tools and versions are present""" # Check go try: go_ver = s.run(['go', 'version'], capture_output=True, check=True) logger.info('Found go.') logger.debug(go_ver.stdout.decode('utf-8')) except FileNotFoundError: logger.critical('go not found in PATH.') except s.CalledProcessError as error: logger.critical('go version returned something unexpected: ' + error.stderr.decode('utf-8')) # Check docker try: docker_ps = s.run(['docker', 'ps'], capture_output=True, check=True) logger.info('Found docker.') logger.debug(docker_ps.stdout.decode('utf-8')) except FileNotFoundError: logger.critical('docker not found in PATH.') except s.CalledProcessError as error: logger.critical('`docker ps` returned something unexpected: ' + error.stderr.decode('utf-8')) logger.critical('Please ensure the docker daemon is running and that ' 'your user is part of the docker group. See README') # Check helm 3 try: helm_ver = s.run(['helm', 'version', '--short'], capture_output=True, check=True) # Check that we have helm 3 if helm_ver.stdout.decode('utf-8')[1] != "3": logger.error( 'Old version of helm detected when running "helm" from PATH.') else: logger.info('Found helm.') logger.debug(helm_ver.stdout.decode('utf-8')) except FileNotFoundError: logger.critical('helm not found in PATH.') except s.CalledProcessError as error: logger.critical('helm version returned something unexpected: ' + error.stderr.decode('utf-8')) # Check k3d try: k3d_ver = s.run(['k3d', 'version'], capture_output=True, check=True) logger.info('Found k3d.') logger.debug(k3d_ver.stdout.decode('utf-8')) except FileNotFoundError: logger.critical('k3d not found in PATH.') except s.CalledProcessError as error: logger.critical('k3d version returned something unexpected: ' + error.stderr.decode('utf-8')) # Check skaffold try: skaffold_ver = s.run(['skaffold', 'version'], capture_output=True, check=True) logger.info('Found skaffold.') logger.debug(skaffold_ver.stdout.decode('utf-8')) except FileNotFoundError: logger.critical('skaffold not found in PATH.') except s.CalledProcessError as error: logger.critical('skaffold version returned something unexpected: ' + error.stderr.decode('utf-8')) # Check kubectl try: kubectl_ver = s.run(['kubectl', 'version', '--client=true'], capture_output=True, check=True) logger.info('Found kubectl.') logger.debug(kubectl_ver.stdout.decode('utf-8')) except FileNotFoundError: logger.critical('kubectl not found in PATH.') except s.CalledProcessError as error: logger.critical('kubectl version returned something unexpected: ' + error.stderr.decode('utf-8'))
def version(ctx, kube_context, submodules, repopath): """Check versions of services in git submodules You can provide a comma separated list of submodules or you can use 'all' for all submodules""" # Get the repo from arguments defaults to cwd repo = get_repo(repopath) submodules = get_submodules(repo, submodules) # Do something with the submodules all_sm_details = [] with click_spinner.spinner(): for submodule in submodules: logger.debug('Switched to submodule: ' + submodule) sm_details = {} sm_details['repo'] = submodule # Are we on an active branch? on a tag? if not then get sha? try: smrepo = git.Repo(submodule) sm_details['present'] = True except git.InvalidGitRepositoryError as error: logger.warning(submodule + ': not present') sm_details['present'] = False all_sm_details.append(sm_details) continue # Get branch try: branch = smrepo.active_branch.name sm_details['branch'] = branch # Check if remotes are ahead or behind origin = smrepo.remotes.origin origin.fetch() commits_behind = smrepo.iter_commits(branch + '..origin/' + branch) commits_ahead = smrepo.iter_commits('origin/' + branch + '..' + branch) sm_details['commits_ahead'] = sum(1 for c in commits_ahead) sm_details['commits_behind'] = sum(1 for c in commits_behind) except TypeError as error: sm_details['branch'] = '' logger.debug(error) # Check if we point to any tags points_at_tag = smrepo.git.tag('--points-at', 'HEAD') sm_details['tag'] = points_at_tag # Get sha of HEAD sha = smrepo.head.commit.hexsha sm_details['sha'] = sha # Add submodule details to the list all_sm_details.append(sm_details) logger.debug('Received following details about the platform submodules:') logger.debug(all_sm_details) for sm_details in all_sm_details: logger.info(sm_details['repo'] + ':') logger.info('Branch: ' + sm_details['branch']) logger.info('SHA: ' + sm_details['sha']) if sm_details['tag']: logger.info('Tag: ' + sm_details['tag']) if sm_details['commits_ahead'] > 0: logger.info('Ahead by: ' + str(sm_details['commits_ahead']) + ' commits') if sm_details['commits_behind'] > 0: logger.info('Behind by: ' + str(sm_details['commits_behind']) + ' commits')
def create(ctx, kube_context): """Create a k3d cluster""" # Check if k3d cluster is already created kube_context = ctx.kube_context if k3d.k3d_get(kube_context): logger.error('K3D cluster \'' + kube_context + '\' already exists') raise click.Abort() # Create the k3d cluster try: logger.debug('Running: `k3d cluster create`') _create_cluster = s.run(['k3d', 'cluster', 'create', '--k3s-server-arg', '--no-deploy=traefik', '--port', '80:80@loadbalancer', '--port', '443:443@loadbalancer', '--port', '8080:8080@loadbalancer', kube_context], capture_output=False, check=True) except s.CalledProcessError as error: logger.critical('Could not create k3d cluster' + error.stderr.decode('utf-8')) # Create required namespaces namespaces = [kube_context, 'traefik', 'monitoring'] for ns in namespaces: ns_exists = s.run(['kubectl', 'get', 'ns', ns, '--context', 'k3d-' + kube_context], capture_output=True) if ns_exists.returncode != 0: try: _app_ns = s.run(['kubectl', 'create', 'ns', ns, '--context', 'k3d-' + kube_context], check=True, stdout=s.DEVNULL) except s.CalledProcessError as error: logger.error('Something went wrong with namespace: ' + error.stderr.decode('utf-8')) raise click.Abort() else: logger.info('Skipping creation of ' + ns + ' namespace ' 'since it already exists.') # Apply traefik CRD definitions try: crd_path = 'infrastructure/k1s-traefik/manifests/001-crds.yaml' logger.debug('Running: `kubectl apply -f {}`'.format(crd_path)) _apply_crds = s.run(['kubectl', 'apply', '-f', crd_path], check=True, stdout=s.DEVNULL) except s.CalledProcessError as error: logger.critical('Could not apply traefik CRDs' + error.stderr.decode('utf-8'))