def test_destroy_network_interfaces_(self): """Test destroying network interfaces""" vpc = DiscoVPC('auto-vpc', 'auto-vpc-type', vpc={ 'CidrBlock': '10.0.0.0/28', 'VpcId': 'mock_vpc_id' }) vpc.boto3_ec2.describe_network_interfaces = MagicMock(return_value={'NetworkInterfaces': [{ 'NetworkInterfaceId': 'net-1', 'Attachment': { 'AttachmentId': 'attach-1234' } }, { 'NetworkInterfaceId': 'net-2' }]}) vpc.boto3_ec2.detach_network_interface = MagicMock() vpc.boto3_ec2.delete_network_interface = MagicMock() vpc._destroy_interfaces() vpc.boto3_ec2.detach_network_interface.assert_called_once_with( AttachmentId='attach-1234', Force=True ) vpc.boto3_ec2.delete_network_interface.assert_has_calls([ call(NetworkInterfaceId='net-1'), call(NetworkInterfaceId='net-2') ])
def test_destroy_network_interfaces_(self): """Test destroying network interfaces""" vpc = DiscoVPC('auto-vpc', 'auto-vpc-type', vpc={ 'CidrBlock': '10.0.0.0/28', 'VpcId': 'mock_vpc_id' }) vpc.boto3_ec2.describe_network_interfaces = MagicMock( return_value={ 'NetworkInterfaces': [{ 'NetworkInterfaceId': 'net-1', 'Attachment': { 'AttachmentId': 'attach-1234' } }, { 'NetworkInterfaceId': 'net-2' }] }) vpc.boto3_ec2.detach_network_interface = MagicMock() vpc.boto3_ec2.delete_network_interface = MagicMock() vpc._destroy_interfaces() vpc.boto3_ec2.detach_network_interface.assert_called_once_with( AttachmentId='attach-1234', Force=True) vpc.boto3_ec2.delete_network_interface.assert_has_calls([ call(NetworkInterfaceId='net-1'), call(NetworkInterfaceId='net-2') ])
def test_create_meta_networks_static_dynamic(self, meta_network_mock, config_mock, endpoints_mock): """Test creating meta networks with a mix of static and dynamic ip ranges""" vpc_mock = {'CidrBlock': '10.0.0.0/28', 'VpcId': 'mock_vpc_id', 'DhcpOptionsId': 'mock_dhcp_options_id'} config_mock.return_value = get_mock_config({ 'envtype:auto-vpc-type': { 'vpc_cidr': '10.0.0.0/28', 'intranet_cidr': 'auto', 'tunnel_cidr': 'auto', 'dmz_cidr': '10.0.0.4/31', 'maintenance_cidr': 'auto' } }) def _create_meta_network_mock(network_name, vpc, cidr): ret = MagicMock() ret.name = network_name ret.vpc = vpc ret.network_cidr = cidr return ret meta_network_mock.side_effect = _create_meta_network_mock auto_vpc = DiscoVPC('auto-vpc', 'auto-vpc-type', vpc_mock) meta_networks = auto_vpc._create_new_meta_networks() self.assertItemsEqual(['intranet', 'tunnel', 'dmz', 'maintenance'], meta_networks.keys()) expected_ip_ranges = ['10.0.0.0/30', '10.0.0.4/31', '10.0.0.8/30', '10.0.0.12/30'] actual_ip_ranges = [str(meta_network.network_cidr) for meta_network in meta_networks.values()] self.assertItemsEqual(actual_ip_ranges, expected_ip_ranges)
def create_vpc_command(args): """ handle vpc create command actions""" if DiscoVPC.fetch_environment(environment_name=args.vpc_name): logging.error("VPC with same name already exists.") sys.exit(1) else: vpc = DiscoVPC(args.vpc_name, args.vpc_type) logging.info("VPC %s(%s) has been created", args.vpc_name, vpc.vpc.id)
def setUp(self): mock_ec2().start() self.disco_vpc1 = DiscoVPC('mock-vpc-1', 'sandbox') self.disco_vpc2 = DiscoVPC('mock-vpc-2', 'sandbox') self.disco_vpc3 = DiscoVPC('mock-vpc-3', 'sandbox') self.client = boto3.client('ec2') self.disco_vpc_peerings = DiscoVPCPeerings()
def create_vpc_command(args): """ handle vpc create command actions""" if DiscoVPC.fetch_environment(environment_name=args.vpc_name): print("VPC with same name already exists.") sys.exit(1) else: tags = tag2dict(key_values_to_tags(args.tags)) if args.tags else None vpc = DiscoVPC(args.vpc_name, args.vpc_type, skip_enis_pre_allocate=args.skip_enis, vpc_tags=tags) print("VPC {0}({1}) has been created".format(args.vpc_name, vpc.get_vpc_id()))
def create_vpc_command(args): """ handle vpc create command actions""" if DiscoVPC.fetch_environment(environment_name=args.vpc_name): print("VPC with same name already exists.") sys.exit(1) else: tags = key_values_to_tags(args.tags) if args.tags else None vpc = DiscoVPC(args.vpc_name, args.vpc_type, skip_enis_pre_allocate=args.skip_enis, vpc_tags=tags) print("VPC {0}({1}) has been created".format(args.vpc_name, vpc.get_vpc_id()))
def update_vpc_command(args): """ handle vpc update command actions""" if args.vpc_name: vpc = DiscoVPC.fetch_environment(environment_name=args.vpc_name) else: vpc = DiscoVPC.fetch_environment(vpc_id=args.vpc_id) if vpc: vpc.update(args.dry_run) else: print("No matching VPC found") sys.exit(2)
def destroy_vpc_command(args): """ handle vpc destroy command actions""" if args.vpc_name: vpc = DiscoVPC.fetch_environment(environment_name=args.vpc_name) else: vpc = DiscoVPC.fetch_environment(vpc_id=args.vpc_id) if vpc: vpc.destroy() else: print("No matching VPC found") sys.exit(2)
def proxy_peerings_command(args): """ handle peerins command actions""" if args.vpc_name and args.vpc_id: logging.error("Don't use vpc_name and vpc_id at the same time.") sys.exit(2) if args.vpc_name: vpc_id = DiscoVPC.find_vpc_id_by_name(args.vpc_name) elif args.vpc_id: vpc_id = args.vpc_id else: vpc_id = None if args.list_peerings: vpc_map = {vpc.id: vpc for vpc in DiscoVPC.list_vpcs()} peerings = sorted(DiscoVPC.list_peerings(vpc_id, include_failed=True), key=lambda p: vpc_map.get(p.accepter_vpc_info.vpc_id) .tags.get("Name")) for peering in peerings: vpc1 = vpc_map.get(peering.accepter_vpc_info.vpc_id) vpc2 = vpc_map.get(peering.requester_vpc_info.vpc_id) line = u"{0:<14} {1:<8} {2:<20} {3:<21}".format( peering.id, peering.status_code, "{}<->{}".format(vpc1.tags.get("Name"), vpc2.tags.get("Name")), "{}<->{}".format(peering.accepter_vpc_info.cidr_block, peering.requester_vpc_info.cidr_block)) print(line) elif args.delete_peerings: DiscoVPC.delete_peerings(vpc_id) elif args.create_peerings: peering_configs = DiscoVPC.parse_peerings_config(vpc_id) DiscoVPC.create_peering_connections(peering_configs)
def proxy_peerings_command(args): """ handle peerins command actions""" if args.vpc_name and args.vpc_id: logging.error("Don't use vpc_name and vpc_id at the same time.") sys.exit(2) if args.vpc_name: vpc_id = DiscoVPC.find_vpc_id_by_name(args.vpc_name) elif args.vpc_id: vpc_id = args.vpc_id else: vpc_id = None if args.list_peerings: vpc_map = {vpc.id: vpc for vpc in DiscoVPC.list_vpcs()} peerings = sorted( DiscoVPC.list_peerings(vpc_id, include_failed=True), key=lambda p: vpc_map.get(p.accepter_vpc_info.vpc_id).tags.get("Name")) for peering in peerings: vpc1 = vpc_map.get(peering.accepter_vpc_info.vpc_id) vpc2 = vpc_map.get(peering.requester_vpc_info.vpc_id) line = u"{0:<14} {1:<8} {2:<20} {3:<21}".format( peering.id, peering.status_code, "{}<->{}".format( vpc1.tags.get("Name"), vpc2.tags.get("Name")), "{}<->{}".format( peering.accepter_vpc_info.cidr_block, peering.requester_vpc_info.cidr_block)) print(line) elif args.delete_peerings: DiscoVPC.delete_peerings(vpc_id) elif args.create_peerings: peering_configs = DiscoVPC.parse_peerings_config(vpc_id) DiscoVPC.create_peering_connections(peering_configs)
def list_vpc_command(args): """ handle list vpcs command actions """ for vpc_env in DiscoVPC.list_vpcs(): line = u"{0}\t{1:<15}".format(vpc_env['id'], vpc_env['tags'].get("Name", "-")) if args.env_type: line += u"\t{0}".format(vpc_env['tags'].get("type", "-")) print(line)
def run(): """Parses command line and dispatches the commands""" args = docopt(__doc__) configure_logging(args["--debug"]) config = read_config() env = args.get("--env") or config.get("disco_aws", "default_environment") vpc = DiscoVPC.fetch_environment(environment_name=env) if not vpc: print("Environment does not exist: {}".format(env)) sys.exit(1) aws = DiscoAWS(config, env) disco_elasticache = DiscoElastiCache(vpc, aws=aws) if args['list']: for cluster in disco_elasticache.list(): size = 'N/A' if cluster['Status'] == 'available': size = len(cluster['NodeGroups'][0]['NodeGroupMembers']) print("{0:<25} {1:5} {2:>5}".format(cluster['Description'], cluster['Status'], size)) elif args['update']: if args['--cluster']: disco_elasticache.update(args['--cluster']) else: disco_elasticache.update_all() elif args['delete']: disco_elasticache.delete(args['--cluster'], wait=args['--wait'])
def run(): """Parses command line and dispatches the commands""" config = read_config() parser = get_parser() args = parser.parse_args() configure_logging(args.debug, args.silent) bucket_name = args.bucket or DiscoVPC.get_credential_buckets_from_env_name( config, args.env)[0] s3_bucket = DiscoS3Bucket(bucket_name) if args.mode == "list": print("\n".join(s3_bucket.listkeys(args.prefix))) elif args.mode == "get": print(s3_bucket.get_key(args.key_name)) elif args.mode == "set": use_password = args.key_password key_value = args.key_value if use_password: key_value = getpass.getpass() elif key_value == "-": key_value = sys.stdin.read() s3_bucket.set_key(args.key_name, key_value) elif args.mode == "delete": s3_bucket.delete_key(args.key_name) elif args.mode == "setfile": key_value = s3_bucket.get_key(args.key_name) s3_bucket.get_contents_to_file(args.key_name, args.file_name)
def run(): """Parses command line and dispatches the commands""" args = docopt(__doc__) configure_logging(args["--debug"]) config = read_config() env = args.get("--env") or config.get("disco_aws", "default_environment") vpc = DiscoVPC.fetch_environment(environment_name=env) if not vpc: print("Environment does not exist: {}".format(env)) sys.exit(1) if args['list']: format_string = "{0:<50} {1:33} {2}" print(format_string.format("ELB Name", "Availability Zones", "ELB Id"), file=sys.stderr) for elb_info in sorted(DiscoELB(vpc).list_for_display()): print( format_string.format(elb_info['elb_name'], elb_info['availability_zones'], elb_info["elb_id"])) elif args['update']: DiscoAWS(config, env).update_elb(args['--hostclass'])
def run(): """Parses command line and dispatches the commands""" config = read_config() parser = get_parser() args = parser.parse_args() configure_logging(args.debug) bucket_name = args.bucket or DiscoVPC.get_credential_buckets_from_env_name(config, args.env)[0] s3_bucket = DiscoS3Bucket(bucket_name) if args.mode == "list": print("\n".join(s3_bucket.listkeys(args.prefix))) elif args.mode == "get": print(s3_bucket.get_key(args.key_name)) elif args.mode == "set": use_password = args.key_password key_value = args.key_value if use_password: key_value = getpass.getpass() elif key_value == "-": key_value = sys.stdin.read() s3_bucket.set_key(args.key_name, key_value) elif args.mode == "delete": s3_bucket.delete_key(args.key_name) elif args.mode == "setfile": key_value = s3_bucket.get_key(args.key_name) s3_bucket.get_contents_to_file(args.key_name, args.file_name)
def test_create_meta_networks_static_dynamic(self, meta_network_mock, config_mock, endpoints_mock): """Test creating meta networks with a mix of static and dynamic ip ranges""" vpc_mock = { 'CidrBlock': '10.0.0.0/28', 'VpcId': 'mock_vpc_id', 'DhcpOptionsId': 'mock_dhcp_options_id' } config_mock.return_value = get_mock_config({ 'envtype:auto-vpc-type': { 'vpc_cidr': '10.0.0.0/28', 'intranet_cidr': 'auto', 'tunnel_cidr': 'auto', 'dmz_cidr': '10.0.0.4/31', 'maintenance_cidr': 'auto' } }) def _create_meta_network_mock(network_name, vpc, cidr): ret = MagicMock() ret.name = network_name ret.vpc = vpc ret.network_cidr = cidr return ret meta_network_mock.side_effect = _create_meta_network_mock auto_vpc = DiscoVPC('auto-vpc', 'auto-vpc-type', vpc_mock) meta_networks = auto_vpc._create_new_meta_networks() self.assertItemsEqual(['intranet', 'tunnel', 'dmz', 'maintenance'], meta_networks.keys()) expected_ip_ranges = [ '10.0.0.0/30', '10.0.0.4/31', '10.0.0.8/30', '10.0.0.12/30' ] actual_ip_ranges = [ str(meta_network.network_cidr) for meta_network in meta_networks.values() ] self.assertItemsEqual(actual_ip_ranges, expected_ip_ranges)
def proxy_peerings_command(args): """ handle peerings command actions""" if args.vpc_name and args.vpc_id: print("Don't use vpc_name and vpc_id at the same time.") sys.exit(2) vpc = None if args.vpc_name: vpc = DiscoVPC.fetch_environment(environment_name=args.vpc_name) elif args.vpc_id: vpc = DiscoVPC.fetch_environment(vpc_id=args.vpc_id) vpc_id = vpc.get_vpc_id() if vpc else None disco_peerings = DiscoVPCPeerings() if args.list_peerings: vpc_map = {vpc['id']: vpc for vpc in DiscoVPC.list_vpcs()} peerings = sorted( disco_peerings.list_peerings(vpc_id, include_failed=True), key=lambda p: vpc_map.get(p['AccepterVpcInfo']['VpcId'])['tags'].get("Name")) for peering in peerings: vpc1 = vpc_map.get(peering['AccepterVpcInfo']['VpcId']) vpc2 = vpc_map.get(peering['RequesterVpcInfo']['VpcId']) line = u"{0:<14} {1:<8} {2:<20} {3:<21}".format( peering['VpcPeeringConnectionId'], peering['Status']['Code'], "{}<->{}".format( vpc1['tags'].get("Name") if vpc1 is not None else "", vpc2['tags'].get("Name") if vpc2 is not None else ""), "{}<->{}".format( peering['AccepterVpcInfo'].get('CidrBlock'), peering['RequesterVpcInfo'].get('CidrBlock'))) print(line) elif args.delete_peerings: disco_peerings.delete_peerings(vpc_id) elif args.create_peerings: disco_peerings.update_peering_connections(vpc)
def test_reserve_hostclass_ip_addresses(self, meta_network_mock, boto3_resource_mock, boto3_client_mock, config_mock, sleep_mock, gateways_mock, sns_mock, endpoints_mock, rds_mock): """Test hostclass IP addresses are being reserved during VPC creation""" config_mock.return_value = get_mock_config({ 'envtype:auto-vpc-type': { 'ip_space': '10.0.0.0/24', 'vpc_cidr_size': '26', 'intranet_cidr': 'auto', 'tunnel_cidr': 'auto', 'dmz_cidr': 'auto', 'maintenance_cidr': 'auto', 'ntp_server': '10.0.0.5' } }) # pylint: disable=C0103 def _create_vpc_mock(CidrBlock): return { 'Vpc': { 'CidrBlock': CidrBlock, 'VpcId': 'mock_vpc_id', 'DhcpOptionsId': 'mock_dhcp_options_id' } } client_mock = MagicMock() client_mock.create_vpc.side_effect = _create_vpc_mock client_mock.get_all_zones.return_value = [MagicMock()] client_mock.describe_dhcp_options.return_value = { 'DhcpOptions': [MagicMock()] } boto3_client_mock.return_value = client_mock network_mock = MagicMock() meta_network_mock.return_value = network_mock DiscoVPC('auto-vpc', 'auto-vpc-type', aws_config=get_mock_config()) expected_calls = [] default_config = get_default_config_dict() for section in default_config: if section.startswith("mhc") and default_config[section].get( "ip_address"): expected_calls.append( call(default_config[section].get("ip_address"))) network_mock.get_interface.assert_has_calls(expected_calls)
def run(): """Parses command line and dispatches the commands""" config = read_config() parser = get_parser() args = parser.parse_args() configure_logging(args.debug) s3_bucket_name = args.bucket or DiscoVPC.get_credential_buckets_from_env_name(config, args.env)[0] app_auth_dir = args.dir or None env = args.env or s3_bucket_name.split('.')[-1] if args.mode == "update": app_auth = DiscoAppAuth(env, s3_bucket_name, app_auth_dir) app_auth.update(args.force)
def run(): """Parses command line and dispatches the commands""" config = read_config() args = docopt(__doc__) configure_logging(args["--debug"]) if args["hashpassword"]: print(password_hash()) sys.exit(0) bucket_name = args.get( "--bucket") or DiscoVPC.get_credential_buckets_from_env_name( config, args["--env"])[0] s3_accounts = S3AccountBackend(DiscoS3Bucket(bucket_name)) if args["install"]: s3_accounts.install_all() elif args["adduser"]: username = args["--name"] or os.environ.get("USER") user_template = s3_accounts.new_user_config( password_hash(args["--password"])) group_config = s3_accounts.new_group_config() user_config = s3_accounts.edit_account_config(user_template) s3_accounts.add_account(username, user_config) s3_accounts.add_account(username, group_config) elif args["addgroup"]: group_config = s3_accounts.new_group_config() s3_accounts.add_account(args["--name"], group_config) elif args["edituser"]: username = args["--name"] or os.environ.get("USER") user_config = s3_accounts.get_user_config(username) kwargs = {"active": args["--active"]} if args["--active"] else {} user_config = s3_accounts.edit_account_config(user_config, **kwargs) s3_accounts.add_account(username, user_config) s3_accounts.refresh_groups() elif args["editgroup"]: # there is nothing to edit for a group.. but.. group_config = s3_accounts.get_group_config(args["--name"]) group_config = s3_accounts.edit_account_config(group_config) s3_accounts.add_account(args["--name"], group_config) elif args["listgroups"]: print("\n".join(s3_accounts.list_groups())) elif args["listusers"]: print("\n".join(s3_accounts.list_users()))
def run(): """Parses command line and dispatches the commands""" config = read_config() args = docopt(__doc__) configure_logging(args["--debug"]) if args["hashpassword"]: print(password_hash()) sys.exit(0) bucket_name = args.get("--bucket") or DiscoVPC.get_credential_buckets_from_env_name( config, args["--env"])[0] s3_accounts = S3AccountBackend(DiscoS3Bucket(bucket_name)) if args["install"]: s3_accounts.install_all() elif args["adduser"]: username = args["--name"] or os.environ.get("USER") user_template = s3_accounts.new_user_config(password_hash(args["--password"])) group_config = s3_accounts.new_group_config() user_config = s3_accounts.edit_account_config(user_template) s3_accounts.add_account(username, user_config) s3_accounts.add_account(username, group_config) elif args["addgroup"]: group_config = s3_accounts.new_group_config() s3_accounts.add_account(args["--name"], group_config) elif args["edituser"]: username = args["--name"] or os.environ.get("USER") user_config = s3_accounts.get_user_config(username) kwargs = {"active": args["--active"]} if args["--active"] else {} user_config = s3_accounts.edit_account_config(user_config, **kwargs) s3_accounts.add_account(username, user_config) s3_accounts.refresh_groups() elif args["editgroup"]: # there is nothing to edit for a group.. but.. group_config = s3_accounts.get_group_config(args["--name"]) group_config = s3_accounts.edit_account_config(group_config) s3_accounts.add_account(args["--name"], group_config) elif args["listgroups"]: print("\n".join(s3_accounts.list_groups())) elif args["listusers"]: print("\n".join(s3_accounts.list_users()))
def run(): """Parses command line and dispatches the commands""" args = docopt(__doc__) configure_logging(args["--debug"]) config = read_config() env = args.get("--env") or config.get("disco_aws", "default_environment") vpc = DiscoVPC.fetch_environment(environment_name=env) if not vpc: print("Environment does not exist: {}".format(env)) sys.exit(1) if args['list']: for elb in sorted(DiscoELB(vpc).list()): print("{0:<20} {1:25}".format(elb['LoadBalancerName'], ','.join(elb['AvailabilityZones']))) elif args['update']: DiscoAWS(config, env).update_elb(args['--hostclass'])
def test_create_auto_vpc(self, meta_network_mock, boto3_resource_mock, boto3_client_mock, config_mock, sleep_mock, gateways_mock, sns_mock, endpoints_mock, rds_mock): """Test creating a VPC with a dynamic ip range""" # FIXME This needs to mock way too many things. DiscoVPC needs to be refactored config_mock.return_value = get_mock_config({ 'envtype:auto-vpc-type': { 'ip_space': '10.0.0.0/24', 'vpc_cidr_size': '26', 'intranet_cidr': 'auto', 'tunnel_cidr': 'auto', 'dmz_cidr': 'auto', 'maintenance_cidr': 'auto', 'ntp_server': '10.0.0.5' } }) # pylint: disable=C0103 def _create_vpc_mock(CidrBlock): return { 'Vpc': { 'CidrBlock': CidrBlock, 'VpcId': 'mock_vpc_id', 'DhcpOptionsId': 'mock_dhcp_options_id' } } client_mock = MagicMock() client_mock.create_vpc.side_effect = _create_vpc_mock client_mock.get_all_zones.return_value = [MagicMock()] client_mock.describe_dhcp_options.return_value = { 'DhcpOptions': [MagicMock()] } boto3_client_mock.return_value = client_mock auto_vpc = DiscoVPC('auto-vpc', 'auto-vpc-type') possible_vpcs = [ '10.0.0.0/26', '10.0.0.64/26', '10.0.0.128/26', '10.0.0.192/26' ] self.assertIn(str(auto_vpc.vpc['CidrBlock']), possible_vpcs)
def run(): """Parses command line and dispatches the commands""" args = docopt(__doc__) configure_logging(args["--debug"]) config = read_config() env = args.get("--env") or config.get("disco_aws", "default_environment") vpc = DiscoVPC.fetch_environment(environment_name=env) if not vpc: print("Environment does not exist: {}".format(env)) sys.exit(1) if args['list']: format_string = "{0:<50} {1:33} {2}" print(format_string.format("ELB Name", "Availability Zones", "ELB Id"), file=sys.stderr) for elb_info in sorted(DiscoELB(vpc).list_for_display()): print(format_string.format(elb_info['elb_name'], elb_info['availability_zones'], elb_info["elb_id"])) elif args['update']: DiscoAWS(config, env).update_elb(args['--hostclass'])
class DiscoVPCPeeringsTests(unittest.TestCase): """Test DiscoVPCPeerings""" @patch("disco_aws_automation.disco_vpc.DiscoSNS", MagicMock()) @patch("disco_aws_automation.disco_vpc.DiscoRDS", MagicMock()) @patch("disco_aws_automation.disco_vpc.DiscoVPCEndpoints", MagicMock()) def setUp(self): mock_ec2().start() self.disco_vpc1 = DiscoVPC('mock-vpc-1', 'sandbox') self.disco_vpc2 = DiscoVPC('mock-vpc-2', 'sandbox') self.disco_vpc3 = DiscoVPC('mock-vpc-3', 'sandbox') self.client = boto3.client('ec2') self.disco_vpc_peerings = DiscoVPCPeerings() @patch('disco_aws_automation.disco_vpc.DiscoMetaNetwork.create_peering_route') @patch('disco_aws_automation.disco_vpc_peerings.read_config') def test_update_peering_connections(self, config_mock, create_peering_route_mock): """ Verify new peering connections are created properly """ config_mock.return_value = get_mock_config({ 'peerings': { 'connection_1': 'mock-vpc-1:sandbox/intranet mock-vpc-2:sandbox/intranet' } }) # End setting up test # Calling method under test self.disco_vpc_peerings.update_peering_connections(self.disco_vpc1) # Asserting correct behavior peeerings = self.client.describe_vpc_peering_connections().get('VpcPeeringConnections') self.assertEqual(1, len(peeerings)) peering_id = peeerings[0]['VpcPeeringConnectionId'] self.assertEqual(self.disco_vpc1.get_vpc_id(), peeerings[0]['RequesterVpcInfo']['VpcId']) self.assertEqual(self.disco_vpc2.get_vpc_id(), peeerings[0]['AccepterVpcInfo']['VpcId']) # create_peering_route should have been called twice, once for each VPC create_peering_route_mock.assert_called_with(peering_id, '10.101.0.0/20') self.assertEqual(2, create_peering_route_mock.call_count) def test_parse_peering_connection(self): """test parsing a peering connection line with wildcards""" actual = self.disco_vpc_peerings._resolve_peering_connection_line( 'mock-vpc-1:sandbox/intranet mock-vpc-3:sandbox/intranet' ) expected = [ PeeringConnection.from_peering_line('mock-vpc-1:sandbox/intranet mock-vpc-3:sandbox/intranet'), ] self.assertItemsEqual(actual, expected) def test_parse_peering_connection_wildcards(self): """test parsing a peering connection line with wildcards""" actual = self.disco_vpc_peerings._resolve_peering_connection_line( '*:sandbox/intranet mock-vpc-3:sandbox/intranet' ) expected = [ PeeringConnection.from_peering_line('mock-vpc-1:sandbox/intranet mock-vpc-3:sandbox/intranet'), PeeringConnection.from_peering_line('mock-vpc-2:sandbox/intranet mock-vpc-3:sandbox/intranet') ] self.assertItemsEqual(actual, expected) def test_parse_peering_double_wildcards(self): """test parsing a peering connection line with wildcards on both sides""" actual = self.disco_vpc_peerings._resolve_peering_connection_line( '*:sandbox/intranet *:sandbox/intranet' ) expected = [ PeeringConnection.from_peering_line('mock-vpc-1:sandbox/intranet mock-vpc-2:sandbox/intranet'), PeeringConnection.from_peering_line('mock-vpc-1:sandbox/intranet mock-vpc-3:sandbox/intranet'), PeeringConnection.from_peering_line('mock-vpc-2:sandbox/intranet mock-vpc-3:sandbox/intranet') ] self.assertItemsEqual(actual, expected)
def run(): """Parses command line and dispatches the commands""" config = read_config() args = docopt(__doc__) configure_logging(args["--debug"]) env = args["--environment"] or config.get("disco_aws", "default_environment") force_deployable = None if args["--deployable"] is None else is_truthy( args["--deployable"]) pipeline_definition = [] if args["--pipeline"]: with open(args["--pipeline"], "r") as f: reader = csv.DictReader(f) pipeline_definition = [line for line in reader] aws = DiscoAWS(config, env) if config.has_option('test', 'env'): test_env = config.get('test', 'env') test_aws = DiscoAWS(config, test_env) else: test_aws = aws bake = DiscoBake(config, aws.connection) if args["--ami"] and args["--hostclass"]: image = bake.get_image(args["--ami"]) if args["--hostclass"] != bake.ami_hostclass(image): logger.error('AMI %s does not belong to hostclass %s', args["--ami"], args["--hostclass"]) sys.exit(1) vpc = DiscoVPC.fetch_environment(environment_name=env) deploy = DiscoDeploy(aws, test_aws, bake, DiscoGroup(env), DiscoELB(vpc), DiscoSSM(environment_name=env), pipeline_definition=pipeline_definition, ami=args.get("--ami"), hostclass=args.get("--hostclass"), allow_any_hostclass=args["--allow-any-hostclass"]) if args["test"]: try: deploy.test(dry_run=args["--dry-run"], deployment_strategy=args["--strategy"], ticket_id=args["--ticket"], force_deployable=force_deployable) except RuntimeError as err: logger.error(str(err)) sys.exit(1) elif args["update"]: try: deploy.update(dry_run=args["--dry-run"], deployment_strategy=args["--strategy"], ticket_id=args["--ticket"], force_deployable=force_deployable) except RuntimeError as err: logger.error(str(err)) sys.exit(1) elif args["list"]: missing = "-" if pipeline_definition else "" if args["--tested"]: for (_hostclass, ami) in deploy.get_latest_tested_amis().iteritems(): print("{} {:40} {}".format( ami.id, ami.name.split()[0], deploy.get_integration_test(ami.name.split()[0]) or missing)) elif args["--untested"]: for (_hostclass, ami) in deploy.get_latest_untested_amis().iteritems(): print("{} {:40} {}".format( ami.id, ami.name.split()[0], deploy.get_integration_test(ami.name.split()[0]) or missing)) elif args["--failed"]: for (_hostclass, ami) in deploy.get_latest_failed_amis().iteritems(): print("{} {:40} {}".format( ami.id, ami.name.split()[0], deploy.get_integration_test(ami.name.split()[0]) or missing)) elif args["--testable"]: for ami in deploy.get_test_amis(): print("{} {:40} {}".format( ami.id, ami.name.split()[0], deploy.get_integration_test(ami.name.split()[0]) or missing)) elif args["--updatable"]: for ami in deploy.get_update_amis(): print("{} {:40} {}".format( ami.id, ami.name.split()[0], deploy.get_integration_test(ami.name.split()[0]) or missing)) elif args["--failures"]: failures = deploy.get_failed_amis() for ami in failures: print("{} {:40} {}".format( ami.id, ami.name.split()[0], deploy.get_integration_test(ami.name.split()[0]) or missing)) sys.exit(1 if failures else 0)
def test_create_vpc_with_custom_tags(self, boto3_resource_mock, boto3_client_mock, config_mock, endpoints_mock, sns_mock, rds_mock): """Test creating a VPC with a dynamic ip range and tags""" # FIXME This needs to mock way too many things. DiscoVPC needs to be refactored config_mock.return_value = get_mock_config({ 'envtype:auto-vpc-type': { 'ip_space': '10.0.0.0/24', 'vpc_cidr_size': '26', 'intranet_cidr': 'auto', 'tunnel_cidr': 'auto', 'dmz_cidr': 'auto', 'maintenance_cidr': 'auto', 'ntp_server': '10.0.0.5', 'application': 'test' } }) # pylint: disable=C0103 def _create_vpc_mock(CidrBlock): return { 'Vpc': { 'CidrBlock': CidrBlock, 'VpcId': 'mock_vpc_id', 'DhcpOptionsId': 'mock_dhcp_options_id' } } client_mock = MagicMock() client_mock.create_vpc.side_effect = _create_vpc_mock boto3_client_mock.return_value = client_mock resource_mock = MagicMock() resource_mock.Vpc.create_tags.return_value = [] boto3_resource_mock.return_value = resource_mock client_mock.describe_vpn_gateways.return_value = {'VpnGateways': []} my_tags_options = {'productline': 'astronauts', 'mytag': 'tag_value'} DiscoVPC._get_vpc_cidr = MagicMock() DiscoVPC._get_vpc_cidr.return_value = '10.0.0.0/26' with patch("disco_aws_automation.DiscoVPC._create_new_meta_networks", return_value=MagicMock(return_value={})): with patch("disco_aws_automation.DiscoVPC._update_dhcp_options", return_value=None): # The expect list of tag dictionaries expected_vpc_tags = [{ 'Value': 'auto-vpc', 'Key': 'Name' }, { 'Value': 'auto-vpc-type', 'Key': 'type' }, { 'Value': 'ANY', 'Key': 'create_date' }, { 'Value': 'astronauts', 'Key': 'productline' }, { 'Value': 'tag_value', 'Key': 'mytag' }, { 'Value': 'test', 'Key': 'application' }] DiscoVPC('auto-vpc', 'auto-vpc-type', vpc_tags=my_tags_options) # Get the create_tags argument call_args_tags = resource_mock.Vpc.return_value.create_tags.call_args[ 1] # Verify Option Name self.assertEqual(['Tags'], call_args_tags.keys()) call_tags_dict = call_args_tags['Tags'] # Verify the number of tag Dictionaries in the list self.assertEqual(6, len(call_tags_dict)) # Verify each tag options for tag_option in call_tags_dict: if tag_option['Key'] == 'create_date': tag_option['Value'] = 'ANY' self.assertIn(tag_option, expected_vpc_tags)
def test_create_vpc_ntp_names(self, meta_network_mock, boto3_resource_mock, boto3_client_mock, config_mock, sleep_mock, gateways_mock, sns_mock, endpoints_mock, rds_mock, gethostbyname_mock): """Test creating VPC with NTP server names""" # FIXME This needs to mock way too many things. DiscoVPC needs to be refactored local_dict = { 'dhcp_options_created': False, 'ntp_servers_dict': { '0.mock.ntp.server': '100.10.10.10', '1.mock.ntp.server': '100.10.10.11', '2.mock.ntp.server': '100.10.10.12' }, 'new_mock_dhcp_options_id': 'new_mock_dhcp_options_id', 'mock_vpc_id': 'mock_vpc_id' } config_mock.return_value = get_mock_config({ 'envtype:auto-vpc-type': { 'ip_space': '10.0.0.0/24', 'vpc_cidr_size': '26', 'intranet_cidr': 'auto', 'tunnel_cidr': 'auto', 'dmz_cidr': 'auto', 'maintenance_cidr': 'auto', 'ntp_server': ' '.join(local_dict['ntp_servers_dict'].keys()) } }) # pylint: disable=C0103 def _create_vpc_mock(CidrBlock): return { 'Vpc': { 'CidrBlock': CidrBlock, 'VpcId': local_dict['mock_vpc_id'], 'DhcpOptionsId': 'mock_dhcp_options_id' } } def _create_create_dhcp_mock(**args): local_dict['dhcp_options_created'] = True return { 'DhcpOptions': { 'DhcpOptionsId': local_dict['new_mock_dhcp_options_id'] } } def _create_describe_dhcp_mock(**args): return {'DhcpOptions': [{'DhcpOptionsId': local_dict['new_mock_dhcp_options_id']}]} \ if local_dict['dhcp_options_created'] else {'DhcpOptions': []} def _create_gethostbyname_mock(hostname): return local_dict['ntp_servers_dict'][hostname] client_mock = MagicMock() client_mock.create_vpc.side_effect = _create_vpc_mock client_mock.get_all_zones.return_value = [MagicMock()] client_mock.create_dhcp_options.side_effect = _create_create_dhcp_mock client_mock.describe_dhcp_options.side_effect = _create_describe_dhcp_mock gethostbyname_mock.side_effect = _create_gethostbyname_mock boto3_client_mock.return_value = client_mock # Calling method under test DiscoVPC('auto-vpc', 'auto-vpc-type') # Verifying result actual_ntp_servers = [ option['Values'] for option in client_mock.create_dhcp_options.call_args[1]['DhcpConfigurations'] if option['Key'] == 'ntp-servers' ][0] self.assertEqual(set(actual_ntp_servers), set(local_dict['ntp_servers_dict'].values())) client_mock.associate_dhcp_options.assert_has_calls([ call(DhcpOptionsId=local_dict['new_mock_dhcp_options_id'], VpcId=local_dict['mock_vpc_id']) ])
class DiscoVPCPeeringsTests(unittest.TestCase): """Test DiscoVPCPeerings""" @patch("disco_aws_automation.disco_vpc.DiscoSNS", MagicMock()) @patch("disco_aws_automation.disco_vpc.DiscoRDS", MagicMock()) @patch("disco_aws_automation.disco_vpc.DiscoVPCEndpoints", MagicMock()) def setUp(self): mock_ec2().start() self.disco_vpc1 = DiscoVPC('mock-vpc-1', 'sandbox') self.disco_vpc2 = DiscoVPC('mock-vpc-2', 'sandbox') self.disco_vpc3 = DiscoVPC('mock-vpc-3', 'sandbox') self.client = boto3.client('ec2') self.disco_vpc_peerings = DiscoVPCPeerings() @patch( 'disco_aws_automation.disco_vpc.DiscoMetaNetwork.create_peering_route') @patch('disco_aws_automation.disco_vpc_peerings.read_config') def test_update_peering_connections(self, config_mock, create_peering_route_mock): """ Verify new peering connections are created properly """ config_mock.return_value = get_mock_config({ 'peerings': { 'connection_1': 'mock-vpc-1:sandbox/intranet mock-vpc-2:sandbox/intranet' } }) # End setting up test # Calling method under test self.disco_vpc_peerings.update_peering_connections(self.disco_vpc1) # Asserting correct behavior peeerings = self.client.describe_vpc_peering_connections().get( 'VpcPeeringConnections') self.assertEqual(1, len(peeerings)) peering_id = peeerings[0]['VpcPeeringConnectionId'] self.assertEqual(self.disco_vpc1.get_vpc_id(), peeerings[0]['RequesterVpcInfo']['VpcId']) self.assertEqual(self.disco_vpc2.get_vpc_id(), peeerings[0]['AccepterVpcInfo']['VpcId']) # create_peering_route should have been called twice, once for each VPC create_peering_route_mock.assert_called_with(peering_id, '10.101.0.0/20') self.assertEqual(2, create_peering_route_mock.call_count) def test_parse_peering_connection(self): """test parsing a peering connection line with wildcards""" actual = self.disco_vpc_peerings._resolve_peering_connection_line( 'mock-vpc-1:sandbox/intranet mock-vpc-3:sandbox/intranet') expected = [ PeeringConnection.from_peering_line( 'mock-vpc-1:sandbox/intranet mock-vpc-3:sandbox/intranet'), ] self.assertItemsEqual(actual, expected) def test_parse_peering_connection_wildcards(self): """test parsing a peering connection line with wildcards""" actual = self.disco_vpc_peerings._resolve_peering_connection_line( '*:sandbox/intranet mock-vpc-3:sandbox/intranet') expected = [ PeeringConnection.from_peering_line( 'mock-vpc-1:sandbox/intranet mock-vpc-3:sandbox/intranet'), PeeringConnection.from_peering_line( 'mock-vpc-2:sandbox/intranet mock-vpc-3:sandbox/intranet') ] self.assertItemsEqual(actual, expected) def test_parse_peering_double_wildcards(self): """test parsing a peering connection line with wildcards on both sides""" actual = self.disco_vpc_peerings._resolve_peering_connection_line( '*:sandbox/intranet *:sandbox/intranet') expected = [ PeeringConnection.from_peering_line( 'mock-vpc-1:sandbox/intranet mock-vpc-2:sandbox/intranet'), PeeringConnection.from_peering_line( 'mock-vpc-1:sandbox/intranet mock-vpc-3:sandbox/intranet'), PeeringConnection.from_peering_line( 'mock-vpc-2:sandbox/intranet mock-vpc-3:sandbox/intranet') ] self.assertItemsEqual(actual, expected)