Exemple #1
0
def wait_for_fargate_cluster_status(
    cluster_name: str,
    cluster_stats: ClusterStatus,
    timeout_seconds: int = CLUSTER_PROVISION_TIMEOUT,
) -> None:
    """
    Waits for a cluster to to reach a desired status by polling the current
    state of the cluster
    """
    cluster_provisioned = False
    wait_time = 0

    log_info(f"Waiting for cluster to reach {cluster_stats.value} state...")
    while not cluster_provisioned and wait_time < timeout_seconds:
        cluster_info = describe_fargate_cluster(cluster_name)

        if len(cluster_info["failures"]) > 0:
            break

        cluster_provisioned = all([
            c["status"] == cluster_stats.value
            for c in cluster_info["clusters"]
        ], )

        sleep(2)
        wait_time += 2

    if not cluster_provisioned:
        log_error("Cluster failed to provision")
        raise Abort()
Exemple #2
0
def wait_for_tasks_to_start(
    cluster_name: str,
    tasks: List[TaskTypeDef],
    timeout_seconds: int = TASK_BOOT_TIMEOUT,
) -> None:
    """
    Waits for all of the tasks to reach their desired state by polling
    the current state of the tasks
    """
    task_arns = [t["taskArn"] for t in tasks]

    tasks_started = False
    wait_time = 0

    log_info("Waiting for bastion task to start...")
    while not tasks_started and wait_time < timeout_seconds:
        task_info = describe_task(cluster_name, task_arns)

        if not task_info or len(task_info["failures"]) > 0:
            break

        tasks_started = all([
            t["lastStatus"] == t["desiredStatus"] for t in task_info["tasks"]
        ], )

        sleep(2)
        wait_time += 2

    if not tasks_started:
        log_error("Bastion task failed to start")
        raise Abort()
Exemple #3
0
def delete_fargate_cluster(cluster_name: str) -> None:
    """
    Deletes a given Fargate cluster
    """
    client: ECSClient = fetch_boto3_client("ecs")

    log_info("Deleting Fargate cluster")

    try:
        client.delete_cluster(cluster=cluster_name)
    except client.exceptions.ClusterNotFoundException:
        log_error(f"Failed to find {cluster_name} Fargate cluster")
        raise Abort()

    wait_for_fargate_cluster_status(cluster_name, ClusterStatus.INACTIVE)
def get_tag_value(
    service: str,
    tags: List[Any],
    tag_key: str,
) -> str:
    """
    Given a list of tags in key value format, returns a matching
    tag value if one is found.
    """
    capitalize = capitalize_tag_kv(service)
    matches = [
        t[f"{'V' if capitalize else 'v'}alue"]
        for t in tags
        if t[f"{'K' if capitalize else 'k'}ey"] == tag_key
    ]
    if len(matches) != 1:
        log_error(
            f"Oops it looks like we're unable to find a match for tag {tag_key}."
            "Please open an issue to help us get this fixed!",
        )
        raise Abort()

    return matches[0]
Exemple #5
0
def launch_fargate_task(
    cluster_name: str,
    subnet_ids: str,
    security_group_ids: str,
    authorized_keys: str,
    instance_name: str,
    timeout_minutes: int,
    bastion_type: BastionType,
) -> RunTaskResponseTypeDef:
    """
    Launches the ssh bastion Fargate task into the proper subnets & security groups,
    also sends in the authorized keys.
    """
    client: ECSClient = fetch_boto3_client("ecs")

    bastion_id = str(uuid4())

    activation: Dict[str, str] = {}
    if bastion_type == BastionType.ssm:
        activation = create_activation(TASK_ROLE_NAME, instance_name,
                                       bastion_id)  # type: ignore

    log_info("Starting bastion task")
    try:
        response = client.run_task(
            cluster=cluster_name,
            taskDefinition=DEFAULT_NAME,
            overrides={
                "containerOverrides": [
                    {
                        "name":
                        DEFAULT_NAME,
                        "environment": [
                            {
                                "name": "AUTHORIZED_SSH_KEYS",
                                "value": authorized_keys
                            },
                            {
                                "name": "ACTIVATION_ID",
                                "value": activation.get("ActivationId", ""),
                            },
                            {
                                "name": "ACTIVATION_CODE",
                                "value": activation.get("ActivationCode", ""),
                            },
                            {
                                "name": "AWS_REGION",
                                "value": load_aws_region_name()
                            },
                            {
                                "name": "TIMEOUT",
                                "value": str(timeout_minutes * 60)
                            },
                            {
                                "name": "BASTION_TYPE",
                                "value": bastion_type.value
                            },
                        ],
                    },
                ],
            },
            count=1,
            launchType="FARGATE",
            networkConfiguration={
                "awsvpcConfiguration": {
                    "subnets": subnet_ids.split(","),
                    "securityGroups": security_group_ids.split(","),
                    "assignPublicIp": "ENABLED",
                },
            },
            tags=build_tags(
                "ecs",
                {
                    "Name": f"{DEFAULT_NAME}/{instance_name}",
                    "BastionId": bastion_id,
                    "ActivationId": activation.get("ActivationId", ""),
                },
            ),
        )

    except client.exceptions.ClusterNotFoundException:
        log_error(
            "Specified cluster to launch bastion task into doesn't exist")
        raise Abort()

    except (
            client.exceptions.ClientException,
            client.exceptions.InvalidParameterException,
    ) as e:
        log_error(e.response["Error"]["Message"])
        raise Abort()

    wait_for_tasks_to_start(cluster_name, response["tasks"])
    return response