def test_launch_templates(ec2_client_stub, ec2_client_stub_fail_fast, ec2_client_stub_max_retries): # given the launch template associated with our default head node type... # expect to first describe the default launch template by ID stubs.describe_launch_template_versions_by_id_default( ec2_client_stub, ["$Latest"]) # given the launch template associated with our default worker node type... # expect to next describe the same default launch template by name stubs.describe_launch_template_versions_by_name_default( ec2_client_stub, ["2"]) # use default stubs to skip ahead to subnet configuration stubs.configure_key_pair_default(ec2_client_stub) # given the security groups associated with our launch template... sgids = [DEFAULT_SG["GroupId"]] security_groups = [DEFAULT_SG] # 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) # 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-launch-templates.yaml") # instantiate a new node provider new_provider = _get_node_provider( config["provider"], DEFAULT_CLUSTER_NAME, False, ) max_count = 1 for name, node_type in config["available_node_types"].items(): # 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 launch template config node_cfg = node_type["node_config"] stubs.run_instances_with_launch_template_consumer( ec2_client_stub_fail_fast, config, node_cfg, name, DEFAULT_LT["LaunchTemplateData"], max_count, ) tags = helpers.node_provider_tags(config, name) new_provider.create_node(node_cfg, tags, max_count) 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()
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) # 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()
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"] ]
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()
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()
def test_subnet_given_head_and_worker_sg(iam_client_stub, ec2_client_stub): stubs.configure_iam_role_default(iam_client_stub) stubs.configure_key_pair_default(ec2_client_stub) # list a security group and a thousand subnets in different vpcs stubs.describe_a_security_group(ec2_client_stub, DEFAULT_SG) stubs.describe_a_thousand_subnets_in_different_vpcs(ec2_client_stub) config = helpers.bootstrap_aws_example_config_file( "example-head-and-worker-security-group.yaml") # check that just the single subnet in the right vpc is filled assert config["head_node"]["SubnetIds"] == [DEFAULT_SUBNET["SubnetId"]] assert config["worker_nodes"]["SubnetIds"] == [DEFAULT_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()
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()