moto/moto/rds/models.py

389 lines
16 KiB
Python
Raw Normal View History

2015-01-09 03:18:06 +00:00
from __future__ import unicode_literals
2015-01-10 18:50:37 +00:00
import copy
import datetime
2015-01-10 18:50:37 +00:00
2015-01-09 03:18:06 +00:00
import boto.rds
from jinja2 import Template
2015-01-11 21:15:08 +00:00
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
2015-01-09 03:18:06 +00:00
from moto.core import BaseBackend
2015-01-11 21:15:08 +00:00
from moto.core.utils import get_random_hex
from moto.ec2.models import ec2_backends
from moto.rds2.models import rds2_backends
2015-01-09 05:17:20 +00:00
from .exceptions import DBInstanceNotFoundError, DBSecurityGroupNotFoundError, DBSubnetGroupNotFoundError
2015-01-09 03:18:06 +00:00
class Database(object):
def __init__(self, **kwargs):
self.status = "available"
2015-01-10 18:50:37 +00:00
self.is_replica = False
self.replicas = []
2015-01-09 03:18:06 +00:00
self.region = kwargs.get('region')
self.engine = kwargs.get("engine")
self.engine_version = kwargs.get("engine_version")
2015-01-11 21:15:08 +00:00
if self.engine_version is None:
self.engine_version = "5.6.21"
2015-01-09 03:18:06 +00:00
self.iops = kwargs.get("iops")
self.storage_encrypted = kwargs.get("storage_encrypted", False)
if self.storage_encrypted:
self.kms_key_id = kwargs.get("kms_key_id", "default_kms_key_id")
else:
self.kms_key_id = kwargs.get("kms_key_id")
2015-01-09 03:18:06 +00:00
self.storage_type = kwargs.get("storage_type")
self.master_username = kwargs.get('master_username')
self.master_password = kwargs.get('master_password')
self.auto_minor_version_upgrade = kwargs.get('auto_minor_version_upgrade')
2015-01-11 21:15:08 +00:00
if self.auto_minor_version_upgrade is None:
self.auto_minor_version_upgrade = True
2015-01-09 03:18:06 +00:00
self.allocated_storage = kwargs.get('allocated_storage')
self.db_instance_identifier = kwargs.get('db_instance_identifier')
2015-01-10 18:50:37 +00:00
self.source_db_identifier = kwargs.get("source_db_identifier")
2015-01-09 03:18:06 +00:00
self.db_instance_class = kwargs.get('db_instance_class')
self.port = kwargs.get('port')
self.db_name = kwargs.get("db_name")
self.publicly_accessible = kwargs.get("publicly_accessible")
2015-01-11 21:15:08 +00:00
if self.publicly_accessible is None:
self.publicly_accessible = True
2015-01-09 03:18:06 +00:00
self.backup_retention_period = kwargs.get("backup_retention_period")
if self.backup_retention_period is None:
self.backup_retention_period = 1
self.availability_zone = kwargs.get("availability_zone")
self.multi_az = kwargs.get("multi_az")
self.db_subnet_group_name = kwargs.get("db_subnet_group_name")
2016-09-07 18:40:52 +00:00
self.instance_create_time = str(datetime.datetime.utcnow())
2015-01-10 18:50:37 +00:00
if self.db_subnet_group_name:
self.db_subnet_group = rds_backends[self.region].describe_subnet_groups(self.db_subnet_group_name)[0]
else:
self.db_subnet_group = []
2015-01-09 03:18:06 +00:00
2015-01-09 04:44:05 +00:00
self.security_groups = kwargs.get('security_groups', [])
2015-01-09 03:18:06 +00:00
# PreferredBackupWindow
# PreferredMaintenanceWindow
# backup_retention_period = self._get_param("BackupRetentionPeriod")
# OptionGroupName
# DBParameterGroupName
# VpcSecurityGroupIds.member.N
@property
def physical_resource_id(self):
return self.db_instance_identifier
2015-01-09 03:18:06 +00:00
@property
def address(self):
2015-01-11 21:27:02 +00:00
return "{0}.aaaaaaaaaa.{1}.rds.amazonaws.com".format(self.db_instance_identifier, self.region)
2015-01-09 03:18:06 +00:00
2015-01-10 18:50:37 +00:00
def add_replica(self, replica):
self.replicas.append(replica.db_instance_identifier)
def remove_replica(self, replica):
self.replicas.remove(replica.db_instance_identifier)
def set_as_replica(self):
self.is_replica = True
self.replicas = []
2015-01-09 04:44:05 +00:00
def update(self, db_kwargs):
for key, value in db_kwargs.items():
if value is not None:
setattr(self, key, value)
2015-01-11 21:15:08 +00:00
def get_cfn_attribute(self, attribute_name):
if attribute_name == 'Endpoint.Address':
return self.address
elif attribute_name == 'Endpoint.Port':
return self.port
raise UnformattedGetAttTemplateException()
@classmethod
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
properties = cloudformation_json['Properties']
db_instance_identifier = properties.get('DBInstanceIdentifier')
if not db_instance_identifier:
db_instance_identifier = resource_name.lower() + get_random_hex(12)
db_security_groups = properties.get('DBSecurityGroups')
if not db_security_groups:
db_security_groups = []
security_groups = [group.group_name for group in db_security_groups]
db_subnet_group = properties.get("DBSubnetGroupName")
db_subnet_group_name = db_subnet_group.subnet_name if db_subnet_group else None
db_kwargs = {
"auto_minor_version_upgrade": properties.get('AutoMinorVersionUpgrade'),
"allocated_storage": properties.get('AllocatedStorage'),
"availability_zone": properties.get("AvailabilityZone"),
"backup_retention_period": properties.get("BackupRetentionPeriod"),
"db_instance_class": properties.get('DBInstanceClass'),
"db_instance_identifier": db_instance_identifier,
"db_name": properties.get("DBName"),
"db_subnet_group_name": db_subnet_group_name,
"engine": properties.get("Engine"),
"engine_version": properties.get("EngineVersion"),
"iops": properties.get("Iops"),
"kms_key_id": properties.get("KmsKeyId"),
2015-01-11 21:15:08 +00:00
"master_password": properties.get('MasterUserPassword'),
"master_username": properties.get('MasterUsername'),
"multi_az": properties.get("MultiAZ"),
"port": properties.get('Port', 3306),
"publicly_accessible": properties.get("PubliclyAccessible"),
"region": region_name,
"security_groups": security_groups,
"storage_encrypted": properties.get("StorageEncrypted"),
2015-01-11 21:15:08 +00:00
"storage_type": properties.get("StorageType"),
"tags": properties.get("Tags"),
2015-01-11 21:15:08 +00:00
}
rds_backend = rds_backends[region_name]
source_db_identifier = properties.get("SourceDBInstanceIdentifier")
if source_db_identifier:
# Replica
db_kwargs["source_db_identifier"] = source_db_identifier
2015-01-11 21:15:08 +00:00
database = rds_backend.create_database_replica(db_kwargs)
else:
database = rds_backend.create_database(db_kwargs)
return database
2015-01-09 03:18:06 +00:00
def to_xml(self):
template = Template("""<DBInstance>
<BackupRetentionPeriod>{{ database.backup_retention_period }}</BackupRetentionPeriod>
<DBInstanceStatus>{{ database.status }}</DBInstanceStatus>
<MultiAZ>{{ database.multi_az }}</MultiAZ>
<VpcSecurityGroups/>
<DBInstanceIdentifier>{{ database.db_instance_identifier }}</DBInstanceIdentifier>
<PreferredBackupWindow>03:50-04:20</PreferredBackupWindow>
<PreferredMaintenanceWindow>wed:06:38-wed:07:08</PreferredMaintenanceWindow>
2015-01-10 18:50:37 +00:00
<ReadReplicaDBInstanceIdentifiers>
{% for replica_id in database.replicas %}
<ReadReplicaDBInstanceIdentifier>{{ replica_id }}</ReadReplicaDBInstanceIdentifier>
{% endfor %}
</ReadReplicaDBInstanceIdentifiers>
<StatusInfos>
{% if database.is_replica %}
<DBInstanceStatusInfo>
<StatusType>read replication</StatusType>
<Status>replicating</Status>
<Normal>true</Normal>
<Message></Message>
</DBInstanceStatusInfo>
{% endif %}
</StatusInfos>
{% if database.is_replica %}
<ReadReplicaSourceDBInstanceIdentifier>{{ database.source_db_identifier }}</ReadReplicaSourceDBInstanceIdentifier>
{% endif %}
2015-01-09 03:18:06 +00:00
<Engine>{{ database.engine }}</Engine>
<LicenseModel>general-public-license</LicenseModel>
<EngineVersion>{{ database.engine_version }}</EngineVersion>
<DBParameterGroups>
</DBParameterGroups>
<OptionGroupMemberships>
</OptionGroupMemberships>
<DBSecurityGroups>
2015-01-09 04:44:05 +00:00
{% for security_group in database.security_groups %}
2015-01-09 03:18:06 +00:00
<DBSecurityGroup>
<Status>active</Status>
2015-01-09 04:44:05 +00:00
<DBSecurityGroupName>{{ security_group }}</DBSecurityGroupName>
2015-01-09 03:18:06 +00:00
</DBSecurityGroup>
2015-01-09 04:44:05 +00:00
{% endfor %}
2015-01-09 03:18:06 +00:00
</DBSecurityGroups>
2015-01-11 21:15:08 +00:00
{% if database.db_subnet_group %}
2015-01-10 18:50:37 +00:00
<DBSubnetGroup>
<DBSubnetGroupName>{{ database.db_subnet_group.subnet_name }}</DBSubnetGroupName>
<DBSubnetGroupDescription>{{ database.db_subnet_group.description }}</DBSubnetGroupDescription>
<SubnetGroupStatus>{{ database.db_subnet_group.status }}</SubnetGroupStatus>
<Subnets>
{% for subnet in database.db_subnet_group.subnets %}
<Subnet>
<SubnetStatus>Active</SubnetStatus>
<SubnetIdentifier>{{ subnet.id }}</SubnetIdentifier>
<SubnetAvailabilityZone>
<Name>{{ subnet.availability_zone }}</Name>
<ProvisionedIopsCapable>false</ProvisionedIopsCapable>
</SubnetAvailabilityZone>
</Subnet>
{% endfor %}
</Subnets>
<VpcId>{{ database.db_subnet_group.vpc_id }}</VpcId>
</DBSubnetGroup>
2015-01-11 21:15:08 +00:00
{% endif %}
2015-01-09 03:18:06 +00:00
<PubliclyAccessible>{{ database.publicly_accessible }}</PubliclyAccessible>
<AutoMinorVersionUpgrade>{{ database.auto_minor_version_upgrade }}</AutoMinorVersionUpgrade>
<AllocatedStorage>{{ database.allocated_storage }}</AllocatedStorage>
<StorageEncrypted>{{ database.storage_encrypted }}</StorageEncrypted>
{% if database.kms_key_id %}
<KmsKeyId>{{ database.kms_key_id }}</KmsKeyId>
{% endif %}
{% if database.iops %}
<Iops>{{ database.iops }}</Iops>
<StorageType>io1</StorageType>
{% else %}
<StorageType>{{ database.storage_type }}</StorageType>
{% endif %}
2015-01-09 03:18:06 +00:00
<DBInstanceClass>{{ database.db_instance_class }}</DBInstanceClass>
<InstanceCreateTime>{{ database.instance_create_time }}</InstanceCreateTime>
2015-01-09 03:18:06 +00:00
<MasterUsername>{{ database.master_username }}</MasterUsername>
<Endpoint>
<Address>{{ database.address }}</Address>
<Port>{{ database.port }}</Port>
</Endpoint>
</DBInstance>""")
return template.render(database=self)
def delete(self, region_name):
backend = rds_backends[region_name]
backend.delete_database(self.db_instance_identifier)
2015-01-09 03:18:06 +00:00
2015-01-09 04:44:05 +00:00
class SecurityGroup(object):
def __init__(self, group_name, description):
self.group_name = group_name
self.description = description
2015-01-10 18:50:37 +00:00
self.status = "authorized"
2015-01-11 21:15:08 +00:00
self.ip_ranges = []
self.ec2_security_groups = []
2015-01-09 04:44:05 +00:00
def to_xml(self):
template = Template("""<DBSecurityGroup>
2015-01-11 21:15:08 +00:00
<EC2SecurityGroups>
{% for security_group in security_group.ec2_security_groups %}
<EC2SecurityGroup>
<EC2SecurityGroupId>{{ security_group.id }}</EC2SecurityGroupId>
<EC2SecurityGroupName>{{ security_group.name }}</EC2SecurityGroupName>
<EC2SecurityGroupOwnerId>{{ security_group.owner_id }}</EC2SecurityGroupOwnerId>
<Status>authorized</Status>
</EC2SecurityGroup>
{% endfor %}
</EC2SecurityGroups>
2015-01-09 04:44:05 +00:00
<DBSecurityGroupDescription>{{ security_group.description }}</DBSecurityGroupDescription>
<IPRanges>
{% for ip_range in security_group.ip_ranges %}
<IPRange>
<CIDRIP>{{ ip_range }}</CIDRIP>
<Status>authorized</Status>
</IPRange>
{% endfor %}
</IPRanges>
<OwnerId>{{ security_group.ownder_id }}</OwnerId>
<DBSecurityGroupName>{{ security_group.group_name }}</DBSecurityGroupName>
</DBSecurityGroup>""")
return template.render(security_group=self)
2015-01-11 21:15:08 +00:00
def authorize_cidr(self, cidr_ip):
2015-01-09 04:44:05 +00:00
self.ip_ranges.append(cidr_ip)
2015-01-11 21:15:08 +00:00
def authorize_security_group(self, security_group):
self.ec2_security_groups.append(security_group)
@classmethod
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
properties = cloudformation_json['Properties']
group_name = resource_name.lower() + get_random_hex(12)
description = properties['GroupDescription']
security_group_ingress_rules = properties.get('DBSecurityGroupIngress', [])
tags = properties.get('Tags')
2015-01-11 21:15:08 +00:00
ec2_backend = ec2_backends[region_name]
rds_backend = rds_backends[region_name]
security_group = rds_backend.create_security_group(
group_name,
description,
tags,
2015-01-11 21:15:08 +00:00
)
for security_group_ingress in security_group_ingress_rules:
for ingress_type, ingress_value in security_group_ingress.items():
if ingress_type == "CIDRIP":
security_group.authorize_cidr(ingress_value)
elif ingress_type == "EC2SecurityGroupName":
subnet = ec2_backend.get_security_group_from_name(ingress_value)
security_group.authorize_security_group(subnet)
elif ingress_type == "EC2SecurityGroupId":
subnet = ec2_backend.get_security_group_from_id(ingress_value)
security_group.authorize_security_group(subnet)
2015-01-11 21:15:08 +00:00
return security_group
def delete(self, region_name):
backend = rds_backends[region_name]
backend.delete_security_group(self.group_name)
2015-01-09 04:44:05 +00:00
2015-01-09 05:17:20 +00:00
class SubnetGroup(object):
def __init__(self, subnet_name, description, subnets):
self.subnet_name = subnet_name
self.description = description
self.subnets = subnets
2015-01-10 18:50:37 +00:00
self.status = "Complete"
2015-01-09 05:17:20 +00:00
self.vpc_id = self.subnets[0].vpc_id
def to_xml(self):
template = Template("""<DBSubnetGroup>
<VpcId>{{ subnet_group.vpc_id }}</VpcId>
2015-01-10 18:50:37 +00:00
<SubnetGroupStatus>{{ subnet_group.status }}</SubnetGroupStatus>
2015-01-09 05:17:20 +00:00
<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)
2015-01-11 21:15:08 +00:00
@classmethod
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
properties = cloudformation_json['Properties']
subnet_name = resource_name.lower() + get_random_hex(12)
description = properties['DBSubnetGroupDescription']
subnet_ids = properties['SubnetIds']
tags = properties.get('Tags')
2015-01-11 21:15:08 +00:00
ec2_backend = ec2_backends[region_name]
subnets = [ec2_backend.get_subnet(subnet_id) for subnet_id in subnet_ids]
rds_backend = rds_backends[region_name]
subnet_group = rds_backend.create_subnet_group(
subnet_name,
description,
subnets,
tags,
2015-01-11 21:15:08 +00:00
)
return subnet_group
def delete(self, region_name):
backend = rds_backends[region_name]
backend.delete_subnet_group(self.subnet_name)
2015-01-09 05:17:20 +00:00
2015-01-09 04:44:05 +00:00
class RDSBackend(BaseBackend):
2015-01-09 04:44:05 +00:00
def __init__(self, region):
self.region = region
2015-01-09 03:18:06 +00:00
def __getattr__(self, attr):
return self.rds2_backend().__getattribute__(attr)
2015-01-09 05:17:20 +00:00
def reset(self):
# preserve region
region = self.region
self.rds2_backend().reset()
self.__dict__ = {}
self.__init__(region)
2015-01-09 05:17:20 +00:00
def rds2_backend(self):
return rds2_backends[self.region]
2015-01-09 05:17:20 +00:00
rds_backends = dict((region.name, RDSBackend(region.name)) for region in boto.rds.regions())