Пример #1
0
def test_configure_security_group_with_network_interfaces_without_sg(
        ec2_client_stub):
    config = {
        "cluster_name": DEFAULT_CLUSTER_NAME,
        "provider": {
            "type": "aws",
            "region": "us-west-2"
        },
        "head_node": {
            "NetworkInterfaces": [{
                "SubnetId": DEFAULT_SUBNET["SubnetId"]
            }]
        },
        "worker_nodes": {
            "NetworkInterfaces": [{
                "SubnetId": DEFAULT_SUBNET["SubnetId"],
                "Groups": []
            }]
        }
    }

    stubs.describe_subnets_echo(ec2_client_stub, DEFAULT_SUBNET)
    stubs.describe_sgs_on_vpc(ec2_client_stub, [DEFAULT_SG["VpcId"]],
                              [DEFAULT_SG])
    stubs.authorize_sg_ingress(ec2_client_stub, DEFAULT_SG_WITH_RULES)
    stubs.describe_sg_echo(ec2_client_stub, DEFAULT_SG_WITH_RULES)

    new_config = _configure_security_group(config)
    assert new_config["head_node"]["NetworkInterfaces"][0]["Groups"] == [
        DEFAULT_SG["GroupId"]
    ]
    assert new_config["worker_nodes"]["NetworkInterfaces"][0]["Groups"] == [
        DEFAULT_SG["GroupId"]
    ]
Пример #2
0
def test_use_subnets_in_only_one_vpc(iam_client_stub, ec2_client_stub):
    """
    This test validates that when bootstrap_aws populates the SubnetIds field,
    all of the subnets used belong to the same VPC, and that a SecurityGroup
    in that VPC is correctly configured.
    """
    stubs.configure_iam_role_default(iam_client_stub)
    stubs.configure_key_pair_default(ec2_client_stub)

    # Add a response with a thousand subnets all in different VPCs.
    # After filtering, only subnet in one particular VPC should remain.
    # Thus head_node.SubnetIds and worker_nodes.SubnetIds should end up as
    # being length-one lists after the bootstrap_config.
    stubs.describe_a_thousand_subnets_in_different_vpcs(ec2_client_stub)

    # describe the subnet in use while determining its vpc
    stubs.describe_subnets_echo(ec2_client_stub, DEFAULT_SUBNET)
    # given no existing security groups within the VPC...
    stubs.describe_no_security_groups(ec2_client_stub)
    # expect to create a security group on the VPC
    stubs.create_sg_echo(ec2_client_stub, DEFAULT_SG)
    # expect new security group details to be retrieved after creation
    stubs.describe_sgs_on_vpc(
        ec2_client_stub,
        [DEFAULT_SUBNET["VpcId"]],
        [DEFAULT_SG],
    )

    # given no existing default security group inbound rules...
    # expect to authorize all default inbound rules
    stubs.authorize_sg_ingress(
        ec2_client_stub,
        DEFAULT_SG_WITH_RULES,
    )

    # expect another call to describe the above security group while checking
    # a second time if it has ip_permissions set ("if not sg.ip_permissions")
    stubs.describe_an_sg_2(
        ec2_client_stub,
        DEFAULT_SG_WITH_RULES,
    )

    # given our mocks and an example config file as input...
    # expect the config to be loaded, validated, and bootstrapped successfully
    config = helpers.bootstrap_aws_example_config_file("example-full.yaml")
    _get_vpc_id_or_die.cache_clear()

    # We've filtered down to only one subnet id -- only one of the thousand
    # subnets generated by ec2.subnets.all() belongs to the right VPC.
    assert config["head_node"]["SubnetIds"] == [DEFAULT_SUBNET["SubnetId"]]
    assert config["worker_nodes"]["SubnetIds"] == [DEFAULT_SUBNET["SubnetId"]]
    # Check that the security group has been filled correctly.
    assert config["head_node"]["SecurityGroupIds"] == [DEFAULT_SG["GroupId"]]
    assert config["worker_nodes"]["SecurityGroupIds"] == [
        DEFAULT_SG["GroupId"]
    ]
Пример #3
0
def test_create_sg_different_vpc_same_rules(iam_client_stub, ec2_client_stub):
    # use default stubs to skip ahead to security group configuration
    stubs.skip_to_configure_sg(ec2_client_stub, iam_client_stub)

    # given head and worker nodes with custom subnets defined...
    # expect to first describe the worker subnet ID
    stubs.describe_subnets_echo(ec2_client_stub, AUX_SUBNET)
    # expect to second describe the head subnet ID
    stubs.describe_subnets_echo(ec2_client_stub, DEFAULT_SUBNET)
    # given no existing security groups within the VPC...
    stubs.describe_no_security_groups(ec2_client_stub)
    # expect to first create a security group on the worker node VPC
    stubs.create_sg_echo(ec2_client_stub, DEFAULT_SG_AUX_SUBNET)
    # expect new worker security group details to be retrieved after creation
    stubs.describe_sgs_on_vpc(
        ec2_client_stub,
        [AUX_SUBNET["VpcId"]],
        [DEFAULT_SG_AUX_SUBNET],
    )
    # expect to second create a security group on the head node VPC
    stubs.create_sg_echo(ec2_client_stub, DEFAULT_SG)
    # expect new head security group details to be retrieved after creation
    stubs.describe_sgs_on_vpc(
        ec2_client_stub,
        [DEFAULT_SUBNET["VpcId"]],
        [DEFAULT_SG],
    )

    # given no existing default head security group inbound rules...
    # expect to authorize all default head inbound rules
    stubs.authorize_sg_ingress(
        ec2_client_stub,
        DEFAULT_SG_DUAL_GROUP_RULES,
    )
    # given no existing default worker security group inbound rules...
    # expect to authorize all default worker inbound rules
    stubs.authorize_sg_ingress(
        ec2_client_stub,
        DEFAULT_SG_WITH_RULES_AUX_SUBNET,
    )

    # given our mocks and an example config file as input...
    # expect the config to be loaded, validated, and bootstrapped successfully
    config = helpers.bootstrap_aws_example_config_file("example-subnets.yaml")

    # expect the bootstrapped config to show different head and worker security
    # groups residing on different subnets
    assert config["head_node"]["SecurityGroupIds"] == [DEFAULT_SG["GroupId"]]
    assert config["head_node"]["SubnetIds"] == [DEFAULT_SUBNET["SubnetId"]]
    assert config["worker_nodes"]["SecurityGroupIds"] == [AUX_SG["GroupId"]]
    assert config["worker_nodes"]["SubnetIds"] == [AUX_SUBNET["SubnetId"]]

    # expect no pending responses left in IAM or EC2 client stub queues
    iam_client_stub.assert_no_pending_responses()
    ec2_client_stub.assert_no_pending_responses()
Пример #4
0
def test_create_sg_with_custom_inbound_rules_and_name(iam_client_stub,
                                                      ec2_client_stub):
    # use default stubs to skip ahead to security group configuration
    stubs.skip_to_configure_sg(ec2_client_stub, iam_client_stub)

    # expect to describe the head subnet ID
    stubs.describe_subnets_echo(ec2_client_stub, DEFAULT_SUBNET)
    # given no existing security groups within the VPC...
    stubs.describe_no_security_groups(ec2_client_stub)
    # expect to create a security group on the head node VPC
    stubs.create_sg_echo(ec2_client_stub, DEFAULT_SG_WITH_NAME)
    # expect new head security group details to be retrieved after creation
    stubs.describe_sgs_on_vpc(
        ec2_client_stub,
        [DEFAULT_SUBNET["VpcId"]],
        [DEFAULT_SG_WITH_NAME],
    )

    # given custom existing default head security group inbound rules...
    # expect to authorize both default and custom inbound rules
    stubs.authorize_sg_ingress(
        ec2_client_stub,
        DEFAULT_SG_WITH_NAME_AND_RULES,
    )

    # given the prior modification to the head security group...
    # expect the next read of a head security group property to reload it
    stubs.describe_sg_echo(ec2_client_stub, DEFAULT_SG_WITH_NAME_AND_RULES)

    _get_vpc_id_or_die.cache_clear()
    # given our mocks and an example config file as input...
    # expect the config to be loaded, validated, and bootstrapped successfully
    config = helpers.bootstrap_aws_example_config_file(
        "example-security-group.yaml")

    # expect the bootstrapped config to have the custom security group...
    # name and in bound rules
    assert config["provider"]["security_group"][
        "GroupName"] == DEFAULT_SG_WITH_NAME_AND_RULES["GroupName"]
    assert config["provider"]["security_group"][
        "IpPermissions"] == CUSTOM_IN_BOUND_RULES

    # expect no pending responses left in IAM or EC2 client stub queues
    iam_client_stub.assert_no_pending_responses()
    ec2_client_stub.assert_no_pending_responses()
Пример #5
0
def test_create_sg_different_vpc_same_rules(iam_client_stub, ec2_client_stub,
                                            correct_az: bool):
    # use default stubs to skip ahead to security group configuration
    stubs.skip_to_configure_sg(ec2_client_stub, iam_client_stub)

    default_subnet = copy.deepcopy(DEFAULT_SUBNET)
    if not correct_az:
        default_subnet["AvailabilityZone"] = "us-west-2b"

    # given head and worker nodes with custom subnets defined...
    # expect to second describe the head subnet ID
    stubs.describe_subnets_echo(ec2_client_stub, [default_subnet])
    # expect to first describe the worker subnet ID
    stubs.describe_subnets_echo(ec2_client_stub, [AUX_SUBNET])
    # given no existing security groups within the VPC...
    stubs.describe_no_security_groups(ec2_client_stub)
    # expect to first create a security group on the worker node VPC
    stubs.create_sg_echo(ec2_client_stub, DEFAULT_SG_AUX_SUBNET)
    # expect new worker security group details to be retrieved after creation
    stubs.describe_sgs_on_vpc(
        ec2_client_stub,
        [AUX_SUBNET["VpcId"]],
        [DEFAULT_SG_AUX_SUBNET],
    )
    # expect to second create a security group on the head node VPC
    stubs.create_sg_echo(ec2_client_stub, DEFAULT_SG)
    # expect new head security group details to be retrieved after creation
    stubs.describe_sgs_on_vpc(
        ec2_client_stub,
        [DEFAULT_SUBNET["VpcId"]],
        [DEFAULT_SG],
    )

    # given no existing default head security group inbound rules...
    # expect to authorize all default head inbound rules
    stubs.authorize_sg_ingress(
        ec2_client_stub,
        DEFAULT_SG_DUAL_GROUP_RULES,
    )
    # given no existing default worker security group inbound rules...
    # expect to authorize all default worker inbound rules
    stubs.authorize_sg_ingress(
        ec2_client_stub,
        DEFAULT_SG_WITH_RULES_AUX_SUBNET,
    )

    # given our mocks and an example config file as input...
    # expect the config to be loaded, validated, and bootstrapped successfully
    error = None
    try:
        config = helpers.bootstrap_aws_example_config_file(
            "example-subnets.yaml")
    except ClickException as e:
        error = e

    _get_subnets_or_die.cache_clear()

    if not correct_az:
        assert isinstance(error,
                          ClickException), "Did not get a ClickException!"
        iam_client_stub._queue.clear()
        ec2_client_stub._queue.clear()
        return

    # expect the bootstrapped config to show different head and worker security
    # groups residing on different subnets
    for node_type_key, node_type in config["available_node_types"].items():
        node_config = node_type["node_config"]
        security_group_ids = node_config["SecurityGroupIds"]
        subnet_ids = node_config["SubnetIds"]
        if node_type_key == config["head_node_type"]:
            assert security_group_ids == [DEFAULT_SG["GroupId"]]
            assert subnet_ids == [DEFAULT_SUBNET["SubnetId"]]
        else:
            assert security_group_ids == [AUX_SG["GroupId"]]
            assert subnet_ids == [AUX_SUBNET["SubnetId"]]

    # expect no pending responses left in IAM or EC2 client stub queues
    iam_client_stub.assert_no_pending_responses()
    ec2_client_stub.assert_no_pending_responses()
Пример #6
0
def test_network_interfaces(
    ec2_client_stub,
    iam_client_stub,
    ec2_client_stub_fail_fast,
    ec2_client_stub_max_retries,
):

    # use default stubs to skip ahead to subnet configuration
    stubs.configure_iam_role_default(iam_client_stub)
    stubs.configure_key_pair_default(ec2_client_stub)

    # given the security groups associated with our network interfaces...
    sgids = ["sg-00000000", "sg-11111111", "sg-22222222", "sg-33333333"]
    security_groups = []
    suffix = 0
    for sgid in sgids:
        sg = copy.deepcopy(DEFAULT_SG)
        sg["GroupName"] += f"-{suffix}"
        sg["GroupId"] = sgid
        security_groups.append(sg)
        suffix += 1
    # expect to describe all security groups to ensure they share the same VPC
    stubs.describe_sgs_by_id(ec2_client_stub, sgids, security_groups)

    # use a default stub to skip subnet configuration
    stubs.configure_subnet_default(ec2_client_stub)
    stubs.describe_subnets_echo(
        ec2_client_stub,
        [DEFAULT_SUBNET, {
            **DEFAULT_SUBNET, "SubnetId": "subnet-11111111"
        }],
    )
    stubs.describe_subnets_echo(
        ec2_client_stub, [{
            **DEFAULT_SUBNET, "SubnetId": "subnet-22222222"
        }])
    stubs.describe_subnets_echo(
        ec2_client_stub, [{
            **DEFAULT_SUBNET, "SubnetId": "subnet-33333333"
        }])

    # given our mocks and an example config file as input...
    # expect the config to be loaded, validated, and bootstrapped successfully
    config = helpers.bootstrap_aws_example_config_file(
        "example-network-interfaces.yaml")

    # instantiate a new node provider
    new_provider = _get_node_provider(
        config["provider"],
        DEFAULT_CLUSTER_NAME,
        False,
    )

    for name, node_type in config["available_node_types"].items():
        node_cfg = node_type["node_config"]
        tags = helpers.node_provider_tags(config, name)
        # given our bootstrapped node config as input to create a new node...
        # expect to first describe all stopped instances that could be reused
        stubs.describe_instances_with_any_filter_consumer(
            ec2_client_stub_max_retries)
        # given no stopped EC2 instances to reuse...
        # expect to create new nodes with the given network interface config
        stubs.run_instances_with_network_interfaces_consumer(
            ec2_client_stub_fail_fast,
            node_cfg["NetworkInterfaces"],
        )
        new_provider.create_node(node_cfg, tags, 1)

    iam_client_stub.assert_no_pending_responses()
    ec2_client_stub.assert_no_pending_responses()
    ec2_client_stub_fail_fast.assert_no_pending_responses()
    ec2_client_stub_max_retries.assert_no_pending_responses()
Пример #7
0
def test_create_sg_multinode(iam_client_stub, ec2_client_stub):
    """
    Test AWS Bootstrap logic when config being bootstrapped has the
    following properties:

    (1) auth config does not specify ssh key path
    (2) available_node_types is provided
    (3) security group name and ip permissions set in provider field
    (4) Available node types have SubnetIds field set and this
        field is of form SubnetIds: [subnet-xxxxx].
        Both node types specify the same subnet-xxxxx.

    Tests creation of a security group and key pair under these conditions.
    """

    # Generate a config of the desired form.
    subnet_id = DEFAULT_SUBNET["SubnetId"]

    # security group info to go in provider field
    provider_data = helpers.load_aws_example_config_file(
        "example-security-group.yaml")["provider"]

    # a multi-node-type config -- will add head/worker stuff and security group
    # info to this.
    base_config = helpers.load_aws_example_config_file("example-full.yaml")

    config = copy.deepcopy(base_config)
    # Add security group data
    config["provider"] = provider_data
    # Add head and worker fields.
    head_node_config = config["available_node_types"]["ray.head.default"][
        "node_config"]
    worker_node_config = config["available_node_types"]["ray.worker.default"][
        "node_config"]
    head_node_config["SubnetIds"] = [subnet_id]
    worker_node_config["SubnetIds"] = [subnet_id]

    # Generate stubs
    stubs.configure_iam_role_default(iam_client_stub)
    stubs.configure_key_pair_default(ec2_client_stub)

    # Only one of these (the one specified in the available_node_types)
    # is in the correct vpc.
    # This list of subnets is generated by the ec2.subnets.all() call
    # and then ignored, since available_node_types already specify
    # subnet_ids.
    stubs.describe_a_thousand_subnets_in_different_vpcs(ec2_client_stub)

    # The rest of the stubbing logic is copied from
    # test_create_sg_with_custom_inbound_rules_and_name.

    # expect to describe the head subnet ID
    stubs.describe_subnets_echo(ec2_client_stub, [DEFAULT_SUBNET])
    # given no existing security groups within the VPC...
    stubs.describe_no_security_groups(ec2_client_stub)
    # expect to create a security group on the head node VPC
    stubs.create_sg_echo(ec2_client_stub, DEFAULT_SG_WITH_NAME)
    # expect new head security group details to be retrieved after creation
    stubs.describe_sgs_on_vpc(
        ec2_client_stub,
        [DEFAULT_SUBNET["VpcId"]],
        [DEFAULT_SG_WITH_NAME],
    )

    # given custom existing default head security group inbound rules...
    # expect to authorize both default and custom inbound rules
    stubs.authorize_sg_ingress(
        ec2_client_stub,
        DEFAULT_SG_WITH_NAME_AND_RULES,
    )

    # given the prior modification to the head security group...
    # expect the next read of a head security group property to reload it
    stubs.describe_sg_echo(ec2_client_stub, DEFAULT_SG_WITH_NAME_AND_RULES)

    _get_subnets_or_die.cache_clear()

    # given our mocks and the config as input...
    # expect the config to be validated and bootstrapped successfully
    bootstrapped_config = helpers.bootstrap_aws_config(config)

    # expect the bootstrapped config to have the custom security group...
    # name and in bound rules
    assert (bootstrapped_config["provider"]["security_group"]["GroupName"] ==
            DEFAULT_SG_WITH_NAME_AND_RULES["GroupName"])
    assert (bootstrapped_config["provider"]["security_group"]["IpPermissions"]
            == CUSTOM_IN_BOUND_RULES)

    # Confirming correct security group got filled for head and workers
    sg_id = DEFAULT_SG["GroupId"]
    for node_type in bootstrapped_config["available_node_types"].values():
        node_config = node_type["node_config"]
        assert node_config["SecurityGroupIds"] == [sg_id]

    # Confirming boostrap config updates available node types with
    # default KeyName
    for node_type in bootstrapped_config["available_node_types"].values():
        node_config = node_type["node_config"]
        assert node_config["KeyName"] == DEFAULT_KEY_PAIR["KeyName"]

    # Confirm security group is in the right VPC.
    # (Doesn't really confirm anything except for the structure of this test
    # data.)
    bootstrapped_head_type = bootstrapped_config["head_node_type"]
    bootstrapped_types = bootstrapped_config["available_node_types"]
    bootstrapped_head_config = bootstrapped_types[bootstrapped_head_type][
        "node_config"]
    assert DEFAULT_SG["VpcId"] == DEFAULT_SUBNET["VpcId"]
    assert DEFAULT_SUBNET["SubnetId"] == bootstrapped_head_config["SubnetIds"][
        0]

    # ssh private key filled in
    assert "ssh_private_key" in bootstrapped_config["auth"]

    # expect no pending responses left in IAM or EC2 client stub queues
    iam_client_stub.assert_no_pending_responses()
    ec2_client_stub.assert_no_pending_responses()