Esempio n. 1
0
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)
Esempio n. 3
0
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)
Esempio n. 5
0
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}')}")
Esempio n. 6
0
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)
Esempio n. 8
0
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
Esempio n. 9
0
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)
Esempio n. 11
0
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)
Esempio n. 15
0
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)
Esempio n. 16
0
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)
Esempio n. 18
0
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
Esempio n. 19
0
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)
Esempio n. 21
0
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)
Esempio n. 23
0
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)
Esempio n. 26
0
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)
Esempio n. 28
0
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)
Esempio n. 29
0
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)
Esempio n. 30
0
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)