def deploy_toolkit( context: "Context", username: Optional[str], password: Optional[str], msg_ctx: MessagesContext, top_level: str = "orbit", ) -> None: credential_received: bool = username is not None and password is not None stack_exist: bool = cfn.does_stack_exist( stack_name=context.toolkit.stack_name) credential_exist: bool = dockerhub.does_credential_exist( context=context) if stack_exist else False image_manifests = [ cast(ImageManifest, getattr(context.images, i)) for i in context.images.names ] credential_required: bool = any([ im.get_source(account_id=context.account_id, region=context.region) == "dockerhub" for im in image_manifests ]) if stack_exist: if credential_required and not credential_exist and not credential_received: username, password = _request_dockerhub_credential(msg_ctx=msg_ctx) dockerhub.store_credential(context=context, username=username, password=password) credential_exist = True elif credential_received: dockerhub.store_credential( context=context, username=cast(str, username), password=cast(str, password), ) credential_exist = True else: context.toolkit.deploy_id = "".join( random.choice(string.ascii_lowercase) for i in range(6)) if credential_required and not credential_received: username, password = _request_dockerhub_credential(msg_ctx=msg_ctx) credential_exist = False msg_ctx.progress(6) _logger.debug("context.toolkit.deploy_id: %s", context.toolkit.deploy_id) template_filename: str = toolkit.synth(context=context, top_level=top_level) cfn.deploy_template(stack_name=context.toolkit.stack_name, filename=template_filename, env_tag=context.env_tag, s3_bucket=None) ContextSerDe.fetch_toolkit_data(context=context) ContextSerDe.dump_context_to_ssm(context=context) if credential_exist is False: dockerhub.store_credential( context=context, username=cast(str, username), password=cast(str, password), )
def deploy_credentials(filename: str, username: str, password: str, registry: str, debug: bool) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(2) manifest: "Manifest" = ManifestSerDe.load_manifest_from_file(filename=filename, type=Manifest) msg_ctx.info(f"Manifest loaded: {filename}") msg_ctx.progress(3) context_parameter_name: str = f"/orbit/{manifest.name}/context" if not ssm.does_parameter_exist(name=context_parameter_name): msg_ctx.error(f"Orbit Environment {manifest.name} cannot be found in the current account and region.") return context: "Context" = ContextSerDe.load_context_from_manifest(manifest=manifest) msg_ctx.info("Current Context loaded") msg_ctx.progress(4) msg_ctx.info("Encrypting credentials with Toolkit KMS Key") ciphertext = kms.encrypt( context=context, plaintext=json.dumps({registry: {"username": username, "password": password}}) ) msg_ctx.progress(20) msg_ctx.info("Starting Remote CodeBuild to deploy credentials") deploy.deploy_credentials(env_name=context.name, ciphertext=ciphertext) msg_ctx.info("Registry Credentials deployed") msg_ctx.progress(98) if cfn.does_stack_exist(stack_name=context.env_stack_name): context = ContextSerDe.load_context_from_ssm(env_name=manifest.name, type=Context) msg_ctx.info(f"Context updated: {filename}") msg_ctx.progress(100)
def build_profile(env: str, team: str, profile: str, debug: bool) -> None: with MessagesContext("Adding profile", debug=debug) as msg_ctx: msg_ctx.info("Retrieving existing profiles") profiles: List[Dict[str, Any]] = read_user_profiles_ssm(env, team) _logger.debug("Existing user profiles for team %s: %s", team, profiles) profiles_new = json.loads(profile) if isinstance(profiles_new, dict): profile_json_list = [cast(Dict[str, Any], profiles_new)] else: profile_json_list = cast(List[Dict[str, Any]], profiles_new) for profile_json in profile_json_list: if "slug" not in profile_json: # generate missing slug fields from display_name profile_json["slug"] = slugify(profile_json["display_name"]) if "slug" not in profile_json: raise Exception( "Profile document must include property 'slug'") _logger.debug(f"new profile name: {profile_json['display_name']}") for p in profiles: if p["slug"] == profile_json["slug"]: _logger.info("Profile exists, updating...") profiles.remove(p) break profiles.append(profile_json) msg_ctx.tip(f"Profile added {profile_json['display_name']}") _logger.debug("Updated user profiles for team %s: %s", team, profiles) write_context_ssm(profiles, env, team) msg_ctx.progress(100)
def destroy_toolkit( env: str, debug: bool, ) -> None: with MessagesContext("Destroying Environment Toolkit", debug=debug) as msg_ctx: msg_ctx.progress(10) context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Context loaded") msg_ctx.progress(25) try: _destroy_toolkit(env_name=context.name) except botocore.exceptions.ClientError as ex: error = ex.response["Error"] if "does not exist" not in error["Message"]: raise _logger.debug(f"Skipping toolkit destroy: {error['Message']}") msg_ctx.info("Toolkit destroyed") ssm.cleanup_env(env_name=context.name) msg_ctx.info("Toolkit destroyed") msg_ctx.progress(100)
def init(name: str, region: Optional[str], foundation: bool, debug: bool) -> None: conf_dir = "conf" with MessagesContext("Initializing", debug=debug) as ctx: conf_dir_src = os.path.join(ORBIT_CLI_ROOT, "data", "init") if os.path.exists(conf_dir): shutil.rmtree(conf_dir) foundation_manifest = "default-foundation.yaml" env_manifest = "default-env-manifest.yaml" shutil.copytree(src=conf_dir_src, dst=conf_dir) ctx.progress(50) name = name.lower() write_resolve_parameters( name=name, filename=os.path.join(conf_dir, foundation_manifest), region=region, manifest_name=foundation_manifest, ) write_resolve_parameters(name=name, filename=os.path.join(conf_dir, env_manifest), region=region, manifest_name=env_manifest) ctx.info("Env Manifest generated into conf folder") ctx.progress(100) if foundation: ctx.tip( f"Recommended next step: {stylize(f'orbit deploy foundation -f {foundation_manifest}')}" ) ctx.tip(f"Then, fill up the manifest file ({env_manifest}) " f"and run: " f"{stylize(f'orbit env -f {env_manifest}')}")
def build_image( env: str, dir: Optional[str], name: str, script: Optional[str], build_args: Optional[List[str]], timeout: int = 30, debug: bool = False, source_registry: Optional[str] = None, source_repository: Optional[str] = None, source_version: Optional[str] = None, ) -> None: with MessagesContext("Deploying Docker Image", debug=debug) as msg_ctx: context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Manifest loaded") if cfn.does_stack_exist(stack_name=f"orbit-{context.name}") is False: msg_ctx.error("Please, deploy your environment before deploying any additional docker image") return msg_ctx.progress(3) if dir: dirs = [(dir, name)] else: dirs = [] bundle_path = bundle.generate_bundle(command_name=f"deploy_image-{name}", context=context, dirs=dirs) msg_ctx.progress(5) script_str = "NO_SCRIPT" if script is None else script source_str = "NO_REPO" if source_registry is None else f"{source_registry} {source_repository} {source_version}" build_args = [] if build_args is None else build_args buildspec = codebuild.generate_spec( context=context, plugins=False, cmds_build=[ f"orbit remote --command build_image " f"{env} {name} {script_str} {source_str} {' '.join(build_args)}" ], changeset=None, ) msg_ctx.progress(6) remote.run( command_name=f"deploy_image-{name}", context=context, bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=timeout, ) msg_ctx.info("Docker Image deploy into ECR") address = ( f"{context.account_id}.dkr.ecr.{context.region}.amazonaws.com/orbit-{context.name}/{name}" if name in [n.replace("_", "-") for n in context.images.names] else f"{context.account_id}.dkr.ecr.{context.region}.amazonaws.com/orbit-{context.name}/users/{name}" ) msg_ctx.info(f"ECR Image Address={address}") msg_ctx.tip(f"ECR Image Address: {stylize(address, underline=True)}") msg_ctx.progress(100)
def destroy_env(env: str, debug: bool) -> None: with MessagesContext("Destroying", debug=debug) as msg_ctx: ssm.cleanup_changeset(env_name=env) ssm.cleanup_manifest(env_name=env) if ssm.does_parameter_exist(name=f"/orbit/{env}/context") is False: msg_ctx.info(f"Environment {env} not found. Destroying only possible remaining resources.") elb.delete_load_balancers(env_name=env) destroy_remaining_resources(env_name=env, top_level="orbit") msg_ctx.progress(100) return context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Context loaded") msg_ctx.info(f"Teams: {','.join([t.name for t in context.teams])}") msg_ctx.progress(2) if any(cfn.does_stack_exist(stack_name=t.stack_name) for t in context.teams): msg_ctx.error("Found Teams dependent on the Envrionment.") return if ( cfn.does_stack_exist(stack_name=context.env_stack_name) or cfn.does_stack_exist(stack_name=context.toolkit.stack_name) or cfn.does_stack_exist(stack_name=context.cdk_toolkit.stack_name) ): bundle_path = bundle.generate_bundle(command_name="destroy", context=context) msg_ctx.progress(5) buildspec = codebuild.generate_spec( context=context, plugins=True, cmds_build=[f"orbit remote --command destroy_env {env}"], changeset=None, ) remote.run( command_name="destroy", context=context, bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=45, ) msg_ctx.info("Env destroyed") msg_ctx.progress(95) try: destroy_toolkit(env_name=context.name) except botocore.exceptions.ClientError as ex: error = ex.response["Error"] if "does not exist" not in error["Message"]: raise _logger.debug(f"Skipping toolkit destroy: {error['Message']}") msg_ctx.info("Toolkit destroyed") ssm.cleanup_env(env_name=context.name) msg_ctx.progress(100)
def _request_dockerhub_credential(msg_ctx: MessagesContext) -> Tuple[str, str]: if msg_ctx.pbar is not None: msg_ctx.pbar.clear() msg_ctx.info("When Container Images are from Dockerhub, " "a Dockerhub login is required.") username = cast( str, click.prompt("Please enter the DockerHub username", type=str, hide_input=False), ) password = cast( str, click.prompt("Please enter the DockerHub password", type=str, hide_input=True), ) return username, password
def _deploy_image( env: str, dir: str, name: str, script: Optional[str], build_args: Optional[List[str]], region: Optional[str], debug: bool, ) -> None: with MessagesContext("Deploying Docker Image", debug=debug) as msg_ctx: context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) if cfn.does_stack_exist(stack_name=f"orbit-{context.name}") is False: msg_ctx.error( "Please, deploy your environment before deploy any addicional docker image" ) return plugins.PLUGINS_REGISTRIES.load_plugins( context=context, msg_ctx=msg_ctx, plugin_changesets=[], teams_changeset=None, ) msg_ctx.progress(3) bundle_path = bundle.generate_bundle( command_name=f"deploy_image-{name}", context=context, dirs=[(dir, name)]) msg_ctx.progress(4) script_str = "NO_SCRIPT" if script is None else script build_args = [] if build_args is None else build_args buildspec = codebuild.generate_spec( context=context, plugins=True, cmds_build=[ f"orbit remote --command _deploy_image {env} {name} {dir} {script_str} {' '.join(build_args)}" ], changeset=None, ) remote.run( command_name=f"deploy_image-{name}", context=context, bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=30, ) msg_ctx.info("Docker Image deploy into ECR") address = f"{context.account_id}.dkr.ecr.{context.region}.amazonaws.com/orbit-{context.name}-{name}" msg_ctx.tip(f"ECR Image Address: {stylize(address, underline=True)}") msg_ctx.progress(100)
def deploy_env( filename: str, debug: bool, ) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(2) manifest: "Manifest" = ManifestSerDe.load_manifest_from_file(filename=filename, type=Manifest) msg_ctx.info(f"Manifest loaded: {filename}") msg_ctx.progress(5) manifest_dir: str = os.path.dirname(os.path.abspath(filename)) _logger.debug("manifest directory is set to %s", manifest_dir) manifest_validations(manifest) context: "Context" = ContextSerDe.load_context_from_manifest(manifest=manifest) msg_ctx.info("Current Context loaded") msg_ctx.progress(10) _logger.debug("Inspecting possible manifest changes...") changeset: "Changeset" = extract_changeset(manifest=manifest, context=context, msg_ctx=msg_ctx) _logger.debug(f"Changeset:\n{dump_changeset_to_str(changeset=changeset)}") msg_ctx.progress(15) _deploy_toolkit( context=context, ) msg_ctx.info("Toolkit deployed") msg_ctx.progress(30) deploy.deploy_env( env_name=context.name, manifest_dir=manifest_dir, ) msg_ctx.info("Orbit Workbench deployed") msg_ctx.progress(98) if cfn.does_stack_exist(stack_name=context.env_stack_name): context = ContextSerDe.load_context_from_manifest(manifest=manifest) msg_ctx.info(f"Context updated: {filename}") msg_ctx.progress(99) if context.cognito_users_url: msg_ctx.tip(f"Add users: {stylize(context.cognito_users_url, underline=True)}") else: RuntimeError("Cognito Users URL not found.") if context.landing_page_url: msg_ctx.tip(f"Access Orbit Workbench: {stylize(f'{context.landing_page_url}/orbit/login', underline=True)}") else: RuntimeError("Landing Page URL not found.") msg_ctx.progress(100)
def destroy_foundation(env: str, debug: bool) -> None: with MessagesContext("Destroying", debug=debug) as msg_ctx: ssm.cleanup_changeset(env_name=env, top_level="orbit-foundation") ssm.cleanup_manifest(env_name=env, top_level="orbit-foundation") if ssm.does_parameter_exist(name=f"/orbit-foundation/{env}/context") is False: msg_ctx.info(f"Foundation {env} not found. Destroying only possible remaining resources.") destroy_remaining_resources(env_name=env, top_level="orbit-foundation") msg_ctx.progress(100) return context: "FoundationContext" = ContextSerDe.load_context_from_ssm(env_name=env, type=FoundationContext) msg_ctx.info("Context loaded") msg_ctx.progress(2) msg_ctx.progress(4) if ( cfn.does_stack_exist(stack_name=cast(str, context.stack_name)) or cfn.does_stack_exist(stack_name=context.toolkit.stack_name) or cfn.does_stack_exist(stack_name=context.cdk_toolkit.stack_name) ): bundle_path = bundle.generate_bundle(command_name="destroy", context=cast(Context, context)) msg_ctx.progress(5) buildspec = codebuild.generate_spec( context=cast(Context, context), plugins=False, cmds_build=[f"orbit remote --command destroy_foundation {env}"], changeset=None, ) remote.run( command_name="destroy", context=cast(Context, context), bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=45, ) msg_ctx.info("Foundation destroyed") msg_ctx.progress(95) try: destroy_toolkit(env_name=context.name, top_level="orbit-foundation") except botocore.exceptions.ClientError as ex: error = ex.response["Error"] if "does not exist" not in error["Message"]: raise _logger.debug(f"Skipping toolkit destroy: {error['Message']}") msg_ctx.info("Toolkit destroyed") ssm.cleanup_env(env_name=context.name, top_level="orbit-foundation") msg_ctx.progress(100)
def deploy_teams( filename: str, debug: bool, ) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(2) manifest: "Manifest" = ManifestSerDe.load_manifest_from_file(filename=filename, type=Manifest) msg_ctx.info(f"Manifest loaded: {filename}") msg_ctx.info(f"Teams: {','.join([t.name for t in manifest.teams])}") msg_ctx.progress(5) manifest_dir: str = os.path.dirname(os.path.abspath(filename)) _logger.debug("manifest directory is set to %s", manifest_dir) context_parameter_name: str = f"/orbit/{manifest.name}/context" if not ssm.does_parameter_exist(name=context_parameter_name): msg_ctx.error(f"Orbit Environment {manifest.name} cannot be found in the current account and region.") return context: "Context" = ContextSerDe.load_context_from_manifest(manifest=manifest) msg_ctx.info("Current Context loaded") msg_ctx.info(f"Teams: {','.join([t.name for t in context.teams])}") msg_ctx.progress(10) _logger.debug("Inspecting possible manifest changes...") changeset: "Changeset" = extract_changeset(manifest=manifest, context=context, msg_ctx=msg_ctx) _logger.debug(f"Changeset:\n{dump_changeset_to_str(changeset=changeset)}") msg_ctx.progress(30) deploy.deploy_teams( env_name=context.name, manifest_dir=manifest_dir, ) msg_ctx.info("Orbit Workbench deployed") msg_ctx.progress(98) if cfn.does_stack_exist(stack_name=context.env_stack_name): context = ContextSerDe.load_context_from_ssm(env_name=manifest.name, type=Context) msg_ctx.info(f"Context updated: {filename}") msg_ctx.progress(99) if context.user_pool_id: cognito_users_url = orbit_cognito.get_users_url(user_pool_id=context.user_pool_id, region=context.region) msg_ctx.tip(f"Add users: {stylize(cognito_users_url, underline=True)}") if context.landing_page_url: msg_ctx.tip(f"Access Orbit Workbench: {stylize(f'{context.landing_page_url}/orbit/login', underline=True)}") else: raise RuntimeError("Landing Page URL not found.") msg_ctx.progress(100)
def destroy_env(env: str, preserve_credentials: bool, debug: bool) -> None: with MessagesContext("Destroying", debug=debug) as msg_ctx: ssm.cleanup_changeset(env_name=env) ssm.cleanup_manifest(env_name=env) if ssm.does_parameter_exist(name=f"/orbit/{env}/context") is False: msg_ctx.info( f"Environment {env} not found. Destroying only possible remaining resources." ) elb.delete_load_balancers(env_name=env) destroy_remaining_resources(env_name=env, top_level="orbit") msg_ctx.progress(100) return msg_ctx.progress(15) context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Context loaded") msg_ctx.info(f"Teams: {','.join([t.name for t in context.teams])}") if any( cfn.does_stack_exist(stack_name=t.stack_name) for t in context.teams): raise click.ClickException( "Found Teams dependent on the Envrionment.") if (cfn.does_stack_exist(stack_name=context.env_stack_name) or cfn.does_stack_exist(stack_name=context.toolkit.stack_name) or cfn.does_stack_exist( stack_name=context.cdk_toolkit.stack_name)): msg_ctx.progress(50) destroy.destroy_env(env_name=context.name) if not preserve_credentials: secretsmanager.delete_docker_credentials( secret_id=f"orbit-{context.name}-docker-credentials") _logger.info("Removed docker credentials from SecretsManager") try: if context.cdk_toolkit.s3_bucket: s3.delete_bucket(bucket=context.cdk_toolkit.s3_bucket) except Exception as ex: _logger.debug( "Skipping Environment CDK Toolkit bucket deletion. Cause: %s", ex) msg_ctx.info("Env destroyed leaving the Env toolkit") msg_ctx.progress(100)
def destroy_credentials(env: str, registry: str, debug: bool) -> None: with MessagesContext("Destroying", debug=debug) as msg_ctx: context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Context loaded") msg_ctx.progress(2) if any( cfn.does_stack_exist(stack_name=t.stack_name) for t in context.teams): destroy.destroy_credentials(env_name=env, registry=registry) msg_ctx.progress(95) msg_ctx.info("Registry Credentials Destroyed") msg_ctx.progress(100)
def destroy_teams(env: str, debug: bool) -> None: with MessagesContext("Destroying", debug=debug) as msg_ctx: ssm.cleanup_changeset(env_name=env) if not ssm.list_parameters(prefix=f"/orbit/{env}/teams/"): msg_ctx.info(f"No {env} Teams found.") msg_ctx.progress(100) return context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Context loaded") msg_ctx.info(f"Teams: {','.join([t.name for t in context.teams])}") msg_ctx.progress(2) plugins.PLUGINS_REGISTRIES.load_plugins( context=context, msg_ctx=msg_ctx, plugin_changesets=[], teams_changeset=None, ) msg_ctx.progress(4) if any( cfn.does_stack_exist(stack_name=t.stack_name) for t in context.teams): bundle_path = bundle.generate_bundle(command_name="destroy", context=context) msg_ctx.progress(5) buildspec = codebuild.generate_spec( context=context, plugins=True, cmds_build=[f"orbit remote --command destroy_teams {env}"], changeset=None, ) remote.run( command_name="destroy", context=context, bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=45, ) msg_ctx.progress(95) msg_ctx.info("Teams Destroyed") msg_ctx.progress(100)
def delete_profile(env: str, team: str, profile_name: str, debug: bool) -> None: with MessagesContext("Profile Deleted", debug=debug) as msg_ctx: msg_ctx.info("Retrieving existing profiles") profiles: List[Dict[str, Any]] = read_user_profiles_ssm(env, team) _logger.debug("Existing user profiles for team %s: %s", team, profiles) for p in profiles: if p["slug"] == profile_name: _logger.info("Profile exists, deleting...") profiles.remove(p) _logger.debug("Updated user profiles for team %s: %s", team, profiles) write_context_ssm(profiles, env, team) msg_ctx.tip("Profile deleted") msg_ctx.progress(100) return raise Exception(f"Profile {profile_name} not found")
def deploy_images(debug: bool, filename: str, reqested_image: Optional[str] = None) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(2) manifest: "Manifest" = ManifestSerDe.load_manifest_from_file(filename=filename, type=Manifest) msg_ctx.info(f"Manifest loaded: {filename}") msg_ctx.progress(3) context_parameter_name: str = f"/orbit/{manifest.name}/context" if not ssm.does_parameter_exist(name=context_parameter_name): msg_ctx.error(f"Orbit Environment {manifest.name} cannot be found in the current account and region.") return env = manifest.name msg_ctx.info(f"Deploying images for env {env}") deploy.deploy_images_remotely(env=env, requested_image=reqested_image) msg_ctx.progress(95) msg_ctx.progress(100)
def delete_podsetting(namespace: str, podsetting_name: str, debug: bool) -> None: with MessagesContext("Podsetting Deleted", debug=debug) as msg_ctx: msg_ctx.info("Recieved request to delete podsetting") _logger.debug( f"Recieved request to delete podsetting {podsetting_name} in namespace {namespace}" ) try: import aws_orbit_sdk.controller as controller controller.delete_podsetting(namespace=namespace, podsetting_name=podsetting_name) except ImportError: raise ImportError("Make sure the Orbit SDK is installed") msg_ctx.tip("Podsetting deleted") msg_ctx.progress(100) return
def build_podsetting( env_name: str, team_name: str, podsetting: str, debug: bool = False, ) -> None: # Do some quick validation and fail fast with MessagesContext("Creating PodSetting", debug=debug) as msg_ctx: ps = json.loads(podsetting) msg_ctx.progress(3) _logger.debug(ps) if not ps["description"] or not ps["name"]: print("raise an error...") msg_ctx.error("Please, make sure the fields description and name are present") return ps_name = ps["name"] msg_ctx.progress(10) resources = ps.get("resources", None) if resources is not None: if ( "nvidia.com/gpu" in resources["limits"] or "nvidia.com/gpu" in resources["requests"] or "node.kubernetes.io/instance-type" in resources["requests"] or "node.kubernetes.io/instance-type" in resources["limits"] ): if ps.get("node-group") is None and ps.get("instance-type") is None: msg_ctx.error( "If you request a GPU, please define a node-group or instance-type to match your cluster / GPU" ) return msg_ctx.info("JSON payload validated") msg_ctx.progress(15) # Looks ok...call the SDK to build and deploy try: import aws_orbit_sdk.controller as controller controller.build_podsetting(env_name=env_name, team_name=team_name, podsetting=podsetting, debug=debug) except ImportError: raise ImportError("Make sure the Orbit SDK is installed") msg_ctx.info(f"PodSetting {ps_name} created") msg_ctx.progress(100)
def destroy_foundation(env: str, debug: bool) -> None: with MessagesContext("Destroying", debug=debug) as msg_ctx: ssm.cleanup_changeset(env_name=env, top_level="orbit-f") ssm.cleanup_manifest(env_name=env, top_level="orbit-f") if ssm.does_parameter_exist(name=f"/orbit-f/{env}/context") is False: msg_ctx.info( f"Foundation {env} not found. Destroying only possible remaining resources." ) destroy_remaining_resources(env_name=env, top_level="orbit-f") msg_ctx.progress(100) return context: "FoundationContext" = ContextSerDe.load_context_from_ssm( env_name=env, type=FoundationContext) msg_ctx.info("Context loaded") msg_ctx.progress(25) if (cfn.does_stack_exist(stack_name=cast(str, context.stack_name)) or cfn.does_stack_exist(stack_name=context.toolkit.stack_name) or cfn.does_stack_exist( stack_name=context.cdk_toolkit.stack_name)): destroy.destroy_foundation(env_name=context.name) msg_ctx.info("Foundation destroyed") msg_ctx.progress(75) try: _destroy_toolkit( env_name=context.name, top_level="orbit-f", cdk_toolkit_bucket=context.cdk_toolkit.s3_bucket, ) except botocore.exceptions.ClientError as ex: error = ex.response["Error"] if "does not exist" not in error["Message"]: raise _logger.debug(f"Skipping toolkit destroy: {error['Message']}") msg_ctx.info("Toolkit destroyed") ssm.cleanup_env(env_name=context.name, top_level="orbit-f") msg_ctx.progress(100)
def init(name: str, region: Optional[str], debug: bool) -> None: conf_dir = "conf" with MessagesContext("Initializing", debug=debug) as ctx: conf_dir_src = os.path.join(ORBIT_CLI_ROOT, "data", "init") if os.path.exists(conf_dir): shutil.rmtree(conf_dir) env_manifest = "default-env-manifest.yaml" shutil.copytree(src=conf_dir_src, dst=conf_dir) ctx.progress(50) name = name.lower() write_resolve_parameters(name=name, filename=os.path.join(conf_dir, env_manifest), region=region, manifest_name=env_manifest) p = os.getcwd() + "/" + conf_dir ctx.info(f"Env Manifest generated into conf folder at {p}") ctx.progress(100) ctx.tip(f"Please edit the manifest file ({env_manifest}) ")
def deploy_toolkit( filename: str, debug: bool, ) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(10) manifest: "Manifest" = ManifestSerDe.load_manifest_from_file(filename=filename, type=Manifest) msg_ctx.info(f"Manifest loaded: {filename}") msg_ctx.progress(25) context: "Context" = ContextSerDe.load_context_from_manifest(manifest=manifest) msg_ctx.info("Current Context loaded") msg_ctx.progress(45) _deploy_toolkit( context=context, ) msg_ctx.info("Toolkit deployed") msg_ctx.progress(100)
def delete_image(env: str, name: str, debug: bool) -> None: with MessagesContext("Destroying Docker Image", debug=debug) as msg_ctx: if not name: raise ValueError("Image name required to delete") ssm.cleanup_changeset(env_name=env) ssm.cleanup_manifest(env_name=env) context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Manifest loaded") if cfn.does_stack_exist(stack_name=f"orbit-{context.name}") is False: msg_ctx.error( "Please, deploy your environment before deploy/destroy any docker image" ) return msg_ctx.progress(3) delete.delete_image(env_name=env, image_name=name) msg_ctx.info("Docker Image destroyed from ECR") msg_ctx.progress(100)
def deploy_user_image( debug: bool, path: str, env: str, image_name: str, script: Optional[str], build_args: Optional[List[str]], timeout: int = 45, ) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: context_parameter_name: str = f"/orbit/{env}/context" if not ssm.does_parameter_exist(name=context_parameter_name): msg_ctx.error(f"Orbit Environment {env} cannot be found in the current account and region.") return msg_ctx.progress(2) deploy.deploy_user_image( path=path, image_name=image_name, env=env, script=script, build_args=build_args, timeout=timeout ) msg_ctx.progress(95) address = f"{get_account_id()}.dkr.ecr.{get_region()}.amazonaws.com/orbit-{env}/users/{image_name}" msg_ctx.info(f"ECR Image Address={address}") msg_ctx.tip(f"ECR Image Address: {stylize(address, underline=True)}") msg_ctx.progress(100)
def destroy_teams(env: str, debug: bool) -> None: with MessagesContext("Destroying", debug=debug) as msg_ctx: ssm.cleanup_changeset(env_name=env) if not ssm.list_parameters(prefix=f"/orbit/{env}/teams/"): msg_ctx.info(f"No {env} Teams found.") msg_ctx.progress(100) return msg_ctx.progress(15) context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Context loaded") msg_ctx.info(f"Teams: {','.join([t.name for t in context.teams])}") msg_ctx.progress(25) if any( cfn.does_stack_exist(stack_name=t.stack_name) for t in context.teams): destroy.destroy_teams(env_name=context.name) msg_ctx.progress(95) msg_ctx.info("Teams Destroyed") msg_ctx.progress(100)
def delete_image(env: str, name: str, debug: bool) -> None: with MessagesContext("Destroying Docker Image", debug=debug) as msg_ctx: ssm.cleanup_changeset(env_name=env) ssm.cleanup_manifest(env_name=env) context: "Context" = ContextSerDe.load_context_from_ssm(env_name=env, type=Context) msg_ctx.info("Manifest loaded") if cfn.does_stack_exist(stack_name=f"orbit-{context.name}") is False: msg_ctx.error("Please, deploy your environment before deploy/destroy any docker image") return plugins.PLUGINS_REGISTRIES.load_plugins( context=context, msg_ctx=msg_ctx, plugin_changesets=[], teams_changeset=None, ) msg_ctx.progress(3) bundle_path = bundle.generate_bundle(command_name=f"delete_image-{name}", context=context, dirs=[]) msg_ctx.progress(4) buildspec = codebuild.generate_spec( context=context, plugins=False, cmds_build=[f"orbit remote --command delete_image {env} {name}"], changeset=None, ) remote.run( command_name=f"delete_image-{name}", context=context, bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=10, ) msg_ctx.info("Docker Image destroyed from ECR") msg_ctx.progress(100)
def deploy_foundation( filename: Optional[str] = None, name: Optional[str] = None, debug: bool = False, internet_accessibility: bool = True, ssl_cert_arn: Optional[str] = None, custom_domain_name: Optional[str] = None, max_availability_zones: Optional[int] = None, role_prefix: Optional[str] = None, ) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(2) if filename: manifest: "FoundationManifest" = ManifestSerDe.load_manifest_from_file( filename=filename, type=FoundationManifest ) if name: msg_ctx.warn(f'Reading parameters from {filename}, "name" ignored.') elif name: if ssl_cert_arn: if not custom_domain_name: raise ValueError('If "ssl_cert_arn" is provided, "custom_domain_name" should be provided') if custom_domain_name: if not ssl_cert_arn: raise ValueError('If "custom_domain_name" is provided, "ssl_cert_arn" should be provided') manifest: FoundationManifest = FoundationManifest( # type: ignore name=name, ssm_parameter_name=f"/orbit-f/{name}/manifest", role_prefix=role_prefix, networking=NetworkingManifest( max_availability_zones=max_availability_zones, frontend=FrontendNetworkingManifest( ssl_cert_arn=ssl_cert_arn, custom_domain_name=custom_domain_name ), data=DataNetworkingManifest(internet_accessible=internet_accessibility), ), ) else: msg_ctx.error('One of "filename" or "name" is required') raise ValueError('One of "filename" or "name" is required') ManifestSerDe.dump_manifest_to_ssm(manifest=manifest) msg_ctx.info(f"Manifest loaded: {manifest.name}") msg_ctx.progress(3) context: FoundationContext = ContextSerDe.load_context_from_manifest(manifest=manifest) msg_ctx.info("Current Context loaded") msg_ctx.progress(4) _deploy_toolkit( context=cast(Context, context), top_level="orbit-f", ) msg_ctx.info("Toolkit deployed") msg_ctx.progress(50) deploy.deploy_foundation(env_name=context.name) msg_ctx.info("Orbit Foundation deployed") msg_ctx.progress(100)
def deploy_teams( filename: str, debug: bool, ) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(2) manifest: "Manifest" = ManifestSerDe.load_manifest_from_file( filename=filename, type=Manifest) msg_ctx.info(f"Manifest loaded: {filename}") msg_ctx.info(f"Teams: {','.join([t.name for t in manifest.teams])}") msg_ctx.progress(3) context: "Context" = ContextSerDe.load_context_from_manifest( manifest=manifest) msg_ctx.info("Current Context loaded") msg_ctx.info(f"Teams: {','.join([t.name for t in context.teams])}") msg_ctx.progress(4) _logger.debug("Inspecting possible manifest changes...") changeset: "Changeset" = extract_changeset(manifest=manifest, context=context, msg_ctx=msg_ctx) _logger.debug( f"Changeset:\n{dump_changeset_to_str(changeset=changeset)}") msg_ctx.progress(5) plugins.PLUGINS_REGISTRIES.load_plugins( context=context, msg_ctx=msg_ctx, plugin_changesets=changeset.plugin_changesets, teams_changeset=changeset.teams_changeset, ) msg_ctx.progress(7) _logger.debug("Preparing bundle directory") dirs: List[Tuple[str, str]] = [] dirs += _get_config_dirs(context=context, manifest_filename=filename) _logger.debug(f"*Directory={dirs}") dirs += _get_images_dirs(context=context, manifest_filename=filename, skip_images=True) _logger.debug(f"**Directory={dirs}") bundle_path = bundle.generate_bundle( command_name="deploy", context=context, dirs=dirs, ) msg_ctx.progress(11) buildspec = codebuild.generate_spec( context=context, plugins=True, cmds_build=[f"orbit remote --command deploy_teams {context.name}"], changeset=changeset, ) remote.run( command_name="deploy", context=context, bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=90, ) msg_ctx.info("Orbit Workbench deployed") msg_ctx.progress(98) if cfn.does_stack_exist(stack_name=context.env_stack_name): context = ContextSerDe.load_context_from_manifest( manifest=manifest) msg_ctx.info(f"Context updated: {filename}") msg_ctx.progress(99) if context.cognito_users_url: msg_ctx.tip( f"Add users: {stylize(context.cognito_users_url, underline=True)}" ) else: RuntimeError("Cognito Users URL not found.") if context.landing_page_url: msg_ctx.tip( f"Access Orbit Workbench: {stylize(context.landing_page_url, underline=True)}" ) else: RuntimeError("Landing Page URL not found.") msg_ctx.progress(100)
def deploy_env( filename: str, skip_images: bool, debug: bool, username: Optional[str] = None, password: Optional[str] = None, ) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(2) manifest: "Manifest" = ManifestSerDe.load_manifest_from_file( filename=filename, type=Manifest) msg_ctx.info(f"Manifest loaded: {filename}") msg_ctx.progress(3) context: "Context" = ContextSerDe.load_context_from_manifest( manifest=manifest) image_manifests = { "code_build": manifest.images.code_build, "landing_page": manifest.images.landing_page } for name in context.images.names: if name not in ["code_build", "image_replicator"]: image_manifests[name] = getattr( context.images, name) if skip_images else getattr( manifest.images, name) context.images = ImagesManifest(**image_manifests) # type: ignore msg_ctx.info("Current Context loaded") msg_ctx.progress(4) _logger.debug("Inspecting possible manifest changes...") changeset: "Changeset" = extract_changeset(manifest=manifest, context=context, msg_ctx=msg_ctx) _logger.debug( f"Changeset:\n{dump_changeset_to_str(changeset=changeset)}") msg_ctx.progress(5) deploy_toolkit( context=context, username=username, password=password, msg_ctx=msg_ctx, ) msg_ctx.info("Toolkit deployed") msg_ctx.progress(10) bundle_path = bundle.generate_bundle( command_name="deploy", context=context, dirs=_get_images_dirs(context=context, manifest_filename=filename, skip_images=skip_images), ) msg_ctx.progress(11) skip_images_remote_flag: str = "skip-images" if skip_images else "no-skip-images" buildspec = codebuild.generate_spec( context=context, plugins=True, cmds_build=[ f"orbit remote --command deploy_env {context.name} {skip_images_remote_flag}" ], changeset=changeset, ) remote.run( command_name="deploy", context=context, bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=90, ) msg_ctx.info("Orbit Workbench deployed") msg_ctx.progress(98) if cfn.does_stack_exist(stack_name=context.env_stack_name): context = ContextSerDe.load_context_from_manifest( manifest=manifest) msg_ctx.info(f"Context updated: {filename}") msg_ctx.progress(99) if context.cognito_users_url: msg_ctx.tip( f"Add users: {stylize(context.cognito_users_url, underline=True)}" ) else: RuntimeError("Cognito Users URL not found.") if context.landing_page_url: msg_ctx.tip( f"Access Orbit Workbench: {stylize(context.landing_page_url, underline=True)}" ) else: RuntimeError("Landing Page URL not found.") msg_ctx.progress(100)
def deploy_foundation( filename: Optional[str] = None, name: Optional[str] = None, debug: bool = False, internet_accessibility: bool = True, codeartifact_domain: Optional[str] = None, codeartifact_repository: Optional[str] = None, username: Optional[str] = None, password: Optional[str] = None, ) -> None: with MessagesContext("Deploying", debug=debug) as msg_ctx: msg_ctx.progress(2) if filename: manifest: "FoundationManifest" = ManifestSerDe.load_manifest_from_file( filename=filename, type=FoundationManifest) if name or codeartifact_domain or codeartifact_repository: msg_ctx.warn( f'Reading parameters from {filename}, "name", "codeartifact-domain", ' 'and "codeartifact-repository" ignored.') elif name: manifest: FoundationManifest = FoundationManifest( # type: ignore name=name, codeartifact_domain=codeartifact_domain, codeartifact_repository=codeartifact_repository, ssm_parameter_name=f"/orbit-foundation/{name}/manifest", networking=NetworkingManifest(data=DataNetworkingManifest( internet_accessible=internet_accessibility)), ) else: msg_ctx.error('One of "filename" or "name" is required') raise ValueError('One of "filename" or "name" is required') ManifestSerDe.dump_manifest_to_ssm(manifest=manifest) msg_ctx.info(f"Manifest loaded: {manifest.name}") msg_ctx.progress(3) context: FoundationContext = ContextSerDe.load_context_from_manifest( manifest=manifest) msg_ctx.info("Current Context loaded") msg_ctx.progress(4) deploy_toolkit( context=cast(Context, context), username=username, password=password, msg_ctx=msg_ctx, top_level="orbit-foundation", ) msg_ctx.info("Toolkit deployed") msg_ctx.progress(8) bundle_path = bundle.generate_bundle(command_name="deploy_foundation", context=cast(Context, context)) msg_ctx.progress(10) buildspec = codebuild.generate_spec( context=cast(Context, context), plugins=False, cmds_build=[ f"orbit remote --command deploy_foundation {context.name}" ], ) msg_ctx.progress(11) remote.run( command_name="deploy_foundation", context=cast(Context, context), bundle_path=bundle_path, buildspec=buildspec, codebuild_log_callback=msg_ctx.progress_bar_callback, timeout=90, ) msg_ctx.info("Orbit Foundation deployed") msg_ctx.progress(100)