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 _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 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_images_batch(context: "Context", images: List[Tuple[str, Optional[str], Optional[str], List[str]]]) -> None: _logger.debug("images:\n%s", images) new_images_manifest = {name: getattr(context.images, name) for name in context.images.names} max_workers = 5 with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: futures: List[Future[Any]] = [] name: str = "" dir: Optional[str] = None script: Optional[str] = None build_args: List[str] = [] for name, dir, script, build_args in images: _logger.debug("name: %s | script: %s", name, script) path = os.path.join(os.getcwd(), "bundle", name) _logger.debug("path: %s", path) image_attr_name = name.replace("-", "_") image_def: ImageManifest = getattr(context.images, image_attr_name) tag = image_def.version if image_def.get_source(account_id=context.account_id, region=context.region) == "code": dirs: List[Tuple[str, str]] = [(path, cast(str, dir))] else: dirs = [] bundle_path = bundle.generate_bundle(command_name=f"deploy_image-{name}", context=context, dirs=dirs) _logger.debug("bundle_path: %s", bundle_path) 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=False, cmds_build=[ "orbit remote --command _deploy_image " f"{context.name} {name} {dir} {script_str} {' '.join(build_args)}" ], ) new_images_manifest[image_attr_name] = ImageManifest( repository=f"{context.account_id}.dkr.ecr.{context.region}.amazonaws.com/orbit-{context.name}/{name}", version=tag, path=None, ) futures.append(executor.submit(_deploy_image_remotely, context, name, bundle_path, buildspec)) for f in futures: f.result() context.images = ImagesManifest(**new_images_manifest) ContextSerDe.dump_context_to_ssm(context=context)
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 _deploy_images_batch( context: "Context", images: List[Tuple[str, Optional[str], Optional[str], List[str]]]) -> None: _logger.debug("images:\n%s", images) with concurrent.futures.ThreadPoolExecutor( max_workers=len(images)) as executor: futures: List[Future[Any]] = [] name: str = "" dir: Optional[str] = None script: Optional[str] = None build_args: List[str] = [] for name, dir, script, build_args in images: _logger.debug("name: %s | script: %s", name, script) path = os.path.join(os.getcwd(), "bundle", name) _logger.debug("path: %s", path) if getattr(context.images, name.replace("-", "_")).source == "code": dirs: List[Tuple[str, str]] = [(path, cast(str, dir))] else: dirs = [] bundle_path = bundle.generate_bundle( command_name=f"deploy_image-{name}", context=context, dirs=dirs) _logger.debug("bundle_path: %s", bundle_path) 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=False, cmds_build=[ "orbit remote --command _deploy_image " f"{context.name} {name} {dir} {script_str} {' '.join(build_args)}" ], ) futures.append( executor.submit(_deploy_image_remotely, context, name, bundle_path, buildspec)) for f in futures: f.result()
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_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)