Add RDS Subnet groups
This commit is contained in:
		
							parent
							
								
									809046e00e
								
							
						
					
					
						commit
						7559fbe0d1
					
				| @ -29,3 +29,10 @@ class DBSecurityGroupNotFoundError(RDSClientError): | |||||||
|         super(DBSecurityGroupNotFoundError, self).__init__( |         super(DBSecurityGroupNotFoundError, self).__init__( | ||||||
|             'DBSecurityGroupNotFound', |             'DBSecurityGroupNotFound', | ||||||
|             "Security Group {0} not found.".format(security_group_name)) |             "Security Group {0} not found.".format(security_group_name)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DBSubnetGroupNotFoundError(RDSClientError): | ||||||
|  |     def __init__(self, subnet_group_name): | ||||||
|  |         super(DBSubnetGroupNotFoundError, self).__init__( | ||||||
|  |             'DBSubnetGroupNotFound', | ||||||
|  |             "Subnet Group {0} not found.".format(subnet_group_name)) | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import boto.rds | |||||||
| from jinja2 import Template | from jinja2 import Template | ||||||
| 
 | 
 | ||||||
| from moto.core import BaseBackend | from moto.core import BaseBackend | ||||||
| from .exceptions import DBInstanceNotFoundError, DBSecurityGroupNotFoundError | from .exceptions import DBInstanceNotFoundError, DBSecurityGroupNotFoundError, DBSubnetGroupNotFoundError | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Database(object): | class Database(object): | ||||||
| @ -118,11 +118,42 @@ class SecurityGroup(object): | |||||||
|         self.ip_ranges.append(cidr_ip) |         self.ip_ranges.append(cidr_ip) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class SubnetGroup(object): | ||||||
|  |     def __init__(self, subnet_name, description, subnets): | ||||||
|  |         self.subnet_name = subnet_name | ||||||
|  |         self.description = description | ||||||
|  |         self.subnets = subnets | ||||||
|  | 
 | ||||||
|  |         self.vpc_id = self.subnets[0].vpc_id | ||||||
|  | 
 | ||||||
|  |     def to_xml(self): | ||||||
|  |         template = Template("""<DBSubnetGroup> | ||||||
|  |               <VpcId>{{ subnet_group.vpc_id }}</VpcId> | ||||||
|  |               <SubnetGroupStatus>Complete</SubnetGroupStatus> | ||||||
|  |               <DBSubnetGroupDescription>{{ subnet_group.description }}</DBSubnetGroupDescription> | ||||||
|  |               <DBSubnetGroupName>{{ subnet_group.subnet_name }}</DBSubnetGroupName> | ||||||
|  |               <Subnets> | ||||||
|  |                 {% for subnet in subnet_group.subnets %} | ||||||
|  |                 <Subnet> | ||||||
|  |                   <SubnetStatus>Active</SubnetStatus> | ||||||
|  |                   <SubnetIdentifier>{{ subnet.id }}</SubnetIdentifier> | ||||||
|  |                   <SubnetAvailabilityZone> | ||||||
|  |                     <Name>{{ subnet.availability_zone }}</Name> | ||||||
|  |                     <ProvisionedIopsCapable>false</ProvisionedIopsCapable> | ||||||
|  |                   </SubnetAvailabilityZone> | ||||||
|  |                 </Subnet> | ||||||
|  |                 {% endfor %} | ||||||
|  |               </Subnets> | ||||||
|  |             </DBSubnetGroup>""") | ||||||
|  |         return template.render(subnet_group=self) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class RDSBackend(BaseBackend): | class RDSBackend(BaseBackend): | ||||||
| 
 | 
 | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.databases = {} |         self.databases = {} | ||||||
|         self.security_groups = {} |         self.security_groups = {} | ||||||
|  |         self.subnet_groups = {} | ||||||
| 
 | 
 | ||||||
|     def create_database(self, db_kwargs): |     def create_database(self, db_kwargs): | ||||||
|         database_id = db_kwargs['db_instance_identifier'] |         database_id = db_kwargs['db_instance_identifier'] | ||||||
| @ -173,6 +204,26 @@ class RDSBackend(BaseBackend): | |||||||
|         security_group.authorize(cidr_ip) |         security_group.authorize(cidr_ip) | ||||||
|         return security_group |         return security_group | ||||||
| 
 | 
 | ||||||
|  |     def create_subnet_group(self, subnet_name, description, subnets): | ||||||
|  |         subnet_group = SubnetGroup(subnet_name, description, subnets) | ||||||
|  |         self.subnet_groups[subnet_name] = subnet_group | ||||||
|  |         return subnet_group | ||||||
|  | 
 | ||||||
|  |     def describe_subnet_groups(self, subnet_group_name): | ||||||
|  |         if subnet_group_name: | ||||||
|  |             if subnet_group_name in self.subnet_groups: | ||||||
|  |                 return [self.subnet_groups[subnet_group_name]] | ||||||
|  |             else: | ||||||
|  |                 raise DBSubnetGroupNotFoundError(subnet_group_name) | ||||||
|  |         return self.subnet_groups.values() | ||||||
|  | 
 | ||||||
|  |     def delete_subnet_group(self, subnet_name): | ||||||
|  |         if subnet_name in self.subnet_groups: | ||||||
|  |             return self.subnet_groups.pop(subnet_name) | ||||||
|  |         else: | ||||||
|  |             raise DBSubnetGroupNotFoundError(subnet_name) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| rds_backends = {} | rds_backends = {} | ||||||
| for region in boto.rds.regions(): | for region in boto.rds.regions(): | ||||||
|     rds_backends[region.name] = RDSBackend() |     rds_backends[region.name] = RDSBackend() | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| from moto.core.responses import BaseResponse | from moto.core.responses import BaseResponse | ||||||
|  | from moto.ec2.models import ec2_backends | ||||||
| from .models import rds_backends | from .models import rds_backends | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -94,6 +95,27 @@ class RDSResponse(BaseResponse): | |||||||
|         template = self.response_template(AUTHORIZE_SECURITY_GROUP_TEMPLATE) |         template = self.response_template(AUTHORIZE_SECURITY_GROUP_TEMPLATE) | ||||||
|         return template.render(security_group=security_group) |         return template.render(security_group=security_group) | ||||||
| 
 | 
 | ||||||
|  |     def create_dbsubnet_group(self): | ||||||
|  |         subnet_name = self._get_param('DBSubnetGroupName') | ||||||
|  |         description = self._get_param('DBSubnetGroupDescription') | ||||||
|  |         subnet_ids = self._get_multi_param('SubnetIds.member') | ||||||
|  |         subnets = [ec2_backends[self.region].get_subnet(subnet_id) for subnet_id in subnet_ids] | ||||||
|  |         subnet_group = self.backend.create_subnet_group(subnet_name, description, subnets) | ||||||
|  |         template = self.response_template(CREATE_SUBNET_GROUP_TEMPLATE) | ||||||
|  |         return template.render(subnet_group=subnet_group) | ||||||
|  | 
 | ||||||
|  |     def describe_dbsubnet_groups(self): | ||||||
|  |         subnet_name = self._get_param('DBSubnetGroupName') | ||||||
|  |         subnet_groups = self.backend.describe_subnet_groups(subnet_name) | ||||||
|  |         template = self.response_template(DESCRIBE_SUBNET_GROUPS_TEMPLATE) | ||||||
|  |         return template.render(subnet_groups=subnet_groups) | ||||||
|  | 
 | ||||||
|  |     def delete_dbsubnet_group(self): | ||||||
|  |         subnet_name = self._get_param('DBSubnetGroupName') | ||||||
|  |         subnet_group = self.backend.delete_subnet_group(subnet_name) | ||||||
|  |         template = self.response_template(DELETE_SUBNET_GROUP_TEMPLATE) | ||||||
|  |         return template.render(subnet_group=subnet_group) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| CREATE_DATABASE_TEMPLATE = """<CreateDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/"> | CREATE_DATABASE_TEMPLATE = """<CreateDBInstanceResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/"> | ||||||
|   <CreateDBInstanceResult> |   <CreateDBInstanceResult> | ||||||
| @ -171,3 +193,31 @@ AUTHORIZE_SECURITY_GROUP_TEMPLATE = """<AuthorizeDBSecurityGroupIngressResponse | |||||||
|     <RequestId>6176b5f8-bfed-11d3-f92b-31fa5e8dbc99</RequestId> |     <RequestId>6176b5f8-bfed-11d3-f92b-31fa5e8dbc99</RequestId> | ||||||
|   </ResponseMetadata> |   </ResponseMetadata> | ||||||
| </AuthorizeDBSecurityGroupIngressResponse>""" | </AuthorizeDBSecurityGroupIngressResponse>""" | ||||||
|  | 
 | ||||||
|  | CREATE_SUBNET_GROUP_TEMPLATE = """<CreateDBSubnetGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/"> | ||||||
|  |   <CreateDBSubnetGroupResult> | ||||||
|  |     {{ subnet_group.to_xml() }} | ||||||
|  |   </CreateDBSubnetGroupResult> | ||||||
|  |   <ResponseMetadata> | ||||||
|  |     <RequestId>3a401b3f-bb9e-11d3-f4c6-37db295f7674</RequestId> | ||||||
|  |   </ResponseMetadata> | ||||||
|  | </CreateDBSubnetGroupResponse>""" | ||||||
|  | 
 | ||||||
|  | DESCRIBE_SUBNET_GROUPS_TEMPLATE = """<DescribeDBSubnetGroupsResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/"> | ||||||
|  |   <DescribeDBSubnetGroupsResult> | ||||||
|  |     <DBSubnetGroups> | ||||||
|  |     {% for subnet_group in subnet_groups %} | ||||||
|  |         {{ subnet_group.to_xml() }} | ||||||
|  |     {% endfor %} | ||||||
|  |     </DBSubnetGroups> | ||||||
|  |   </DescribeDBSubnetGroupsResult> | ||||||
|  |   <ResponseMetadata> | ||||||
|  |     <RequestId>b783db3b-b98c-11d3-fbc7-5c0aad74da7c</RequestId> | ||||||
|  |   </ResponseMetadata> | ||||||
|  | </DescribeDBSubnetGroupsResponse>""" | ||||||
|  | 
 | ||||||
|  | DELETE_SUBNET_GROUP_TEMPLATE = """<DeleteDBSubnetGroupResponse xmlns="http://rds.amazonaws.com/doc/2014-09-01/"> | ||||||
|  |   <ResponseMetadata> | ||||||
|  |     <RequestId>6295e5ab-bbf3-11d3-f4c6-37db295f7674</RequestId> | ||||||
|  |   </ResponseMetadata> | ||||||
|  | </DeleteDBSubnetGroupResponse>""" | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
| 
 | 
 | ||||||
| import boto.rds | import boto.rds | ||||||
|  | import boto.vpc | ||||||
| from boto.exception import BotoServerError | from boto.exception import BotoServerError | ||||||
| import sure  # noqa | import sure  # noqa | ||||||
| 
 | 
 | ||||||
| from moto import mock_rds | from moto import mock_ec2, mock_rds | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @mock_rds | @mock_rds | ||||||
| @ -138,3 +139,55 @@ def test_add_security_group_to_database(): | |||||||
|     list(database.security_groups).should.have.length_of(1) |     list(database.security_groups).should.have.length_of(1) | ||||||
| 
 | 
 | ||||||
|     database.security_groups[0].name.should.equal("db_sg") |     database.security_groups[0].name.should.equal("db_sg") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_ec2 | ||||||
|  | @mock_rds | ||||||
|  | def test_add_database_subnet_group(): | ||||||
|  |     vpc_conn = boto.vpc.connect_to_region("us-west-2") | ||||||
|  |     vpc = vpc_conn.create_vpc("10.0.0.0/16") | ||||||
|  |     subnet1 = vpc_conn.create_subnet(vpc.id, "10.1.0.0/24") | ||||||
|  |     subnet2 = vpc_conn.create_subnet(vpc.id, "10.2.0.0/24") | ||||||
|  | 
 | ||||||
|  |     subnet_ids = [subnet1.id, subnet2.id] | ||||||
|  |     conn = boto.rds.connect_to_region("us-west-2") | ||||||
|  |     subnet_group = conn.create_db_subnet_group("db_subnet", "my db subnet", subnet_ids) | ||||||
|  |     subnet_group.name.should.equal('db_subnet') | ||||||
|  |     subnet_group.description.should.equal("my db subnet") | ||||||
|  |     list(subnet_group.subnet_ids).should.equal(subnet_ids) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_ec2 | ||||||
|  | @mock_rds | ||||||
|  | def test_describe_database_subnet_group(): | ||||||
|  |     vpc_conn = boto.vpc.connect_to_region("us-west-2") | ||||||
|  |     vpc = vpc_conn.create_vpc("10.0.0.0/16") | ||||||
|  |     subnet = vpc_conn.create_subnet(vpc.id, "10.1.0.0/24") | ||||||
|  | 
 | ||||||
|  |     conn = boto.rds.connect_to_region("us-west-2") | ||||||
|  |     conn.create_db_subnet_group("db_subnet1", "my db subnet", [subnet.id]) | ||||||
|  |     conn.create_db_subnet_group("db_subnet2", "my db subnet", [subnet.id]) | ||||||
|  | 
 | ||||||
|  |     list(conn.get_all_db_subnet_groups()).should.have.length_of(2) | ||||||
|  |     list(conn.get_all_db_subnet_groups("db_subnet1")).should.have.length_of(1) | ||||||
|  | 
 | ||||||
|  |     conn.get_all_db_subnet_groups.when.called_with("not-a-subnet").should.throw(BotoServerError) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @mock_ec2 | ||||||
|  | @mock_rds | ||||||
|  | def test_delete_database_subnet_group(): | ||||||
|  |     vpc_conn = boto.vpc.connect_to_region("us-west-2") | ||||||
|  |     vpc = vpc_conn.create_vpc("10.0.0.0/16") | ||||||
|  |     subnet = vpc_conn.create_subnet(vpc.id, "10.1.0.0/24") | ||||||
|  | 
 | ||||||
|  |     conn = boto.rds.connect_to_region("us-west-2") | ||||||
|  |     conn.create_db_subnet_group("db_subnet1", "my db subnet", [subnet.id]) | ||||||
|  |     list(conn.get_all_db_subnet_groups()).should.have.length_of(1) | ||||||
|  | 
 | ||||||
|  |     conn.delete_db_subnet_group("db_subnet1") | ||||||
|  |     list(conn.get_all_db_subnet_groups()).should.have.length_of(0) | ||||||
|  | 
 | ||||||
|  |     conn.delete_db_subnet_group.when.called_with("db_subnet1").should.throw(BotoServerError) | ||||||
|  | 
 | ||||||
|  | # TODO incorporate subnet groups with actual DBs | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user