def check_phase(phase): if phase not in PHASE_CHOICES: error('phase %s not in available phases: %s.' % (phase, PHASE_CHOICES)) warn( 'phase can be added using: lain config save %s domain {{ domain }}' % phase) exit(1)
def lain_yaml_data(): if not os.path.exists(LAIN_YAML_PATH): error('Missing lain.yaml under current directory') sys.exit(1) with open(LAIN_YAML_PATH) as f: data = f.read() return yaml.load(data)
def tag(phase): """ Tag release and meta images """ check_phase(phase) info("Taging meta and relese image ...") 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 meta_tag = "%s:meta-%s" % (yml.appname, meta_version) release_tag = "%s:release-%s" % (yml.appname, meta_version) 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.tag(meta_tag, phase_meta_tag) release_code = docker.tag(release_tag, phase_release_tag) if meta_code or release_code: error("Error lain tag.") else: info("Done lain tag.")
def get_domain(phase): domain = user_config.get_config().get(phase, {}).get(DOMAIN_KEY, None) if not domain: error('please set %s domain by "lain config save %s %s ${%s_domain}"' % (phase, phase, DOMAIN_KEY, phase)) exit(1) return domain
def authorize_and_check(phase, appname): role = get_role(phase, appname) # if unauthorized, refresh first if role == 'unauthorized': if not sso_refresh(phase): error('please login first') exit(1) role = get_role(phase, appname) # after refresh, should be authorized if role == 'unauthorized': error('still unauthorized after refresh') exit(1) elif role in ['wrong status', 'error', 'unknown']: error('shit happened when getting role') exit(1) elif role == 'no role': error('you have not a role of the app {}'.format(appname)) error('please contact maintainers of the app') exit(1) elif role == 'no app': # no app, let it go warn('app {} does not exist, passed by.'.format(appname)) return None else: # valid role return role
def gen_run_ctx(proc_name): yml = lain_yaml(ignore_prepare=True) proc = yml.procs.get(proc_name, None) if proc is None: error('proc {} does not exist'.format(proc_name)) exit(1) container_name = "{}.{}.{}".format(yml.appname, proc.type.name, proc.name) image = yml.img_names['release'] port = proc.port.keys()[0] if proc.port.keys() else None working_dir = proc.working_dir or DOCKER_APP_ROOT cmd = proc.cmd env = proc.env extra_env = [ 'TZ=Asia/Shanghai', 'LAIN_APPNAME={}'.format(yml.appname), 'LAIN_PROCNAME={}'.format(proc.name), 'LAIN_DOMAIN=lain.local', 'DEPLOYD_POD_INSTANCE_NO=1', 'DEPLOYD_POD_NAME={}'.format(container_name), 'DEPLOYD_POD_NAMESPACE={}'.format(yml.appname) ] volumes = {} local_proc_volume_base = os.path.join(LOCAL_VOLUME_BASE, container_name) if proc.volumes: for v in proc.volumes: container_path = os.path.join(local_proc_volume_base, v) host_path = local_proc_volume_base + container_path volumes[host_path] = container_path return container_name, image, working_dir, port, cmd, env + extra_env, volumes, local_proc_volume_base
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 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 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 build(push=False, release=False): """ Build release and meta images """ info("Building meta and release images ...") validate_only_warning() yml = lain_yaml() meta_version = yml.repo_meta_version() use_prepare = docker.exist(yml.img_names['prepare']) use_build = release and docker.exist(yml.img_names['build']) release_suc, release_name = yml.build_release(use_prepare, use_build) (meta_suc, meta_name) = (False, '') if not release_suc else yml.build_meta() if not (release_suc and meta_suc): sys.exit(1) if meta_version is None: warn("please git commit.") if push: if meta_version is None: error("need git commit SHA1.") return None tag_release_name = yml.tag_meta_version(release_name) docker.push(tag_release_name) tag_meta_name = yml.tag_meta_version(meta_name) docker.push(tag_meta_name) info("Done lain build.")
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 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 validate_only_warning(): valid, _ = _validate() if not valid: error('##############################') error('# maybe invalid lain.yaml #') error('# check the schema with #') error('# lain validate #') error('##############################')
def print_available_version(version, version_list): if not version_list: error("No available versions, please push first.") return if version: error("Version %s not exist." % version) info("Below are the available versions: ") for version in version_list: print(version)
def print_available_repos(console, auth_header): repos_url = "http://%s/api/v1/repos/" % console repos_res = requests.get(repos_url, headers=auth_header) info('Available repos are :') if repos_res.status_code == 200: repos = repos_res.json()["repos"] render_repos([repo["appname"] for repo in repos]) print('') else: error("shit happened : %s" % repos_res.content)
def meta(): """ Show current meta version """ meta_version = lain_yaml(ignore_prepare=True).repo_meta_version() if meta_version is None: error("please git commit.") else: info("meta version : %s" % lain_yaml(ignore_prepare=True).repo_meta_version())
def check(phase): """ Check current version of release and meta images in the remote registry """ check_phase(phase) tag_ok = _check_phase_tag(phase) if tag_ok: info("Image Tag OK in registry") else: error("Image Tag not OK in registry")
def deploy_app(phase, appname, console, auth_header, version, output): info("Begin deploy app %s to %s ..." % (appname, phase)) app_url = "http://%s/api/v1/apps/%s/" % (console, appname) apps_url = "http://%s/api/v1/apps/" % console app_r = requests.get(app_url, headers=auth_header) former_version, deploy_version = None, version if app_r.status_code == 200: operation = "upgrading" deploy_params = None if not is_resource_instance(appname): former_version = app_r.json()["app"]["metaversion"] exist, valid_version = check_meta_version(phase, appname, deploy_version) if not exist: print_available_version(deploy_version, valid_version) exit(1) if deploy_version: deploy_params = {"meta_version": deploy_version} else: deploy_version = valid_version deploy_r = requests.put(app_url, headers=auth_header, json=deploy_params) elif app_r.status_code == 404: operation = "deploying" payload = {'appname': appname} deploy_r = requests.post(apps_url, headers=auth_header, data=json.dumps(payload), timeout=120) else: error("shit happend: %s" % app_r.content) exit(1) if deploy_r.status_code < 300: if output != 'pretty': info("%s" % deploy_r.json()['msg']) info("app status: ") render_app_status(deploy_r.json()['app'], output=output) else: check_deploy_result(operation, console, appname, auth_header) if former_version: info("app {} deploy operation:".format(appname)) info(" last version: {}".format(former_version)) info(" this version: {}".format(deploy_version)) info("if shit happened, rollback your app by:") info(" lain deploy -v {}".format(former_version)) else: error("deploy latest version of %s to %s failed: %s" % (appname, phase, deploy_r.json()['msg']))
def print_available_apps(console, auth_header, sort_type): apps_url = "http://%s/api/v1/apps/" % console apps_res = requests.get(apps_url, headers=auth_header) info('Available apps are :') print("{:<30} {:<20} {:<60} {:<10}".format("Appname", "AppType", "MetaVersion", "State")) if apps_res.status_code == 200: apps = apps_res.json()["apps"] render_apps([AppInfo.new(app) for app in apps], sort_type) else: error("shit happened: %s" % apps_res.content)
def print_available_apps(console, auth_header, sort_type): apps_url = "http://%s/api/v1/apps/" % console apps_res = requests.get(apps_url, headers=auth_header) info('Available apps are :') print("{:<30} {:<20} {:<60} {:<10}".format( "Appname", "AppType", "MetaVersion", "State")) if apps_res.status_code == 200: apps = apps_res.json()["apps"] render_apps([AppInfo.new(app) for app in apps], sort_type) else: error("shit happened: %s" % apps_res.content)
def get_sso_url(cls, phase): try: sso_url = user_config.get_config().get(phase, {}).get(SSO_URL_KEY, None) if not sso_url: error( 'please set %s sso url by "lain config save %s %s ${%s_sso_url}"' % (phase, phase, SSO_URL_KEY, phase)) exit(1) return sso_url except Exception as e: error('error get %s sso url: %s' % (phase, e)) return ''
def prepare(): """ Build prepare image """ validate_only_warning() info("Generating prepare image...") if not lain_yaml().build_prepare()[0]: error("Error lain prepare.") sys.exit(1) else: info("Done lain prepare.") sys.exit(0)
def undeploy_app(appname, console, auth_header): delete_url = "http://%s/api/v1/apps/%s/" % (console, appname) delete_r = requests.delete(delete_url, headers=auth_header) try: if delete_r.status_code == 202: info("delete app %s success." % appname) info("delete result details: ") print(delete_r.json()['msg']) else: warn("delete app %s fail: %s" % (appname, delete_r.json()['msg'])) except Exception: error("shit happend: %s" % delete_r.content) exit(1)
def undeploy_proc(proc, appname, console, auth_header): proc_url = "http://%s/api/v1/apps/%s/procs/%s/" % (console, appname, proc) delete_r = requests.delete(proc_url, headers=auth_header) try: if delete_r.status_code == 202: info("delete proc %s success." % proc) info("delete result details: ") print(delete_r.json()['msg']) else: warn("delete proc %s fail: %s" % (proc, delete_r.json()['msg'])) except Exception: error("shit happend: %s" % delete_r.content) exit(1)
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 is_console_auth_activated(phase): domain = get_domain(phase) console = "console.%s" % domain apps_url = "http://%s/api/v1/apps/" % (console) apps_r = requests.get(apps_url) if apps_r.status_code == 401: return True elif apps_r.status_code == 200: return False else: error('shit happened when checking console auth status') error(apps_r.text) exit(1)
def validate(): """ Validate lain.yaml """ valid, msg = _validate() if valid: info('valid lain.yaml.') else: error('invalid lain.yaml.') warn('error message:') info(msg) # TODO : show related doc url warn('for details of lain.yaml schema please check related docs.') sys.exit(1)
def get_role(phase, appname): # 404: {"msg": "user yisun4 does not exist in the app sso-ldap\n", "url": "/api/v1/repos/sso-ldap/maintainers/", "role": null} # 404: {"msg": "app with appname sso-ldap1 not exist", "url": "/api/v1/repos/", "role": null} # 401: {"msg": "unauthorized : don't have the access to the operation", "url": "/api/v1/docs/", "app": null} if not is_console_auth_activated(phase): return 'noauth-admin' no_role_pattern = re.compile(r"^user (.+) does not exist in the app (.+)$") no_app_pattern = re.compile(r"^app with appname (.+) not exist, has not been reposited yet") domain = get_domain(phase) console = "console.%s" % domain url = "http://%s/api/v1/repos/%s/roles/" % (console, appname) auth_header = get_auth_header(SSOAccess.get_token(phase)) r = requests.get(url, headers=auth_header) if r.status_code == 401: return 'unauthorized' elif r.status_code == 200: try: r_json = r.json() return r_json["role"]["role"] except Exception as e: error(e) warn('DEBUG status: {}'.format(r.status_code)) warn('DEBUG result: {}'.format(r.content)) return 'error' elif r.status_code == 404: try: r_json = r.json() msg = r_json["msg"] if no_app_pattern.match(msg): return 'no app' elif no_role_pattern.match(msg): return 'no role' else: warn('DEBUG status: {}'.format(r.status_code)) warn('unknown result: {}'.format(r_json)) return 'unknown' except Exception as e: error(e) warn('DEBUG status: {}'.format(r.status_code)) warn('DEBUG result: {}'.format(r.content)) return 'error' else: warn('DEBUG status: {}'.format(r.status_code)) warn('DEBUG content: {}'.format(r.content)) return 'wrong status'
def reposit_app(phase, appname, console, auth_header): payload = {'appname': appname} repo_url = "http://%s/api/v1/repos/%s/" % (console, appname) repos_url = "http://%s/api/v1/repos/" % console repo_r = requests.get(repo_url, headers=auth_header) if repo_r.status_code == 404: repos_r = requests.post(repos_url, headers=auth_header, data=json.dumps(payload), timeout=120) if repos_r.status_code == 201: return 'reposit successfully' else: error("shit happened: %s" % repos_r.content) exit(1) elif repo_r.status_code == 200: return "already been reposited" else: error("shit happened: %s" % repo_r.content) exit(1)
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)
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 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 validate_parameters(cpu, memory, numinstances): if all([cpu is None, memory is None, numinstances is None]): warn("please input at least one param in cpu/memory/numinstances") exit(1) if numinstances is not None: try: numinstances = int(numinstances) except ValueError: warn('invalid parameter: num_instances (%s) should be integer' % numinstances) exit(1) if numinstances <= 0: warn('invalid parameter: num_instances (%s) should > 0' % numinstances) exit(1) if cpu is not None: try: cpu = int(cpu) except ValueError: warn('invalid parameter: cpu (%s) should be integer' % cpu) exit(1) if cpu < 0: warn('invalid parameter: cpu (%s) should >= 0' % cpu) exit(1) if memory is not None: memory = str(memory) try: if humanfriendly.parse_size(memory) < 4194304: error('invalid parameter: memory (%s) should >= 4M' % memory) exit(1) except humanfriendly.InvalidSize: error( 'invalid parameter: memory (%s) humanfriendly.parse_size(memory) failed' % memory) exit(1) return cpu, memory, numinstances
def deploy_proc(proc, appname, console, auth_header, output): info("Begin deploy proc %s from app %s ..." % (proc, appname)) url = "http://%s/api/v1/apps/%s/procs/" % (console, appname) payload = {'procname': proc} deploy_r = requests.post(url, headers=auth_header, data=json.dumps(payload), timeout=120) if deploy_r.status_code < 300: info("deploy proc %s successfully." % proc) info("deploy result detail:") try: result = deploy_r.json() msg = result.pop('msg', '') if msg: print msg.decode('string_escape') info("proc status: ") render_proc_status(result.get('proc'), output=output) except Exception: pprint.pprint(deploy_r.content) else: error("deploy proc %s fail : %s" % (proc, deploy_r.json()['msg'])) 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 login(phase, cid=None, secret=None, redirect_uri=None): """ Login specific phase, need open auth first cid: Client id get from the sso system, default: 3 secret: Client secret get from the sso system, default: lain-cli_admin redirect_uri: Redirect uri get from the sso system, default: https://example.com/ """ check_phase(phase) username = raw_input('SSO Username:'******'SSO Password:'******'sso Login failed, Please try again!') exit(1) docker_login_success = docker_login(phase, username, password) if not docker_login_success: error('docker Login failed, Please try again!') exit(1) info("Login successfully!")
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.")
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 validate_parameters(cpu, memory, numinstances): if all([cpu is None, memory is None, numinstances is None]): warn("please input at least one param in cpu/memory/numinstances") exit(1) if numinstances is not None: try: numinstances = int(numinstances) except ValueError: warn('invalid parameter: num_instances (%s) should be integer'%numinstances) exit(1) if numinstances <= 0: warn('invalid parameter: num_instances (%s) should > 0'%numinstances) exit(1) if cpu is not None: try: cpu = int(cpu) except ValueError: warn('invalid parameter: cpu (%s) should be integer'%cpu) exit(1) if cpu < 0: warn('invalid parameter: cpu (%s) should >= 0'%cpu) exit(1) if memory is not None: memory = str(memory) try: if humanfriendly.parse_size(memory) < 4194304: error('invalid parameter: memory (%s) should >= 4M'%memory) exit(1) except humanfriendly.InvalidSize: error('invalid parameter: memory (%s) humanfriendly.parse_size(memory) failed'%memory) exit(1) return cpu, memory, numinstances
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 deploy_app(phase, appname, console, auth_header, version, output): info("Begin deploy app %s to %s ..." % (appname, phase)) app_url = "http://%s/api/v1/apps/%s/" % (console, appname) apps_url = "http://%s/api/v1/apps/" % console app_r = requests.get(app_url, headers=auth_header) former_version, deploy_version = None, version if app_r.status_code == 200: operation = "upgrading" deploy_params = None if not is_resource_instance(appname): former_version = app_r.json()["app"]["metaversion"] exist, valid_version = check_meta_version(phase, appname, deploy_version) if not exist: print_available_version(deploy_version, valid_version) exit(1) if deploy_version: deploy_params = {"meta_version": deploy_version} else: deploy_version = valid_version deploy_r = requests.put(app_url, headers=auth_header, json=deploy_params) elif app_r.status_code == 404: operation = "deploying" payload = {'appname': appname} deploy_r = requests.post(apps_url, headers=auth_header, data=json.dumps(payload), timeout=120) else: error("shit happend: %s" % app_r.content) exit(1) if deploy_r.status_code < 300: if output != 'pretty': info("%s" % deploy_r.json()['msg']) info("app status: ") render_app_status(deploy_r.json()['app'], output=output) else: result = check_deploy_result(operation, console, appname, auth_header) if result != 'Done': error("deploy latest version of %s to %s failed: %s" % (appname, phase, result)) exit(1) if former_version: info("app {} deploy operation:".format(appname)) info(" last version: {}".format(former_version)) info(" this version: {}".format(deploy_version)) info("if shit happened, rollback your app by:") info(" lain deploy -v {}".format(former_version)) else: error("deploy latest version of %s to %s failed: %s" % (appname, phase, deploy_r.json()['msg'])) exit(1)
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 _check_phase_tag(phase): 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 metatag = "meta-%s"%meta_version releasetag = "release-%s"%meta_version tag_list = docker.get_tag_list_in_registry(registry, yml.appname) tag_ok = True if metatag not in tag_list: tag_ok = False error("%s/%s:%s not exist." % (registry, yml.appname, metatag)) else: info("%s/%s:%s exist." % (registry, yml.appname, metatag)) if releasetag not in tag_list: tag_ok = False error("%s/%s:%s not exist." % (registry, yml.appname, releasetag)) else: info("%s/%s:%s exist." % (registry, yml.appname, releasetag)) return tag_ok