def push(phase): """ Push release and meta images """ check_phase(phase) info("Pushing meta and release images ...") yml = lain_yaml(ignore_prepare=True) meta_version = yml.repo_meta_version() if meta_version is None: error("please git commit.") return None domain = get_domain(phase) registry = "registry.%s" % domain phase_meta_tag = docker.gen_image_name(yml.appname, 'meta', meta_version, registry) phase_release_tag = docker.gen_image_name(yml.appname, 'release', meta_version, registry) meta_code = docker.push(phase_meta_tag) release_code = docker.push(phase_release_tag) if meta_code or release_code: error("Error lain push.") sys.exit(1) else: info("Done lain push.") info("notifying lain push.") access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) last_commit_id = fetch_last_commit_id(domain, yml.appname, auth_header) if last_commit_id is not None: notify_diffs(domain, yml.appname, last_commit_id, auth_header) else: warn("Notified Nothing!") info("Done notifying lain push.")
def sync(src_phase, dst_phase, appname, meta_version): check_phase(src_phase) check_phase(dst_phase) src_domain = get_domain(src_phase) dst_domain = get_domain(dst_phase) src_registry = "registry.{domain}".format(domain=src_domain) dst_registry = "registry.{domain}".format(domain=dst_domain) src_phase_meta_tag = docker.gen_image_name( appname, 'meta', meta_version, src_registry) src_phase_release_tag = docker.gen_image_name( appname, 'release', meta_version, src_registry) dst_phase_meta_tag = docker.gen_image_name( appname, 'meta', meta_version, dst_registry) dst_phase_release_tag = docker.gen_image_name( appname, 'release', meta_version, dst_registry) return_code = transfer_to(src_phase_meta_tag, dst_phase_meta_tag) if return_code != 0: sys.exit(return_code) return_code = transfer_to(src_phase_release_tag, dst_phase_release_tag) if return_code != 0: sys.exit(return_code) access_token = SSOAccess.get_token(dst_phase) auth_header = get_auth_header(access_token) info("notifying lain push.") notify_pushs(dst_domain, appname, auth_header) info("notify lain push done.")
def show(cls, phase, procname, path=None): """ show secret file of special procname in different phase path: absolute path of config file, eg : /lain/app/config """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) proc = yml.procs.get(procname, None) if proc is None: error('proc {} does not exist'.format(procname)) exit(1) podgroup_name = "{}.{}.{}".format(yml.appname, proc.type.name, proc.name) lvault_url = "http://lvault.%s/v2/secrets?app=%s&proc=%s" % ( get_domain(phase), yml.appname, podgroup_name) if path: lvault_url += "&path=%s" % path show_response = requests.get(lvault_url, headers=auth_header) if show_response.status_code < 300: info("secret file detail:") print( json.dumps(show_response.json(), encoding="utf-8", ensure_ascii=False, indent=2)) else: error("shit happened : %s" % show_response.text)
def ps(phase, output='pretty'): """ Show basic deploy messages of app """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) console = "console.%s" % get_domain(phase) access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) repo_url = "http://%s/api/v1/repos/%s/" % (console, yml.appname) repo_r = requests.get(repo_url, headers=auth_header) if repo_r.status_code == 404: error('app {} has not been reposited at {}'.format(yml.appname, phase)) exit(1) elif repo_r.status_code == 200: pass else: error("shit happend: %s" % repo_r.content) exit(1) app_url = "http://%s/api/v1/apps/%s/" % (console, yml.appname) app_r = requests.get(app_url, headers=auth_header) if app_r.status_code == 200: app_status = app_r.json()["app"] render_app_status(app_status, output) elif app_r.status_code == 404: error('app {} has not been deployed at {}'.format(yml.appname, phase)) exit(1) else: error("shit happend: %s" % repo_r.content) exit(1)
def attach(phase, proc_name, instance_no, target=None): """ Attach the stdout/stderr of the container """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) appname = target if target else yml.appname authorize_and_check(phase, appname) domain = get_domain(phase) access_token = SSOAccess.get_token(phase) endpoint = "wss://entry.%s/attach" % domain header_data = [ "access-token: %s" % access_token, "app-name: %s" % appname, "proc-name: %s" % proc_name, "instance-no: %s" % instance_no ] try: client = EntryClient(endpoint, header=header_data) info( "Start to attach the stdout/stderr of the container. Press <Ctrl+c> to stop..." ) client.attach_container() except KeyboardInterrupt: pass except: error("Server stops the connection. Ask admin for help.")
def show(cls, phase, procname, path=None): """ show secret file of special procname in different phase path: absolute path of config file, eg : /lain/app/config """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) proc = yml.procs.get(procname, None) if proc is None: error('proc {} does not exist'.format(procname)) exit(1) podgroup_name = "{}.{}.{}".format(yml.appname, proc.type.name, proc.name) lvault_url = "http://lvault.%s/v2/secrets?app=%s&proc=%s" % ( get_domain(phase), yml.appname, podgroup_name) if path: lvault_url += "&path=%s" % path show_response = requests.get(lvault_url, headers=auth_header) if show_response.status_code < 300: info("secret file detail:") print(json.dumps(show_response.json(), encoding="utf-8", ensure_ascii=False, indent=2)) else: error("shit happened : %s" % show_response.text)
def sync(src_phase, dst_phase, appname, meta_version): check_phase(src_phase) check_phase(dst_phase) src_domain = get_domain(src_phase) dst_domain = get_domain(dst_phase) src_registry = "registry.{domain}".format(domain=src_domain) dst_registry = "registry.{domain}".format(domain=dst_domain) src_phase_meta_tag = docker.gen_image_name(appname, 'meta', meta_version, src_registry) src_phase_release_tag = docker.gen_image_name(appname, 'release', meta_version, src_registry) dst_phase_meta_tag = docker.gen_image_name(appname, 'meta', meta_version, dst_registry) dst_phase_release_tag = docker.gen_image_name(appname, 'release', meta_version, dst_registry) return_code = transfer_to(src_phase_meta_tag, dst_phase_meta_tag) if return_code != 0: sys.exit(return_code) return_code = transfer_to(src_phase_release_tag, dst_phase_release_tag) if return_code != 0: sys.exit(return_code) access_token = SSOAccess.get_token(dst_phase) auth_header = get_auth_header(access_token) info("notifying lain push.") notify_pushs(dst_domain, appname, auth_header) info("notify lain push done.")
def push(phase): """ Push release and meta images """ check_phase(phase) info("Pushing meta and release images ...") yml = lain_yaml(ignore_prepare=True) meta_version = yml.repo_meta_version() if meta_version is None: error("please git commit.") return None domain = get_domain(phase) registry = "registry.%s" % domain phase_meta_tag = docker.gen_image_name( yml.appname, 'meta', meta_version, registry) phase_release_tag = docker.gen_image_name( yml.appname, 'release', meta_version, registry) meta_code = docker.push(phase_meta_tag) release_code = docker.push(phase_release_tag) if meta_code or release_code: error("Error lain push.") sys.exit(1) else: info("Done lain push.") info("notifying lain push.") access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) last_commit_id = fetch_last_commit_id(domain, yml.appname, auth_header) if last_commit_id is not None: notify_diffs(domain, yml.appname, last_commit_id, auth_header) else: warn("Notified Nothing!") info("Done notifying lain push.")
def logout(phase): """ Logout specific phase """ check_phase(phase) domain = get_domain(phase) logout_success = SSOAccess.clear_token(phase) if logout_success: docker.logout('registry.%s' % domain) info("Logout successfully!") else: warn('Logout failed!')
def logout(phase): """ Logout specific phase """ check_phase(phase) domain = get_domain(phase) logout_success = SSOAccess.clear_token(phase) if logout_success: docker.logout('registry.%s'%domain) info("Logout successfully!") else: warn('Logout failed!')
def dashboard(phase, sort='appname'): """ Basic dashboard of Lain """ check_phase(phase) print_welecome() print_workflows() console = "console.%s" % (get_domain(phase)) access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) print_available_repos(console, auth_header) print_available_apps(console, auth_header, sort)
def undeploy(phase, target=None, proc=None): """ Undeploy specific proc in the app or the whole app """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) appname = target if target else yml.appname authorize_and_check(phase, appname) console = "console.%s" % get_domain(phase) access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) if proc: undeploy_proc(proc, appname, console, auth_header) else: undeploy_app(appname, console, auth_header)
def delete(cls, phase, username): """ delete maintianer for different phase """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) console = "console.%s" % get_domain(phase) maintainer_url = "http://%s/api/v1/repos/%s/maintainers/%s/" % ( console, yml.appname, username) delete_response = requests.delete(maintainer_url, headers=auth_header) if delete_response.status_code < 300: info("delete successfully.") else: error("shit happened : %s" % delete_response.text)
def reposit(phase): """ Initialize a repository in lain """ check_phase(phase) validate_only_warning() info("Repositing ...") yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) console = "console.%s" % get_domain(phase) result = reposit_app(phase, yml.appname, console, auth_header) info("Done, %s" % result)
def deploy(phase, version=None, target=None, proc=None, output='pretty'): """ Deploy specific proc in the app or the whole app """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) appname = target if target else yml.appname authorize_and_check(phase, appname) console = "console.%s" % get_domain(phase) access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) if proc: deploy_proc(proc, appname, console, auth_header, output) else: if not is_resource_instance(appname): reposit_app(phase, appname, console, auth_header) deploy_app(phase, appname, console, auth_header, version, output)
def add(cls, phase, username, role): """ add maintianer for different phase """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) console = "console.%s" % get_domain(phase) maintainer_url = "http://%s/api/v1/repos/%s/maintainers/" % ( console, yml.appname) payload = {"username": username, "role": role} add_response = requests.post(maintainer_url, headers=auth_header, json=payload) if add_response.status_code < 300: info("add successfully.") else: error("shit happened : %s" % add_response.text)
def ps(phase, output='pretty'): """ Show basic deploy messages of app """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) console = "console.%s" % get_domain(phase) access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) repo_url = "http://%s/api/v1/repos/%s/" % (console, yml.appname) repo_r = requests.get(repo_url, headers=auth_header) if repo_r.status_code == 404: error('app {} has not been reposited at {}'.format( yml.appname, phase )) exit(1) elif repo_r.status_code == 200: pass else: error("shit happend: %s" % repo_r.content) exit(1) app_url = "http://%s/api/v1/apps/%s/" % (console, yml.appname) app_r = requests.get(app_url, headers=auth_header) if app_r.status_code == 200: app_status = app_r.json()["app"] render_app_status(app_status, output) elif app_r.status_code == 404: error('app {} has not been deployed at {}'.format( yml.appname, phase )) exit(1) else: error("shit happend: %s" % repo_r.content) exit(1)
def delete(cls, phase, procname, path): """ delete secret file for different phase """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) proc = yml.procs.get(procname, None) if proc is None: error('proc {} does not exist'.format(procname)) exit(1) podgroup_name = "{}.{}.{}".format(yml.appname, proc.type.name, proc.name) lvault_url = "http://lvault.%s/v2/secrets?app=%s&proc=%s&path=%s" % ( get_domain(phase), yml.appname, podgroup_name, path) delete_response = requests.delete(lvault_url, headers=auth_header) if delete_response.status_code < 300: info("delete successfully.") else: error("shit happened : %s" % delete_response.text)
def show(cls, phase, username=None): """ show maintainers list or specical maitainer message of app in different phase username: sso username """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) console = "console.%s" % get_domain(phase) maintainer_url = "http://%s/api/v1/repos/%s/maintainers/" % ( console, yml.appname) if username: maintainer_url += '%s/' % username show_response = requests.get(maintainer_url, headers=auth_header) if show_response.status_code < 300: info("maintainer detail:") pprint.pprint(show_response.json()) else: error("shit happened : %s" % show_response.text)
def enter(phase, proc_name, instance_no, target=None): """ Enter the container of specific proc """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) appname = target if target else yml.appname authorize_and_check(phase, appname) domain = get_domain(phase) access_token = SSOAccess.get_token(phase) term_type = os.environ.get("TERM", "xterm") endpoint = "wss://entry.%s/enter" % domain header_data = ["access-token: %s" % access_token, "app-name: %s" % appname, "proc-name: %s" % proc_name, "instance-no: %s" % instance_no, "term-type: %s" % term_type] try: client = EntryClient(endpoint, header=header_data) client.invoke_shell() except: error("Server stops the connection. Ask admin for help.")
def attach(phase, proc_name, instance_no, target=None): """ Attach the stdout/stderr of the container """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) appname = target if target else yml.appname authorize_and_check(phase, appname) domain = get_domain(phase) access_token = SSOAccess.get_token(phase) endpoint = "wss://entry.%s/attach" % domain header_data = ["access-token: %s" % access_token, "app-name: %s" % appname, "proc-name: %s" % proc_name, "instance-no: %s" % instance_no] try: client = EntryClient(endpoint, header=header_data) info("Start to attach the stdout/stderr of the container. Press <Ctrl+c> to stop...") client.attach_container() except KeyboardInterrupt: pass except: error("Server stops the connection. Ask admin for help.")
class SecretCommands(TwoLevelCommandBase): ''' allow add secret files for app, lain will add the secret file into image of the proc when deploying. ''' @classmethod def subcommands(self): return [self.show, self.add, self.delete] @classmethod def namespace(self): return "secret" @classmethod def help_message(self): return "secret operation: including add, delete or show secret files of the app" @classmethod @arg('phase', help="lain cluster phase id, can be added by lain config save") @arg('procname', help="proc name of the app") def show(cls, phase, procname, path=None): """ show secret file of special procname in different phase path: absolute path of config file, eg : /lain/app/config """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) proc = yml.procs.get(procname, None) if proc is None: error('proc {} does not exist'.format(procname)) exit(1) podgroup_name = "{}.{}.{}".format(yml.appname, proc.type.name, proc.name) lvault_url = "http://lvault.%s/v2/secrets?app=%s&proc=%s" % ( get_domain(phase), yml.appname, podgroup_name) if path: lvault_url += "&path=%s" % path show_response = requests.get(lvault_url, headers=auth_header) if show_response.status_code < 300: info("secret file detail:") print( json.dumps(show_response.json(), encoding="utf-8", ensure_ascii=False, indent=2)) else: error("shit happened : %s" % show_response.text) @classmethod @arg('phase', help="lain cluster phase id, can be added by lain config save") @arg('procname', help="proc name of the app") @arg('path', help='absolute path of config file, eg : /lain/app/config') def add(cls, phase, procname, path, content=None, file=None): """ add secret file for different phase content: content of the secret file file: read secret content from a specify file """ if file is None and content is None: error("need specify the content use -c or -f parameter") exit(1) if file is not None: try: f = open(file) content = f.read() except Exception, e: error("error read file %s : %s" % (file, str(e))) exit(1) check_phase(phase) yml = lain_yaml(ignore_prepare=True) authorize_and_check(phase, yml.appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) proc = yml.procs.get(procname, None) if proc is None: error('proc {} does not exist'.format(procname)) exit(1) podgroup_name = "{}.{}.{}".format(yml.appname, proc.type.name, proc.name) lvault_url = "http://lvault.%s/v2/secrets?app=%s&proc=%s&path=%s" % ( get_domain(phase), yml.appname, podgroup_name, path) payload = {"content": content} add_response = requests.put(lvault_url, headers=auth_header, json=payload) if add_response.status_code < 300: info("add successfully.") else: error("shit happened : %s" % add_response.text)
def scale(phase, proc, target=None, cpu=None, memory=None, numinstances=None, output='pretty'): """ Scale proc with cpu/memory/num_instances """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) appname = target if target else yml.appname authorize_and_check(phase, appname) domain = get_domain(phase) console = "console.%s" % domain url = "http://{}/api/v1/apps/{}/procs/{}/".format(console, appname, proc) access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) cpu, memory, numinstances = validate_parameters(cpu, memory, numinstances) proc_status = requests.get(url, headers=auth_header) if proc_status.status_code == 200: # proc exists info( "Start to scale Proc {} of App {} in Lain Cluster {} with domain {}" .format(proc, appname, phase, domain)) elif proc_status.status_code == 404: # proc does not exist warn( "Proc {} of App {} does not exists in Lain Cluster {} with domain {}" .format(proc, appname, phase, domain)) info("Please deploy it first") exit(1) else: error("shit happend: %s" % proc_status.content) exit(1) scale_results = {} payload1 = {} payload2 = {} if cpu is not None: payload1['cpu'] = cpu if memory is not None: payload1['memory'] = memory if len(payload1) > 0: info("Scaling......") info(str(payload1)) scale_r = requests.patch(url, headers=auth_header, data=json.dumps(payload1), timeout=120) scale_results['cpu_or_memory'] = { 'payload': payload1, 'success': scale_r.status_code < 300 } render_scale_result(scale_r, output) if numinstances is not None: payload2['num_instances'] = numinstances if len(payload2) > 0: info("Scaling...") info(str(payload2)) scale_r = requests.patch(url, headers=auth_header, data=json.dumps(payload2), timeout=120) scale_results['num_instances'] = { 'payload': payload2, 'success': scale_r.status_code < 300 } render_scale_result(scale_r, output) info("Outline of scale result: ") for k, v in scale_results.iteritems(): success = v['success'] output_func = None if success: output_func = info else: output_func = error output_func(" scale of {} {}".format( k, "success" if success else "failed")) output_func(" params: {}".format(v['payload']))
def scale(phase, proc, target=None, cpu=None, memory=None, numinstances=None, output='pretty'): """ Scale proc with cpu/memory/num_instances """ check_phase(phase) yml = lain_yaml(ignore_prepare=True) appname = target if target else yml.appname authorize_and_check(phase, appname) domain = get_domain(phase) console = "console.%s" % domain url = "http://{}/api/v1/apps/{}/procs/{}/".format( console, appname, proc ) access_token = SSOAccess.get_token(phase) auth_header = get_auth_header(access_token) cpu, memory, numinstances = validate_parameters(cpu, memory, numinstances) proc_status = requests.get(url, headers=auth_header) if proc_status.status_code == 200: # proc exists info( "Start to scale Proc {} of App {} in Lain Cluster {} with domain {}".format( proc, appname, phase, domain ) ) elif proc_status.status_code == 404: # proc does not exist warn( "Proc {} of App {} does not exists in Lain Cluster {} with domain {}".format( proc, appname, phase, domain ) ) info("Please deploy it first") exit(1) else: error("shit happend: %s"%proc_status.content) exit(1) scale_results = {} payload1 = {} payload2 = {} if cpu is not None: payload1['cpu'] = cpu if memory is not None: payload1['memory'] = memory if len(payload1) > 0: info("Scaling......") info(str(payload1)) scale_r = requests.patch(url, headers=auth_header, data=json.dumps(payload1), timeout=120) scale_results['cpu_or_memory'] = { 'payload': payload1, 'success': scale_r.status_code < 300 } render_scale_result(scale_r, output) if numinstances is not None: payload2['num_instances'] = numinstances if len(payload2) > 0: info("Scaling...") info(str(payload2)) scale_r = requests.patch(url, headers=auth_header, data=json.dumps(payload2), timeout=120) scale_results['num_instances'] = { 'payload': payload2, 'success': scale_r.status_code < 300 } render_scale_result(scale_r, output) info("Outline of scale result: ") for k, v in scale_results.iteritems(): success = v['success'] output_func = None if success: output_func = info else: output_func = error output_func(" scale of {} {}".format(k, "success" if success else "failed")) output_func(" params: {}".format(v['payload']))