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 load_context_from_ssm(env_name: str, type: Type[V]) -> V: if type is Context: context_parameter_name: str = f"/orbit/{env_name}/context" if ssm.does_parameter_exist(context_parameter_name): main = ssm.get_parameter(name=context_parameter_name) else: msg = f"SSM parameter {context_parameter_name} not found for env {env_name}" _logger.error(msg) raise Exception(msg) teams_parameters = ssm.list_parameters( prefix=f"/orbit/{env_name}/teams/") _logger.debug("teams_parameters: %s", teams_parameters) teams = [ ssm.get_parameter_if_exists(name=p) for p in teams_parameters if p.endswith("/context") ] main["Teams"] = [t for t in teams if t] return cast( V, Context.Schema().load(data=main, many=False, partial=False, unknown="RAISE")) elif type is FoundationContext: context_parameter_name = f"/orbit-foundation/{env_name}/context" main = ssm.get_parameter(name=context_parameter_name) return cast( V, FoundationContext.Schema().load(data=main, many=False, partial=False, unknown="RAISE")) else: raise ValueError("Unknown 'context' Type")
def _load_context_from_manifest(manifest: "Manifest") -> Context: _logger.debug("Loading Context from manifest") context_parameter_name: str = f"/orbit/{manifest.name}/context" if ssm.does_parameter_exist(name=context_parameter_name): context: Context = ContextSerDe.load_context_from_ssm( env_name=manifest.name, type=Context) context.networking = create_networking_context_from_manifest( networking=manifest.networking) context.user_pool_id = manifest.user_pool_id context.shared_efs_fs_id = manifest.shared_efs_fs_id context.shared_efs_sg_id = manifest.shared_efs_sg_id context.scratch_bucket_arn = manifest.scratch_bucket_arn context.policies = manifest.policies context.role_prefix = manifest.role_prefix context.cognito_external_provider = manifest.cognito_external_provider context.cognito_external_provider_label = manifest.cognito_external_provider_label else: context = Context( name=manifest.name, account_id=utils.get_account_id(), region=utils.get_region(), env_tag=f"orbit-{manifest.name}", env_stack_name=f"orbit-{manifest.name}", env_ssm_parameter_name=f"/orbit/{manifest.name}/env", eks_stack_name=f"eksctl-orbit-{manifest.name}-cluster", ssm_parameter_name=context_parameter_name, ssm_dockerhub_parameter_name= f"/orbit/{manifest.name}/dockerhub", toolkit=ToolkitManifest( stack_name=f"orbit-{manifest.name}-toolkit", codebuild_project=f"orbit-{manifest.name}", ), cdk_toolkit=CdkToolkitManifest( stack_name=f"orbit-{manifest.name}-cdk-toolkit"), role_prefix=manifest.role_prefix, scratch_bucket_arn=manifest.scratch_bucket_arn, networking=create_networking_context_from_manifest( networking=manifest.networking), images=manifest.images, user_pool_id=manifest.user_pool_id, cognito_external_provider=manifest.cognito_external_provider, cognito_external_provider_label=manifest. cognito_external_provider_label, teams=create_teams_context_from_manifest(manifest=manifest), shared_efs_fs_id=manifest.shared_efs_fs_id, shared_efs_sg_id=manifest.shared_efs_sg_id, managed_nodegroups=[], eks_system_masters_roles=[], policies=manifest.policies, install_ssm_agent=manifest.install_ssm_agent, install_image_replicator=manifest.install_image_replicator, ) context.install_ssm_agent = manifest.install_ssm_agent context.install_image_replicator = manifest.install_image_replicator ContextSerDe.fetch_toolkit_data(context=context) ContextSerDe.dump_context_to_ssm(context=context) return context
def _load_context_from_manifest(manifest: "Manifest") -> Context: _logger.debug("Loading Context from manifest") context_parameter_name: str = f"/orbit/{manifest.name}/context" if ssm.does_parameter_exist(name=context_parameter_name): context: Context = ContextSerDe.load_context_from_ssm( env_name=manifest.name, type=Context) context.images = manifest.images context.networking = create_networking_context_from_manifest( networking=manifest.networking) context.user_pool_id = manifest.user_pool_id context.shared_efs_fs_id = manifest.shared_efs_fs_id context.shared_efs_sg_id = manifest.shared_efs_sg_id context.scratch_bucket_arn = manifest.scratch_bucket_arn context.policies = manifest.policies for team_manifest in manifest.teams: team_context: Optional[TeamContext] = context.get_team_by_name( name=team_manifest.name) if team_context: _logger.debug("Updating context profiles for team %s", team_manifest.name) team_context.profiles = team_manifest.profiles else: context = Context( name=manifest.name, account_id=utils.get_account_id(), region=utils.get_region(), env_tag=f"orbit-{manifest.name}", env_stack_name=f"orbit-{manifest.name}", env_ssm_parameter_name=f"/orbit/{manifest.name}/env", eks_stack_name=f"eksctl-orbit-{manifest.name}-cluster", ssm_parameter_name=context_parameter_name, ssm_dockerhub_parameter_name= f"/orbit/{manifest.name}/dockerhub", toolkit=ToolkitManifest( stack_name=f"orbit-{manifest.name}-toolkit", codebuild_project=f"orbit-{manifest.name}"), cdk_toolkit=CdkToolkitManifest( stack_name=f"orbit-{manifest.name}-cdk-toolkit"), codeartifact_domain=manifest.codeartifact_domain, codeartifact_repository=manifest.codeartifact_repository, scratch_bucket_arn=manifest.scratch_bucket_arn, networking=create_networking_context_from_manifest( networking=manifest.networking), images=manifest.images, user_pool_id=manifest.user_pool_id, cognito_external_provider=manifest.cognito_external_provider, cognito_external_provider_label=manifest. cognito_external_provider_label, teams=create_teams_context_from_manifest(manifest=manifest), shared_efs_fs_id=manifest.shared_efs_fs_id, shared_efs_sg_id=manifest.shared_efs_sg_id, managed_nodegroups=[], eks_system_masters_roles=[], policies=manifest.policies, ) ContextSerDe.fetch_toolkit_data(context=context) ContextSerDe.dump_context_to_ssm(context=context) return context
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 create_teams_context_from_manifest( manifest: "Manifest") -> List[TeamContext]: teams: List[TeamContext] = [] for team in manifest.teams: ssm_parameter_name: str = f"/orbit/{manifest.name}/teams/{team.name}/context" if ssm.does_parameter_exist(name=ssm_parameter_name) is False: _logger.debug("Team %s is not deployed yet.", team.name) continue teams.append( create_team_context_from_manifest(manifest=manifest, team_manifest=team)) return teams
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 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 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 _load_foundation_context_from_manifest( manifest: "FoundationManifest") -> FoundationContext: _logger.debug("Loading Context from manifest") context_parameter_name: str = f"/orbit-foundation/{manifest.name}/context" if ssm.does_parameter_exist(name=context_parameter_name): context: FoundationContext = ContextSerDe.load_context_from_ssm( env_name=manifest.name, type=FoundationContext) context.images = manifest.images context.policies = manifest.policies context.codeartifact_domain = manifest.codeartifact_domain context.codeartifact_repository = manifest.codeartifact_repository else: context = FoundationContext( name=manifest.name, account_id=utils.get_account_id(), region=utils.get_region(), env_tag=f"orbit-foundation-{manifest.name}", ssm_parameter_name=context_parameter_name, resources_ssm_parameter_name= f"/orbit-foundation/{manifest.name}/resources", toolkit=ToolkitManifest( stack_name=f"orbit-foundation-{manifest.name}-toolkit", codebuild_project=f"orbit-foundation-{manifest.name}", ), cdk_toolkit=CdkToolkitManifest( stack_name=f"orbit-foundation-{manifest.name}-cdk-toolkit" ), codeartifact_domain=manifest.codeartifact_domain, codeartifact_repository=manifest.codeartifact_repository, networking=create_networking_context_from_manifest( networking=manifest.networking), images=manifest.images, policies=manifest.policies, stack_name=f"orbit-foundation-{manifest.name}", ) ContextSerDe.fetch_toolkit_data(context=context) ContextSerDe.dump_context_to_ssm(context=context) return context
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)