diff --git a/moto/cloudformation/parsing.py b/moto/cloudformation/parsing.py index 3e348ac37..521658cee 100644 --- a/moto/cloudformation/parsing.py +++ b/moto/cloudformation/parsing.py @@ -14,6 +14,7 @@ from moto.elb import models as elb_models from moto.iam import models as iam_models from moto.kms import models as kms_models from moto.rds import models as rds_models +from moto.rds2 import models as rds2_models from moto.redshift import models as redshift_models from moto.route53 import models as route53_models from moto.s3 import models as s3_models @@ -56,6 +57,7 @@ MODEL_MAP = { "AWS::RDS::DBInstance": rds_models.Database, "AWS::RDS::DBSecurityGroup": rds_models.SecurityGroup, "AWS::RDS::DBSubnetGroup": rds_models.SubnetGroup, + "AWS::RDS::DBParameterGroup": rds2_models.DBParameterGroup, "AWS::Redshift::Cluster": redshift_models.Cluster, "AWS::Redshift::ClusterParameterGroup": redshift_models.ParameterGroup, "AWS::Redshift::ClusterSubnetGroup": redshift_models.SubnetGroup, @@ -311,7 +313,8 @@ class ResourceMap(collections.Mapping): if not resource_json: raise KeyError(resource_logical_id) new_resource = parse_and_create_resource(resource_logical_id, resource_json, self, self._region_name) - self._parsed_resources[resource_logical_id] = new_resource + if new_resource is not None: + self._parsed_resources[resource_logical_id] = new_resource return new_resource def __iter__(self): diff --git a/moto/rds/models.py b/moto/rds/models.py index 3ce005e5e..b63a30737 100644 --- a/moto/rds/models.py +++ b/moto/rds/models.py @@ -10,6 +10,7 @@ from moto.cloudformation.exceptions import UnformattedGetAttTemplateException from moto.core import BaseBackend from moto.core.utils import get_random_hex from moto.ec2.models import ec2_backends +from moto.rds2.models import rds2_backends from .exceptions import DBInstanceNotFoundError, DBSecurityGroupNotFoundError, DBSubnetGroupNotFoundError @@ -26,6 +27,11 @@ class Database(object): if self.engine_version is None: self.engine_version = "5.6.21" 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") self.storage_type = kwargs.get("storage_type") self.master_username = kwargs.get('master_username') self.master_password = kwargs.get('master_password') @@ -119,6 +125,7 @@ class Database(object): "engine": properties.get("Engine"), "engine_version": properties.get("EngineVersion"), "iops": properties.get("Iops"), + "kms_key_id": properties.get("KmsKeyId"), "master_password": properties.get('MasterUserPassword'), "master_username": properties.get('MasterUsername'), "multi_az": properties.get("MultiAZ"), @@ -126,7 +133,9 @@ class Database(object): "publicly_accessible": properties.get("PubliclyAccessible"), "region": region_name, "security_groups": security_groups, + "storage_encrypted": properties.get("StorageEncrypted"), "storage_type": properties.get("StorageType"), + "tags": properties.get("Tags"), } rds_backend = rds_backends[region_name] @@ -204,6 +213,10 @@ class Database(object): {{ database.publicly_accessible }} {{ database.auto_minor_version_upgrade }} {{ database.allocated_storage }} + {{ database.storage_encrypted }} + {% if database.kms_key_id %} + {{ database.kms_key_id }} + {% endif %} {% if database.iops %} {{ database.iops }} io1 @@ -220,6 +233,10 @@ class Database(object): """) return template.render(database=self) + def delete(self, region_name): + backend = rds_backends[region_name] + backend.delete_database(self.db_instance_identifier) + class SecurityGroup(object): def __init__(self, group_name, description): @@ -267,25 +284,33 @@ class SecurityGroup(object): properties = cloudformation_json['Properties'] group_name = resource_name.lower() + get_random_hex(12) description = properties['GroupDescription'] - security_group_ingress = properties['DBSecurityGroupIngress'] + security_group_ingress_rules = properties.get('DBSecurityGroupIngress', []) + tags = properties.get('Tags') ec2_backend = ec2_backends[region_name] rds_backend = rds_backends[region_name] security_group = rds_backend.create_security_group( group_name, description, + tags, ) - 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) + + 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) return security_group + def delete(self, region_name): + backend = rds_backends[region_name] + backend.delete_security_group(self.group_name) + class SubnetGroup(object): def __init__(self, subnet_name, description, subnets): @@ -324,6 +349,7 @@ class SubnetGroup(object): subnet_name = resource_name.lower() + get_random_hex(12) description = properties['DBSubnetGroupDescription'] subnet_ids = properties['SubnetIds'] + tags = properties.get('Tags') ec2_backend = ec2_backends[region_name] subnets = [ec2_backend.get_subnet(subnet_id) for subnet_id in subnet_ids] @@ -332,102 +358,31 @@ class SubnetGroup(object): subnet_name, description, subnets, + tags, ) return subnet_group + def delete(self, region_name): + backend = rds_backends[region_name] + backend.delete_subnet_group(self.subnet_name) + class RDSBackend(BaseBackend): - def __init__(self): - self.databases = {} - self.security_groups = {} - self.subnet_groups = {} + def __init__(self, region): + self.region = region - def create_database(self, db_kwargs): - database_id = db_kwargs['db_instance_identifier'] - database = Database(**db_kwargs) - self.databases[database_id] = database - return database + def __getattr__(self, attr): + return self.rds2_backend().__getattribute__(attr) - def create_database_replica(self, db_kwargs): - database_id = db_kwargs['db_instance_identifier'] - source_database_id = db_kwargs['source_db_identifier'] - primary = self.describe_databases(source_database_id)[0] - replica = copy.deepcopy(primary) - replica.update(db_kwargs) - replica.set_as_replica() - self.databases[database_id] = replica - primary.add_replica(replica) - return replica + def reset(self): + # preserve region + region = self.region + self.rds2_backend().reset() + self.__dict__ = {} + self.__init__(region) - def describe_databases(self, db_instance_identifier=None): - if db_instance_identifier: - if db_instance_identifier in self.databases: - return [self.databases[db_instance_identifier]] - else: - raise DBInstanceNotFoundError(db_instance_identifier) - return self.databases.values() + def rds2_backend(self): + return rds2_backends[self.region] - def modify_database(self, db_instance_identifier, db_kwargs): - database = self.describe_databases(db_instance_identifier)[0] - database.update(db_kwargs) - return database - - def delete_database(self, db_instance_identifier): - if db_instance_identifier in self.databases: - database = self.databases.pop(db_instance_identifier) - if database.is_replica: - primary = self.describe_databases(database.source_db_identifier)[0] - primary.remove_replica(database) - database.status = 'deleting' - return database - else: - raise DBInstanceNotFoundError(db_instance_identifier) - - def create_security_group(self, group_name, description): - security_group = SecurityGroup(group_name, description) - self.security_groups[group_name] = security_group - return security_group - - def describe_security_groups(self, security_group_name): - if security_group_name: - if security_group_name in self.security_groups: - return [self.security_groups[security_group_name]] - else: - raise DBSecurityGroupNotFoundError(security_group_name) - return self.security_groups.values() - - def delete_security_group(self, security_group_name): - if security_group_name in self.security_groups: - return self.security_groups.pop(security_group_name) - else: - raise DBSecurityGroupNotFoundError(security_group_name) - - def authorize_security_group(self, security_group_name, cidr_ip): - security_group = self.describe_security_groups(security_group_name)[0] - security_group.authorize_cidr(cidr_ip) - 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 = {} -for region in boto.rds.regions(): - rds_backends[region.name] = RDSBackend() +rds_backends = dict((region.name, RDSBackend(region.name)) for region in boto.rds.regions()) diff --git a/moto/rds/responses.py b/moto/rds/responses.py index 98015e7bb..5207264f6 100644 --- a/moto/rds/responses.py +++ b/moto/rds/responses.py @@ -12,7 +12,7 @@ class RDSResponse(BaseResponse): return rds_backends[self.region] def _get_db_kwargs(self): - return { + args = { "auto_minor_version_upgrade": self._get_param('AutoMinorVersionUpgrade'), "allocated_storage": self._get_int_param('AllocatedStorage'), "availability_zone": self._get_param("AvailabilityZone"), @@ -25,6 +25,7 @@ class RDSResponse(BaseResponse): "engine": self._get_param("Engine"), "engine_version": self._get_param("EngineVersion"), "iops": self._get_int_param("Iops"), + "kms_key_id": self._get_param("KmsKeyId"), "master_password": self._get_param('MasterUserPassword'), "master_username": self._get_param('MasterUsername'), "multi_az": self._get_bool_param("MultiAZ"), @@ -35,9 +36,13 @@ class RDSResponse(BaseResponse): "publicly_accessible": self._get_param("PubliclyAccessible"), "region": self.region, "security_groups": self._get_multi_param('DBSecurityGroups.member'), + "storage_encrypted": self._get_param("StorageEncrypted"), "storage_type": self._get_param("StorageType"), # VpcSecurityGroupIds.member.N + "tags": list(), } + args['tags'] = self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')) + return args def _get_db_replica_kwargs(self): return { @@ -54,6 +59,17 @@ class RDSResponse(BaseResponse): "storage_type": self._get_param("StorageType"), } + def unpack_complex_list_params(self, label, names): + unpacked_list = list() + count = 1 + while self._get_param('{0}.{1}.{2}'.format(label, count, names[0])): + param = dict() + for i in range(len(names)): + param[names[i]] = self._get_param('{0}.{1}.{2}'.format(label, count, names[i])) + unpacked_list.append(param) + count += 1 + return unpacked_list + def create_dbinstance(self): db_kwargs = self._get_db_kwargs() @@ -90,7 +106,8 @@ class RDSResponse(BaseResponse): def create_dbsecurity_group(self): group_name = self._get_param('DBSecurityGroupName') description = self._get_param('DBSecurityGroupDescription') - security_group = self.backend.create_security_group(group_name, description) + tags = self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')) + security_group = self.backend.create_security_group(group_name, description, tags) template = self.response_template(CREATE_SECURITY_GROUP_TEMPLATE) return template.render(security_group=security_group) @@ -118,7 +135,8 @@ class RDSResponse(BaseResponse): 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) + tags = self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')) + subnet_group = self.backend.create_subnet_group(subnet_name, description, subnets, tags) template = self.response_template(CREATE_SUBNET_GROUP_TEMPLATE) return template.render(subnet_group=subnet_group) diff --git a/moto/rds2/exceptions.py b/moto/rds2/exceptions.py index a5c935659..6fcae4b56 100644 --- a/moto/rds2/exceptions.py +++ b/moto/rds2/exceptions.py @@ -1,20 +1,22 @@ from __future__ import unicode_literals -import json +from jinja2 import Template from werkzeug.exceptions import BadRequest class RDSClientError(BadRequest): def __init__(self, code, message): super(RDSClientError, self).__init__() - self.description = json.dumps({ - "Error": { - "Code": code, - "Message": message, - 'Type': 'Sender', - }, - 'RequestId': '6876f774-7273-11e4-85dc-39e55ca848d1', - }) + template = Template(""" + + + {{ code }} + {{ message }} + Sender + + 6876f774-7273-11e4-85dc-39e55ca848d1 + """) + self.description = template.render(code=code, message=message) class DBInstanceNotFoundError(RDSClientError): @@ -37,3 +39,8 @@ class DBSubnetGroupNotFoundError(RDSClientError): 'DBSubnetGroupNotFound', "Subnet Group {0} not found.".format(subnet_group_name)) +class DBParameterGroupNotFoundError(RDSClientError): + def __init__(self, db_parameter_group_name): + super(DBParameterGroupNotFoundError, self).__init__( + 'DBParameterGroupNotFound', + 'DB Parameter Group {0} not found.'.format(db_parameter_group_name)) diff --git a/moto/rds2/models.py b/moto/rds2/models.py index 37ecbf873..9bb1f8200 100644 --- a/moto/rds2/models.py +++ b/moto/rds2/models.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import copy +from collections import defaultdict import boto.rds2 import json from jinja2 import Template @@ -10,7 +11,12 @@ from moto.cloudformation.exceptions import UnformattedGetAttTemplateException from moto.core import BaseBackend from moto.core.utils import get_random_hex from moto.ec2.models import ec2_backends -from .exceptions import RDSClientError, DBInstanceNotFoundError, DBSecurityGroupNotFoundError, DBSubnetGroupNotFoundError +from .exceptions import (RDSClientError, + DBInstanceNotFoundError, + DBSecurityGroupNotFoundError, + DBSubnetGroupNotFoundError, + DBParameterGroupNotFoundError) + class Database(object): @@ -35,6 +41,11 @@ class Database(object): if not self.engine_version and self.engine in self.default_engine_versions: self.engine_version = self.default_engine_versions[self.engine] 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") self.storage_type = kwargs.get("storage_type") self.master_username = kwargs.get('master_username') self.master_user_password = kwargs.get('master_user_password') @@ -64,13 +75,9 @@ class Database(object): self.security_groups = kwargs.get('security_groups', []) self.vpc_security_group_ids = kwargs.get('vpc_security_group_ids', []) self.preferred_maintenance_window = kwargs.get('preferred_maintenance_window', 'wed:06:38-wed:07:08') - self.db_parameter_group_name = kwargs.get('db_parameter_group_name', None) - self.default_parameter_groups = {"MySQL": "default.mysql5.6", - "mysql": "default.mysql5.6", - "postgres": "default.postgres9.3" - } - if not self.db_parameter_group_name and self.engine in self.default_parameter_groups: - self.db_parameter_group_name = self.default_parameter_groups[self.engine] + self.db_parameter_group_name = kwargs.get('db_parameter_group_name') + if self.db_parameter_group_name and self.db_parameter_group_name not in rds2_backends[self.region].db_parameter_groups: + raise DBParameterGroupNotFoundError(self.db_parameter_group_name) self.preferred_backup_window = kwargs.get('preferred_backup_window', '13:14-13:44') self.license_model = kwargs.get('license_model', 'general-public-license') @@ -84,6 +91,120 @@ class Database(object): self.character_set_name = kwargs.get('character_set_name', None) self.tags = kwargs.get('tags', []) + @property + def physical_resource_id(self): + return self.db_instance_identifier + + def db_parameter_groups(self): + if not self.db_parameter_group_name: + db_family, db_parameter_group_name = self.default_db_parameter_group_details() + description = 'Default parameter group for {0}'.format(db_family) + return [DBParameterGroup(name=db_parameter_group_name, + family=db_family, + description=description, + tags={})] + else: + return [rds2_backends[self.region].db_parameter_groups[self.db_parameter_group_name]] + + def default_db_parameter_group_details(self): + if not self.engine_version: + return (None, None) + + minor_engine_version = '.'.join(self.engine_version.rsplit('.')[:-1]) + db_family = '{0}{1}'.format(self.engine.lower(), minor_engine_version) + + return db_family, 'default.{0}'.format(db_family) + + def to_xml(self): + template = Template(""" + {{ database.backup_retention_period }} + {{ database.status }} + {{ database.multi_az }} + + {{ database.db_instance_identifier }} + 03:50-04:20 + wed:06:38-wed:07:08 + + {% for replica_id in database.replicas %} + {{ replica_id }} + {% endfor %} + + + {% if database.is_replica %} + + read replication + replicating + true + + + {% endif %} + + {% if database.is_replica %} + {{ database.source_db_identifier }} + {% endif %} + {{ database.engine }} + general-public-license + {{ database.engine_version }} + + + + {% for db_parameter_group in database.db_parameter_groups() %} + + in-sync + {{ db_parameter_group.name }} + + {% endfor %} + + + {% for security_group in database.security_groups %} + + active + {{ security_group }} + + {% endfor %} + + {% if database.db_subnet_group %} + + {{ database.db_subnet_group.subnet_name }} + {{ database.db_subnet_group.description }} + {{ database.db_subnet_group.status }} + + {% for subnet in database.db_subnet_group.subnets %} + + Active + {{ subnet.id }} + + {{ subnet.availability_zone }} + false + + + {% endfor %} + + {{ database.db_subnet_group.vpc_id }} + + {% endif %} + {{ database.publicly_accessible }} + {{ database.auto_minor_version_upgrade }} + {{ database.allocated_storage }} + {{ database.storage_encrypted }} + {% if database.kms_key_id %} + {{ database.kms_key_id }} + {% endif %} + {% if database.iops %} + {{ database.iops }} + io1 + {% else %} + {{ database.storage_type }} + {% endif %} + {{ database.db_instance_class }} + {{ database.master_username }} + +
{{ database.address }}
+ {{ database.port }} +
+
""") + return template.render(database=self) + @property def address(self): return "{0}.aaaaaaaaaa.{1}.rds.amazonaws.com".format(self.db_instance_identifier, self.region) @@ -135,21 +256,25 @@ class Database(object): "engine": properties.get("Engine"), "engine_version": properties.get("EngineVersion"), "iops": properties.get("Iops"), + "kms_key_id": properties.get("KmsKeyId"), "master_user_password": properties.get('MasterUserPassword'), "master_username": properties.get('MasterUsername'), "multi_az": properties.get("MultiAZ"), + "db_parameter_group_name": properties.get('DBParameterGroupName'), "port": properties.get('Port', 3306), "publicly_accessible": properties.get("PubliclyAccessible"), "region": region_name, "security_groups": security_groups, + "storage_encrypted": properties.get("StorageEncrypted"), "storage_type": properties.get("StorageType"), + "tags": properties.get("Tags"), } rds2_backend = rds2_backends[region_name] source_db_identifier = properties.get("SourceDBInstanceIdentifier") if source_db_identifier: # Replica - db_kwargs["source_db_identifier"] = source_db_identifier.db_instance_identifier + db_kwargs["source_db_identifier"] = source_db_identifier database = rds2_backend.create_database_replica(db_kwargs) else: database = rds2_backend.create_database(db_kwargs) @@ -236,15 +361,19 @@ class Database(object): def remove_tags(self, tag_keys): self.tags = [tag_set for tag_set in self.tags if tag_set['Key'] not in tag_keys] + def delete(self, region_name): + backend = rds2_backends[region_name] + backend.delete_database(self.db_instance_identifier) + class SecurityGroup(object): - def __init__(self, group_name, description): + def __init__(self, group_name, description, tags): self.group_name = group_name self.description = description self.status = "authorized" self.ip_ranges = [] self.ec2_security_groups = [] - self.tags = [] + self.tags = tags self.owner_id = '1234567890' self.vpc_id = None @@ -301,27 +430,29 @@ class SecurityGroup(object): properties = cloudformation_json['Properties'] group_name = resource_name.lower() + get_random_hex(12) description = properties['GroupDescription'] - security_group_ingress = properties['DBSecurityGroupIngress'] + security_group_ingress_rules = properties.get('DBSecurityGroupIngress', []) + tags = properties.get('Tags') ec2_backend = ec2_backends[region_name] rds2_backend = rds2_backends[region_name] security_group = rds2_backend.create_security_group( group_name, description, + tags, ) - 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) + 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) return security_group def get_tags(self): - # TODO: Write tags add/remove/list tests for SecurityGroups return self.tags def add_tags(self, tags): @@ -333,14 +464,18 @@ class SecurityGroup(object): def remove_tags(self, tag_keys): self.tags = [tag_set for tag_set in self.tags if tag_set['Key'] not in tag_keys] + def delete(self, region_name): + backend = rds2_backends[region_name] + backend.delete_security_group(self.group_name) + class SubnetGroup(object): - def __init__(self, subnet_name, description, subnets): + def __init__(self, subnet_name, description, subnets, tags): self.subnet_name = subnet_name self.description = description self.subnets = subnets self.status = "Complete" - self.tags = [] + self.tags = tags self.vpc_id = self.subnets[0].vpc_id def to_xml(self): @@ -392,6 +527,7 @@ class SubnetGroup(object): subnet_name = resource_name.lower() + get_random_hex(12) description = properties['DBSubnetGroupDescription'] subnet_ids = properties['SubnetIds'] + tags = properties.get('Tags') ec2_backend = ec2_backends[region_name] subnets = [ec2_backend.get_subnet(subnet_id) for subnet_id in subnet_ids] @@ -400,11 +536,11 @@ class SubnetGroup(object): subnet_name, description, subnets, + tags, ) return subnet_group def get_tags(self): - # TODO: Write tags add/remove/list tests for SubnetGroups return self.tags def add_tags(self, tags): @@ -416,15 +552,27 @@ class SubnetGroup(object): def remove_tags(self, tag_keys): self.tags = [tag_set for tag_set in self.tags if tag_set['Key'] not in tag_keys] + def delete(self, region_name): + backend = rds2_backends[region_name] + backend.delete_subnet_group(self.subnet_name) + class RDS2Backend(BaseBackend): - def __init__(self): + def __init__(self, region): + self.region = region self.arn_regex = re_compile(r'^arn:aws:rds:.*:[0-9]*:(db|es|og|pg|ri|secgrp|snapshot|subgrp):.*$') self.databases = {} + self.db_parameter_groups = {} + self.option_groups = {} self.security_groups = {} self.subnet_groups = {} - self.option_groups = {} + + def reset(self): + # preserve region + region = self.region + self.__dict__ = {} + self.__init__(region) def create_database(self, db_kwargs): database_id = db_kwargs['db_instance_identifier'] @@ -435,7 +583,10 @@ class RDS2Backend(BaseBackend): def create_database_replica(self, db_kwargs): database_id = db_kwargs['db_instance_identifier'] source_database_id = db_kwargs['source_db_identifier'] - primary = self.describe_databases(source_database_id)[0] + primary = self.find_db_from_id(source_database_id) + if self.arn_regex.match(source_database_id): + db_kwargs['region'] = self.region + replica = copy.deepcopy(primary) replica.update(db_kwargs) replica.set_as_replica() @@ -460,18 +611,31 @@ class RDS2Backend(BaseBackend): database = self.describe_databases(db_instance_identifier)[0] return database + def find_db_from_id(self, db_id): + if self.arn_regex.match(db_id): + arn_breakdown = db_id.split(':') + region = arn_breakdown[3] + backend = rds2_backends[region] + db_name = arn_breakdown[-1] + else: + backend = self + db_name = db_id + + return backend.describe_databases(db_name)[0] + def delete_database(self, db_instance_identifier): if db_instance_identifier in self.databases: database = self.databases.pop(db_instance_identifier) if database.is_replica: - primary = self.describe_databases(database.source_db_identifier)[0] + primary = self.find_db_from_id(database.source_db_identifier) primary.remove_replica(database) + database.status = 'deleting' return database else: raise DBInstanceNotFoundError(db_instance_identifier) - def create_security_group(self, group_name, description): - security_group = SecurityGroup(group_name, description) + def create_security_group(self, group_name, description, tags): + security_group = SecurityGroup(group_name, description, tags) self.security_groups[group_name] = security_group return security_group @@ -489,13 +653,19 @@ class RDS2Backend(BaseBackend): else: raise DBSecurityGroupNotFoundError(security_group_name) + def delete_db_parameter_group(self, db_parameter_group_name): + if db_parameter_group_name in self.db_parameter_groups: + return self.db_parameter_groups.pop(db_parameter_group_name) + else: + raise DBParameterGroupNotFoundError(db_parameter_group_name) + def authorize_security_group(self, security_group_name, cidr_ip): security_group = self.describe_security_groups(security_group_name)[0] security_group.authorize_cidr(cidr_ip) return security_group - def create_subnet_group(self, subnet_name, description, subnets): - subnet_group = SubnetGroup(subnet_name, description, subnets) + def create_subnet_group(self, subnet_name, description, subnets, tags): + subnet_group = SubnetGroup(subnet_name, description, subnets, tags) self.subnet_groups[subnet_name] = subnet_group return subnet_group @@ -580,24 +750,18 @@ class RDS2Backend(BaseBackend): @staticmethod def describe_option_group_options(engine_name, major_engine_version=None): - default_option_group_options = { - 'mysql': {'all': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "12", "OptionsDependedOn": [], "MajorEngineVersion": "5.6", "Persistent": false, "DefaultPort": 11211, "Permanent": false, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies how many memcached read operations (get) to perform before doing a COMMIT to start a new transaction", "DefaultValue": "1", "AllowedValues": "1-4294967295", "IsModifiable": true, "SettingName": "DAEMON_MEMCACHED_R_BATCH_SIZE", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies how many memcached write operations, such as add, set, or incr, to perform before doing a COMMIT to start a new transaction", "DefaultValue": "1", "AllowedValues": "1-4294967295", "IsModifiable": true, "SettingName": "DAEMON_MEMCACHED_W_BATCH_SIZE", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies how often to auto-commit idle connections that use the InnoDB memcached interface.", "DefaultValue": "5", "AllowedValues": "1-1073741824", "IsModifiable": true, "SettingName": "INNODB_API_BK_COMMIT_INTERVAL", "ApplyType": "DYNAMIC"}, {"SettingDescription": "Disables the use of row locks when using the InnoDB memcached interface.", "DefaultValue": "0", "AllowedValues": "0,1", "IsModifiable": true, "SettingName": "INNODB_API_DISABLE_ROWLOCK", "ApplyType": "STATIC"}, {"SettingDescription": "Locks the table used by the InnoDB memcached plugin, so that it cannot be dropped or altered by DDL through the SQL interface.", "DefaultValue": "0", "AllowedValues": "0,1", "IsModifiable": true, "SettingName": "INNODB_API_ENABLE_MDL", "ApplyType": "STATIC"}, {"SettingDescription": "Lets you control the transaction isolation level on queries processed by the memcached interface.", "DefaultValue": "0", "AllowedValues": "0-3", "IsModifiable": true, "SettingName": "INNODB_API_TRX_LEVEL", "ApplyType": "STATIC"}, {"SettingDescription": "The binding protocol to use which can be either auto, ascii, or binary. The default is auto which means the server automatically negotiates the protocol with the client.", "DefaultValue": "auto", "AllowedValues": "auto,ascii,binary", "IsModifiable": true, "SettingName": "BINDING_PROTOCOL", "ApplyType": "STATIC"}, {"SettingDescription": "The backlog queue configures how many network connections can be waiting to be processed by memcached", "DefaultValue": "1024", "AllowedValues": "1-2048", "IsModifiable": true, "SettingName": "BACKLOG_QUEUE_LIMIT", "ApplyType": "STATIC"}, {"SettingDescription": "Disable the use of compare and swap (CAS) which reduces the per-item size by 8 bytes.", "DefaultValue": "0", "AllowedValues": "0,1", "IsModifiable": true, "SettingName": "CAS_DISABLED", "ApplyType": "STATIC"}, {"SettingDescription": "Minimum chunk size in bytes to allocate for the smallest item\'s key, value, and flags. The default is 48 and you can get a significant memory efficiency gain with a lower value.", "DefaultValue": "48", "AllowedValues": "1-48", "IsModifiable": true, "SettingName": "CHUNK_SIZE", "ApplyType": "STATIC"}, {"SettingDescription": "Chunk size growth factor that controls the size of each successive chunk with each chunk growing times this amount larger than the previous chunk.", "DefaultValue": "1.25", "AllowedValues": "1-2", "IsModifiable": true, "SettingName": "CHUNK_SIZE_GROWTH_FACTOR", "ApplyType": "STATIC"}, {"SettingDescription": "If enabled when there is no more memory to store items, memcached will return an error rather than evicting items.", "DefaultValue": "0", "AllowedValues": "0,1", "IsModifiable": true, "SettingName": "ERROR_ON_MEMORY_EXHAUSTED", "ApplyType": "STATIC"}, {"SettingDescription": "Maximum number of concurrent connections. Setting this value to anything less than 10 prevents MySQL from starting.", "DefaultValue": "1024", "AllowedValues": "10-1024", "IsModifiable": true, "SettingName": "MAX_SIMULTANEOUS_CONNECTIONS", "ApplyType": "STATIC"}, {"SettingDescription": "Verbose level for memcached.", "DefaultValue": "v", "AllowedValues": "v,vv,vvv", "IsModifiable": true, "SettingName": "VERBOSITY", "ApplyType": "STATIC"}], "EngineName": "mysql", "Name": "MEMCACHED", "PortRequired": true, "Description": "Innodb Memcached for MySQL"}]}, "ResponseMetadata": {"RequestId": "c9847a08-9fca-11e4-9084-5754f80d5144"}}}', - '5.6': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "12", "OptionsDependedOn": [], "MajorEngineVersion": "5.6", "Persistent": false, "DefaultPort": 11211, "Permanent": false, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies how many memcached read operations (get) to perform before doing a COMMIT to start a new transaction", "DefaultValue": "1", "AllowedValues": "1-4294967295", "IsModifiable": true, "SettingName": "DAEMON_MEMCACHED_R_BATCH_SIZE", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies how many memcached write operations, such as add, set, or incr, to perform before doing a COMMIT to start a new transaction", "DefaultValue": "1", "AllowedValues": "1-4294967295", "IsModifiable": true, "SettingName": "DAEMON_MEMCACHED_W_BATCH_SIZE", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies how often to auto-commit idle connections that use the InnoDB memcached interface.", "DefaultValue": "5", "AllowedValues": "1-1073741824", "IsModifiable": true, "SettingName": "INNODB_API_BK_COMMIT_INTERVAL", "ApplyType": "DYNAMIC"}, {"SettingDescription": "Disables the use of row locks when using the InnoDB memcached interface.", "DefaultValue": "0", "AllowedValues": "0,1", "IsModifiable": true, "SettingName": "INNODB_API_DISABLE_ROWLOCK", "ApplyType": "STATIC"}, {"SettingDescription": "Locks the table used by the InnoDB memcached plugin, so that it cannot be dropped or altered by DDL through the SQL interface.", "DefaultValue": "0", "AllowedValues": "0,1", "IsModifiable": true, "SettingName": "INNODB_API_ENABLE_MDL", "ApplyType": "STATIC"}, {"SettingDescription": "Lets you control the transaction isolation level on queries processed by the memcached interface.", "DefaultValue": "0", "AllowedValues": "0-3", "IsModifiable": true, "SettingName": "INNODB_API_TRX_LEVEL", "ApplyType": "STATIC"}, {"SettingDescription": "The binding protocol to use which can be either auto, ascii, or binary. The default is auto which means the server automatically negotiates the protocol with the client.", "DefaultValue": "auto", "AllowedValues": "auto,ascii,binary", "IsModifiable": true, "SettingName": "BINDING_PROTOCOL", "ApplyType": "STATIC"}, {"SettingDescription": "The backlog queue configures how many network connections can be waiting to be processed by memcached", "DefaultValue": "1024", "AllowedValues": "1-2048", "IsModifiable": true, "SettingName": "BACKLOG_QUEUE_LIMIT", "ApplyType": "STATIC"}, {"SettingDescription": "Disable the use of compare and swap (CAS) which reduces the per-item size by 8 bytes.", "DefaultValue": "0", "AllowedValues": "0,1", "IsModifiable": true, "SettingName": "CAS_DISABLED", "ApplyType": "STATIC"}, {"SettingDescription": "Minimum chunk size in bytes to allocate for the smallest item\'s key, value, and flags. The default is 48 and you can get a significant memory efficiency gain with a lower value.", "DefaultValue": "48", "AllowedValues": "1-48", "IsModifiable": true, "SettingName": "CHUNK_SIZE", "ApplyType": "STATIC"}, {"SettingDescription": "Chunk size growth factor that controls the size of each successive chunk with each chunk growing times this amount larger than the previous chunk.", "DefaultValue": "1.25", "AllowedValues": "1-2", "IsModifiable": true, "SettingName": "CHUNK_SIZE_GROWTH_FACTOR", "ApplyType": "STATIC"}, {"SettingDescription": "If enabled when there is no more memory to store items, memcached will return an error rather than evicting items.", "DefaultValue": "0", "AllowedValues": "0,1", "IsModifiable": true, "SettingName": "ERROR_ON_MEMORY_EXHAUSTED", "ApplyType": "STATIC"}, {"SettingDescription": "Maximum number of concurrent connections. Setting this value to anything less than 10 prevents MySQL from starting.", "DefaultValue": "1024", "AllowedValues": "10-1024", "IsModifiable": true, "SettingName": "MAX_SIMULTANEOUS_CONNECTIONS", "ApplyType": "STATIC"}, {"SettingDescription": "Verbose level for memcached.", "DefaultValue": "v", "AllowedValues": "v,vv,vvv", "IsModifiable": true, "SettingName": "VERBOSITY", "ApplyType": "STATIC"}], "EngineName": "mysql", "Name": "MEMCACHED", "PortRequired": true, "Description": "Innodb Memcached for MySQL"}]}, "ResponseMetadata": {"RequestId": "c9847a08-9fca-11e4-9084-5754f80d5144"}}}', - }, - 'sqlserver-ee': {'all': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "2789.0.v1", "OptionsDependedOn": [], "MajorEngineVersion": "10.50", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "sqlserver-ee", "Name": "Mirroring", "PortRequired": false, "Description": "SQLServer Database Mirroring"}, {"MinimumRequiredMinorEngineVersion": "2789.0.v1", "OptionsDependedOn": [], "MajorEngineVersion": "10.50", "Persistent": true, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "sqlserver-ee", "Name": "TDE", "PortRequired": false, "Description": "SQL Server - Transparent Data Encryption"}, {"MinimumRequiredMinorEngineVersion": "2100.60.v1", "OptionsDependedOn": [], "MajorEngineVersion": "11.00", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "sqlserver-ee", "Name": "Mirroring", "PortRequired": false, "Description": "SQLServer Database Mirroring"}, {"MinimumRequiredMinorEngineVersion": "2100.60.v1", "OptionsDependedOn": [], "MajorEngineVersion": "11.00", "Persistent": true, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "sqlserver-ee", "Name": "TDE", "PortRequired": false, "Description": "SQL Server - Transparent Data Encryption"}]}, "ResponseMetadata": {"RequestId": "c9f2fd9b-9fcb-11e4-8add-31b6fe33145f"}}}', - '10.50': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "2789.0.v1", "OptionsDependedOn": [], "MajorEngineVersion": "10.50", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "sqlserver-ee", "Name": "Mirroring", "PortRequired": false, "Description": "SQLServer Database Mirroring"}, {"MinimumRequiredMinorEngineVersion": "2789.0.v1", "OptionsDependedOn": [], "MajorEngineVersion": "10.50", "Persistent": true, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "sqlserver-ee", "Name": "TDE", "PortRequired": false, "Description": "SQL Server - Transparent Data Encryption"}]}, "ResponseMetadata": {"RequestId": "e6326fd0-9fcb-11e4-99cf-55e92d4bbada"}}}', - '11.00': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "2100.60.v1", "OptionsDependedOn": [], "MajorEngineVersion": "11.00", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "sqlserver-ee", "Name": "Mirroring", "PortRequired": false, "Description": "SQLServer Database Mirroring"}, {"MinimumRequiredMinorEngineVersion": "2100.60.v1", "OptionsDependedOn": [], "MajorEngineVersion": "11.00", "Persistent": true, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "sqlserver-ee", "Name": "TDE", "PortRequired": false, "Description": "SQL Server - Transparent Data Encryption"}]}, "ResponseMetadata": {"RequestId": "222cbeeb-9fcc-11e4-bb07-576f5bf522b5"}}}' - }, - 'oracle-ee': {'all': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["XMLDB"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX", "PortRequired": false, "Description": "Oracle Application Express Runtime Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["APEX"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX-DEV", "PortRequired": false, "Description": "Oracle Application Express Development Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the desired encryption behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies the desired data integrity behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of encryption algorithms in order of intended use", "DefaultValue": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "AllowedValues": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_TYPES_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of checksumming algorithms in order of intended use", "DefaultValue": "SHA1,MD5", "AllowedValues": "SHA1,MD5", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER", "ApplyType": "STATIC"}], "EngineName": "oracle-ee", "Name": "NATIVE_NETWORK_ENCRYPTION", "PortRequired": false, "Description": "Oracle Advanced Security - Native Network Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": 1158, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "OEM", "PortRequired": true, "Description": "Oracle Enterprise Manager (Database Control only)"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "STATSPACK", "PortRequired": false, "Description": "Oracle Statspack"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE", "PortRequired": false, "Description": "Oracle Advanced Security - Transparent Data Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE_HSM", "PortRequired": false, "Description": "Oracle Advanced Security - TDE with HSM"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the timezone the user wants to change the system time to", "DefaultValue": "UTC", "AllowedValues": "Africa/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTC", "IsModifiable": true, "SettingName": "TIME_ZONE", "ApplyType": "DYNAMIC"}], "EngineName": "oracle-ee", "Name": "Timezone", "PortRequired": false, "Description": "Change time zone"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "XMLDB", "PortRequired": false, "Description": "Oracle XMLDB Repository"}]}, "ResponseMetadata": {"RequestId": "36a0a612-9fcc-11e4-a07c-e12b0fcebb71"}}}', - '11.2': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["XMLDB"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX", "PortRequired": false, "Description": "Oracle Application Express Runtime Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["APEX"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX-DEV", "PortRequired": false, "Description": "Oracle Application Express Development Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the desired encryption behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies the desired data integrity behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of encryption algorithms in order of intended use", "DefaultValue": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "AllowedValues": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_TYPES_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of checksumming algorithms in order of intended use", "DefaultValue": "SHA1,MD5", "AllowedValues": "SHA1,MD5", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER", "ApplyType": "STATIC"}], "EngineName": "oracle-ee", "Name": "NATIVE_NETWORK_ENCRYPTION", "PortRequired": false, "Description": "Oracle Advanced Security - Native Network Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": 1158, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "OEM", "PortRequired": true, "Description": "Oracle Enterprise Manager (Database Control only)"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "STATSPACK", "PortRequired": false, "Description": "Oracle Statspack"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE", "PortRequired": false, "Description": "Oracle Advanced Security - Transparent Data Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE_HSM", "PortRequired": false, "Description": "Oracle Advanced Security - TDE with HSM"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the timezone the user wants to change the system time to", "DefaultValue": "UTC", "AllowedValues": "Africa/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTC", "IsModifiable": true, "SettingName": "TIME_ZONE", "ApplyType": "DYNAMIC"}], "EngineName": "oracle-ee", "Name": "Timezone", "PortRequired": false, "Description": "Change time zone"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "XMLDB", "PortRequired": false, "Description": "Oracle XMLDB Repository"}]}, "ResponseMetadata": {"RequestId": "36a0a612-9fcc-11e4-a07c-e12b0fcebb71"}}}' - }, - 'oracle-sa': {'all': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["XMLDB"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX", "PortRequired": false, "Description": "Oracle Application Express Runtime Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["APEX"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX-DEV", "PortRequired": false, "Description": "Oracle Application Express Development Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the desired encryption behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies the desired data integrity behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of encryption algorithms in order of intended use", "DefaultValue": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "AllowedValues": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_TYPES_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of checksumming algorithms in order of intended use", "DefaultValue": "SHA1,MD5", "AllowedValues": "SHA1,MD5", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER", "ApplyType": "STATIC"}], "EngineName": "oracle-ee", "Name": "NATIVE_NETWORK_ENCRYPTION", "PortRequired": false, "Description": "Oracle Advanced Security - Native Network Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": 1158, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "OEM", "PortRequired": true, "Description": "Oracle Enterprise Manager (Database Control only)"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "STATSPACK", "PortRequired": false, "Description": "Oracle Statspack"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE", "PortRequired": false, "Description": "Oracle Advanced Security - Transparent Data Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE_HSM", "PortRequired": false, "Description": "Oracle Advanced Security - TDE with HSM"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the timezone the user wants to change the system time to", "DefaultValue": "UTC", "AllowedValues": "Africa/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTC", "IsModifiable": true, "SettingName": "TIME_ZONE", "ApplyType": "DYNAMIC"}], "EngineName": "oracle-ee", "Name": "Timezone", "PortRequired": false, "Description": "Change time zone"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "XMLDB", "PortRequired": false, "Description": "Oracle XMLDB Repository"}]}, "ResponseMetadata": {"RequestId": "36a0a612-9fcc-11e4-a07c-e12b0fcebb71"}}}', - '11.2': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["XMLDB"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX", "PortRequired": false, "Description": "Oracle Application Express Runtime Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["APEX"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX-DEV", "PortRequired": false, "Description": "Oracle Application Express Development Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the desired encryption behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies the desired data integrity behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of encryption algorithms in order of intended use", "DefaultValue": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "AllowedValues": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_TYPES_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of checksumming algorithms in order of intended use", "DefaultValue": "SHA1,MD5", "AllowedValues": "SHA1,MD5", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER", "ApplyType": "STATIC"}], "EngineName": "oracle-ee", "Name": "NATIVE_NETWORK_ENCRYPTION", "PortRequired": false, "Description": "Oracle Advanced Security - Native Network Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": 1158, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "OEM", "PortRequired": true, "Description": "Oracle Enterprise Manager (Database Control only)"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "STATSPACK", "PortRequired": false, "Description": "Oracle Statspack"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE", "PortRequired": false, "Description": "Oracle Advanced Security - Transparent Data Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE_HSM", "PortRequired": false, "Description": "Oracle Advanced Security - TDE with HSM"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the timezone the user wants to change the system time to", "DefaultValue": "UTC", "AllowedValues": "Africa/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTC", "IsModifiable": true, "SettingName": "TIME_ZONE", "ApplyType": "DYNAMIC"}], "EngineName": "oracle-ee", "Name": "Timezone", "PortRequired": false, "Description": "Change time zone"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "XMLDB", "PortRequired": false, "Description": "Oracle XMLDB Repository"}]}, "ResponseMetadata": {"RequestId": "36a0a612-9fcc-11e4-a07c-e12b0fcebb71"}}}' - }, - 'oracle-sa1': {'all': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["XMLDB"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX", "PortRequired": false, "Description": "Oracle Application Express Runtime Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["APEX"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX-DEV", "PortRequired": false, "Description": "Oracle Application Express Development Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the desired encryption behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies the desired data integrity behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of encryption algorithms in order of intended use", "DefaultValue": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "AllowedValues": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_TYPES_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of checksumming algorithms in order of intended use", "DefaultValue": "SHA1,MD5", "AllowedValues": "SHA1,MD5", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER", "ApplyType": "STATIC"}], "EngineName": "oracle-ee", "Name": "NATIVE_NETWORK_ENCRYPTION", "PortRequired": false, "Description": "Oracle Advanced Security - Native Network Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": 1158, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "OEM", "PortRequired": true, "Description": "Oracle Enterprise Manager (Database Control only)"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "STATSPACK", "PortRequired": false, "Description": "Oracle Statspack"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE", "PortRequired": false, "Description": "Oracle Advanced Security - Transparent Data Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE_HSM", "PortRequired": false, "Description": "Oracle Advanced Security - TDE with HSM"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the timezone the user wants to change the system time to", "DefaultValue": "UTC", "AllowedValues": "Africa/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTC", "IsModifiable": true, "SettingName": "TIME_ZONE", "ApplyType": "DYNAMIC"}], "EngineName": "oracle-ee", "Name": "Timezone", "PortRequired": false, "Description": "Change time zone"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "XMLDB", "PortRequired": false, "Description": "Oracle XMLDB Repository"}]}, "ResponseMetadata": {"RequestId": "36a0a612-9fcc-11e4-a07c-e12b0fcebb71"}}}', - '11.2': '{"DescribeOptionGroupOptionsResponse": {"DescribeOptionGroupOptionsResult": {"Marker": null, "OptionGroupOptions": [{"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["XMLDB"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX", "PortRequired": false, "Description": "Oracle Application Express Runtime Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": ["APEX"], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "APEX-DEV", "PortRequired": false, "Description": "Oracle Application Express Development Environment"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the desired encryption behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies the desired data integrity behavior", "DefaultValue": "REQUESTED", "AllowedValues": "ACCEPTED,REJECTED,REQUESTED,REQUIRED", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of encryption algorithms in order of intended use", "DefaultValue": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "AllowedValues": "RC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40", "IsModifiable": true, "SettingName": "SQLNET.ENCRYPTION_TYPES_SERVER", "ApplyType": "STATIC"}, {"SettingDescription": "Specifies list of checksumming algorithms in order of intended use", "DefaultValue": "SHA1,MD5", "AllowedValues": "SHA1,MD5", "IsModifiable": true, "SettingName": "SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER", "ApplyType": "STATIC"}], "EngineName": "oracle-ee", "Name": "NATIVE_NETWORK_ENCRYPTION", "PortRequired": false, "Description": "Oracle Advanced Security - Native Network Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": 1158, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "OEM", "PortRequired": true, "Description": "Oracle Enterprise Manager (Database Control only)"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "STATSPACK", "PortRequired": false, "Description": "Oracle Statspack"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE", "PortRequired": false, "Description": "Oracle Advanced Security - Transparent Data Encryption"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "TDE_HSM", "PortRequired": false, "Description": "Oracle Advanced Security - TDE with HSM"}, {"MinimumRequiredMinorEngineVersion": "0.2.v3", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": true, "DefaultPort": null, "Permanent": true, "OptionGroupOptionSettings": [{"SettingDescription": "Specifies the timezone the user wants to change the system time to", "DefaultValue": "UTC", "AllowedValues": "Africa/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTC", "IsModifiable": true, "SettingName": "TIME_ZONE", "ApplyType": "DYNAMIC"}], "EngineName": "oracle-ee", "Name": "Timezone", "PortRequired": false, "Description": "Change time zone"}, {"MinimumRequiredMinorEngineVersion": "0.2.v4", "OptionsDependedOn": [], "MajorEngineVersion": "11.2", "Persistent": false, "DefaultPort": null, "Permanent": false, "OptionGroupOptionSettings": [], "EngineName": "oracle-ee", "Name": "XMLDB", "PortRequired": false, "Description": "Oracle XMLDB Repository"}]}, "ResponseMetadata": {"RequestId": "36a0a612-9fcc-11e4-a07c-e12b0fcebb71"}}}' - } - } + default_option_group_options = {'mysql': {'5.6': '\n \n \n \n 5.611211TrueInnodb Memcached for MySQLMEMCACHED1-4294967295STATIC1TrueSpecifies how many memcached read operations (get) to perform before doing a COMMIT to start a new transactionDAEMON_MEMCACHED_R_BATCH_SIZE1-4294967295STATIC1TrueSpecifies how many memcached write operations, such as add, set, or incr, to perform before doing a COMMIT to start a new transactionDAEMON_MEMCACHED_W_BATCH_SIZE1-1073741824DYNAMIC5TrueSpecifies how often to auto-commit idle connections that use the InnoDB memcached interface.INNODB_API_BK_COMMIT_INTERVAL0,1STATIC0TrueDisables the use of row locks when using the InnoDB memcached interface.INNODB_API_DISABLE_ROWLOCK0,1STATIC0TrueLocks the table used by the InnoDB memcached plugin, so that it cannot be dropped or altered by DDL through the SQL interface.INNODB_API_ENABLE_MDL0-3STATIC0TrueLets you control the transaction isolation level on queries processed by the memcached interface.INNODB_API_TRX_LEVELauto,ascii,binarySTATICautoTrueThe binding protocol to use which can be either auto, ascii, or binary. The default is auto which means the server automatically negotiates the protocol with the client.BINDING_PROTOCOL1-2048STATIC1024TrueThe backlog queue configures how many network connections can be waiting to be processed by memcachedBACKLOG_QUEUE_LIMIT0,1STATIC0TrueDisable the use of compare and swap (CAS) which reduces the per-item size by 8 bytes.CAS_DISABLED1-48STATIC48TrueMinimum chunk size in bytes to allocate for the smallest item\'s key, value, and flags. The default is 48 and you can get a significant memory efficiency gain with a lower value.CHUNK_SIZE1-2STATIC1.25TrueChunk size growth factor that controls the size of each successive chunk with each chunk growing times this amount larger than the previous chunk.CHUNK_SIZE_GROWTH_FACTOR0,1STATIC0TrueIf enabled when there is no more memory to store items, memcached will return an error rather than evicting items.ERROR_ON_MEMORY_EXHAUSTED10-1024STATIC1024TrueMaximum number of concurrent connections. Setting this value to anything less than 10 prevents MySQL from starting.MAX_SIMULTANEOUS_CONNECTIONSv,vv,vvvSTATICvTrueVerbose level for memcached.VERBOSITYmysql\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n', + 'all': '\n \n \n \n 5.611211TrueInnodb Memcached for MySQLMEMCACHED1-4294967295STATIC1TrueSpecifies how many memcached read operations (get) to perform before doing a COMMIT to start a new transactionDAEMON_MEMCACHED_R_BATCH_SIZE1-4294967295STATIC1TrueSpecifies how many memcached write operations, such as add, set, or incr, to perform before doing a COMMIT to start a new transactionDAEMON_MEMCACHED_W_BATCH_SIZE1-1073741824DYNAMIC5TrueSpecifies how often to auto-commit idle connections that use the InnoDB memcached interface.INNODB_API_BK_COMMIT_INTERVAL0,1STATIC0TrueDisables the use of row locks when using the InnoDB memcached interface.INNODB_API_DISABLE_ROWLOCK0,1STATIC0TrueLocks the table used by the InnoDB memcached plugin, so that it cannot be dropped or altered by DDL through the SQL interface.INNODB_API_ENABLE_MDL0-3STATIC0TrueLets you control the transaction isolation level on queries processed by the memcached interface.INNODB_API_TRX_LEVELauto,ascii,binarySTATICautoTrueThe binding protocol to use which can be either auto, ascii, or binary. The default is auto which means the server automatically negotiates the protocol with the client.BINDING_PROTOCOL1-2048STATIC1024TrueThe backlog queue configures how many network connections can be waiting to be processed by memcachedBACKLOG_QUEUE_LIMIT0,1STATIC0TrueDisable the use of compare and swap (CAS) which reduces the per-item size by 8 bytes.CAS_DISABLED1-48STATIC48TrueMinimum chunk size in bytes to allocate for the smallest item\'s key, value, and flags. The default is 48 and you can get a significant memory efficiency gain with a lower value.CHUNK_SIZE1-2STATIC1.25TrueChunk size growth factor that controls the size of each successive chunk with each chunk growing times this amount larger than the previous chunk.CHUNK_SIZE_GROWTH_FACTOR0,1STATIC0TrueIf enabled when there is no more memory to store items, memcached will return an error rather than evicting items.ERROR_ON_MEMORY_EXHAUSTED10-1024STATIC1024TrueMaximum number of concurrent connections. Setting this value to anything less than 10 prevents MySQL from starting.MAX_SIMULTANEOUS_CONNECTIONSv,vv,vvvSTATICvTrueVerbose level for memcached.VERBOSITYmysql\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n'}, + 'oracle-ee': {'11.2': '\n \n \n \n 11.2XMLDBOracle Application Express Runtime EnvironmentAPEXoracle-ee\n \n 11.2APEXOracle Application Express Development EnvironmentAPEX-DEVoracle-ee\n \n 11.2Oracle Advanced Security - Native Network EncryptionNATIVE_NETWORK_ENCRYPTIONACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired encryption behaviorSQLNET.ENCRYPTION_SERVERACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired data integrity behaviorSQLNET.CRYPTO_CHECKSUM_SERVERRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40STATICRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40TrueSpecifies list of encryption algorithms in order of intended useSQLNET.ENCRYPTION_TYPES_SERVERSHA1,MD5STATICSHA1,MD5TrueSpecifies list of checksumming algorithms in order of intended useSQLNET.CRYPTO_CHECKSUM_TYPES_SERVERoracle-ee\n \n 11.21158TrueOracle Enterprise Manager (Database Control only)OEMoracle-ee\n \n 11.2Oracle StatspackSTATSPACKoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - Transparent Data EncryptionTDEoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - TDE with HSMTDE_HSMoracle-ee\n \n 11.2TrueTrueChange time zoneTimezoneAfrica/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTCDYNAMICUTCTrueSpecifies the timezone the user wants to change the system time toTIME_ZONEoracle-ee\n \n 11.2Oracle XMLDB RepositoryXMLDBoracle-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n', + 'all': '\n \n \n \n 11.2XMLDBOracle Application Express Runtime EnvironmentAPEXoracle-ee\n \n 11.2APEXOracle Application Express Development EnvironmentAPEX-DEVoracle-ee\n \n 11.2Oracle Advanced Security - Native Network EncryptionNATIVE_NETWORK_ENCRYPTIONACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired encryption behaviorSQLNET.ENCRYPTION_SERVERACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired data integrity behaviorSQLNET.CRYPTO_CHECKSUM_SERVERRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40STATICRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40TrueSpecifies list of encryption algorithms in order of intended useSQLNET.ENCRYPTION_TYPES_SERVERSHA1,MD5STATICSHA1,MD5TrueSpecifies list of checksumming algorithms in order of intended useSQLNET.CRYPTO_CHECKSUM_TYPES_SERVERoracle-ee\n \n 11.21158TrueOracle Enterprise Manager (Database Control only)OEMoracle-ee\n \n 11.2Oracle StatspackSTATSPACKoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - Transparent Data EncryptionTDEoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - TDE with HSMTDE_HSMoracle-ee\n \n 11.2TrueTrueChange time zoneTimezoneAfrica/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTCDYNAMICUTCTrueSpecifies the timezone the user wants to change the system time toTIME_ZONEoracle-ee\n \n 11.2Oracle XMLDB RepositoryXMLDBoracle-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n'}, + 'oracle-sa': {'11.2': '\n \n \n \n 11.2XMLDBOracle Application Express Runtime EnvironmentAPEXoracle-ee\n \n 11.2APEXOracle Application Express Development EnvironmentAPEX-DEVoracle-ee\n \n 11.2Oracle Advanced Security - Native Network EncryptionNATIVE_NETWORK_ENCRYPTIONACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired encryption behaviorSQLNET.ENCRYPTION_SERVERACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired data integrity behaviorSQLNET.CRYPTO_CHECKSUM_SERVERRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40STATICRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40TrueSpecifies list of encryption algorithms in order of intended useSQLNET.ENCRYPTION_TYPES_SERVERSHA1,MD5STATICSHA1,MD5TrueSpecifies list of checksumming algorithms in order of intended useSQLNET.CRYPTO_CHECKSUM_TYPES_SERVERoracle-ee\n \n 11.21158TrueOracle Enterprise Manager (Database Control only)OEMoracle-ee\n \n 11.2Oracle StatspackSTATSPACKoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - Transparent Data EncryptionTDEoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - TDE with HSMTDE_HSMoracle-ee\n \n 11.2TrueTrueChange time zoneTimezoneAfrica/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTCDYNAMICUTCTrueSpecifies the timezone the user wants to change the system time toTIME_ZONEoracle-ee\n \n 11.2Oracle XMLDB RepositoryXMLDBoracle-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n', + 'all': '\n \n \n \n 11.2XMLDBOracle Application Express Runtime EnvironmentAPEXoracle-ee\n \n 11.2APEXOracle Application Express Development EnvironmentAPEX-DEVoracle-ee\n \n 11.2Oracle Advanced Security - Native Network EncryptionNATIVE_NETWORK_ENCRYPTIONACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired encryption behaviorSQLNET.ENCRYPTION_SERVERACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired data integrity behaviorSQLNET.CRYPTO_CHECKSUM_SERVERRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40STATICRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40TrueSpecifies list of encryption algorithms in order of intended useSQLNET.ENCRYPTION_TYPES_SERVERSHA1,MD5STATICSHA1,MD5TrueSpecifies list of checksumming algorithms in order of intended useSQLNET.CRYPTO_CHECKSUM_TYPES_SERVERoracle-ee\n \n 11.21158TrueOracle Enterprise Manager (Database Control only)OEMoracle-ee\n \n 11.2Oracle StatspackSTATSPACKoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - Transparent Data EncryptionTDEoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - TDE with HSMTDE_HSMoracle-ee\n \n 11.2TrueTrueChange time zoneTimezoneAfrica/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTCDYNAMICUTCTrueSpecifies the timezone the user wants to change the system time toTIME_ZONEoracle-ee\n \n 11.2Oracle XMLDB RepositoryXMLDBoracle-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n'}, + 'oracle-sa1': {'11.2': '\n \n \n \n 11.2XMLDBOracle Application Express Runtime EnvironmentAPEXoracle-ee\n \n 11.2APEXOracle Application Express Development EnvironmentAPEX-DEVoracle-ee\n \n 11.2Oracle Advanced Security - Native Network EncryptionNATIVE_NETWORK_ENCRYPTIONACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired encryption behaviorSQLNET.ENCRYPTION_SERVERACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired data integrity behaviorSQLNET.CRYPTO_CHECKSUM_SERVERRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40STATICRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40TrueSpecifies list of encryption algorithms in order of intended useSQLNET.ENCRYPTION_TYPES_SERVERSHA1,MD5STATICSHA1,MD5TrueSpecifies list of checksumming algorithms in order of intended useSQLNET.CRYPTO_CHECKSUM_TYPES_SERVERoracle-ee\n \n 11.21158TrueOracle Enterprise Manager (Database Control only)OEMoracle-ee\n \n 11.2Oracle StatspackSTATSPACKoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - Transparent Data EncryptionTDEoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - TDE with HSMTDE_HSMoracle-ee\n \n 11.2TrueTrueChange time zoneTimezoneAfrica/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTCDYNAMICUTCTrueSpecifies the timezone the user wants to change the system time toTIME_ZONEoracle-ee\n \n 11.2Oracle XMLDB RepositoryXMLDBoracle-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n', + 'all': '\n \n \n \n 11.2XMLDBOracle Application Express Runtime EnvironmentAPEXoracle-ee\n \n 11.2APEXOracle Application Express Development EnvironmentAPEX-DEVoracle-ee\n \n 11.2Oracle Advanced Security - Native Network EncryptionNATIVE_NETWORK_ENCRYPTIONACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired encryption behaviorSQLNET.ENCRYPTION_SERVERACCEPTED,REJECTED,REQUESTED,REQUIREDSTATICREQUESTEDTrueSpecifies the desired data integrity behaviorSQLNET.CRYPTO_CHECKSUM_SERVERRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40STATICRC4_256,AES256,AES192,3DES168,RC4_128,AES128,3DES112,RC4_56,DES,RC4_40,DES40TrueSpecifies list of encryption algorithms in order of intended useSQLNET.ENCRYPTION_TYPES_SERVERSHA1,MD5STATICSHA1,MD5TrueSpecifies list of checksumming algorithms in order of intended useSQLNET.CRYPTO_CHECKSUM_TYPES_SERVERoracle-ee\n \n 11.21158TrueOracle Enterprise Manager (Database Control only)OEMoracle-ee\n \n 11.2Oracle StatspackSTATSPACKoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - Transparent Data EncryptionTDEoracle-ee\n \n 11.2TrueTrueOracle Advanced Security - TDE with HSMTDE_HSMoracle-ee\n \n 11.2TrueTrueChange time zoneTimezoneAfrica/Cairo,Africa/Casablanca,Africa/Harare,Africa/Monrovia,Africa/Nairobi,Africa/Tripoli,Africa/Windhoek,America/Araguaina,America/Asuncion,America/Bogota,America/Caracas,America/Chihuahua,America/Cuiaba,America/Denver,America/Fortaleza,America/Guatemala,America/Halifax,America/Manaus,America/Matamoros,America/Monterrey,America/Montevideo,America/Phoenix,America/Santiago,America/Tijuana,Asia/Amman,Asia/Ashgabat,Asia/Baghdad,Asia/Baku,Asia/Bangkok,Asia/Beirut,Asia/Calcutta,Asia/Damascus,Asia/Dhaka,Asia/Irkutsk,Asia/Jerusalem,Asia/Kabul,Asia/Karachi,Asia/Kathmandu,Asia/Krasnoyarsk,Asia/Magadan,Asia/Muscat,Asia/Novosibirsk,Asia/Riyadh,Asia/Seoul,Asia/Shanghai,Asia/Singapore,Asia/Taipei,Asia/Tehran,Asia/Tokyo,Asia/Ulaanbaatar,Asia/Vladivostok,Asia/Yakutsk,Asia/Yerevan,Atlantic/Azores,Australia/Adelaide,Australia/Brisbane,Australia/Darwin,Australia/Hobart,Australia/Perth,Australia/Sydney,Brazil/East,Canada/Newfoundland,Canada/Saskatchewan,Europe/Amsterdam,Europe/Athens,Europe/Dublin,Europe/Helsinki,Europe/Istanbul,Europe/Kaliningrad,Europe/Moscow,Europe/Paris,Europe/Prague,Europe/Sarajevo,Pacific/Auckland,Pacific/Fiji,Pacific/Guam,Pacific/Honolulu,Pacific/Samoa,US/Alaska,US/Central,US/Eastern,US/East-Indiana,US/Pacific,UTCDYNAMICUTCTrueSpecifies the timezone the user wants to change the system time toTIME_ZONEoracle-ee\n \n 11.2Oracle XMLDB RepositoryXMLDBoracle-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n'}, + 'sqlserver-ee': {'10.50': '\n \n \n \n 10.50SQLServer Database MirroringMirroringsqlserver-ee\n \n 10.50TrueSQL Server - Transparent Data EncryptionTDEsqlserver-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n', + '11.00': '\n \n \n \n 11.00SQLServer Database MirroringMirroringsqlserver-ee\n \n 11.00TrueSQL Server - Transparent Data EncryptionTDEsqlserver-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n', + 'all': '\n \n \n \n 10.50SQLServer Database MirroringMirroringsqlserver-ee\n \n 10.50TrueSQL Server - Transparent Data EncryptionTDEsqlserver-ee\n \n 11.00SQLServer Database MirroringMirroringsqlserver-ee\n \n 11.00TrueSQL Server - Transparent Data EncryptionTDEsqlserver-ee\n \n \n \n \n 457f7bb8-9fbf-11e4-9084-5754f80d5144\n \n'}} + if engine_name not in default_option_group_options: raise RDSClientError('InvalidParameterValue', 'Invalid DB engine: {0}'.format(engine_name)) if major_engine_version and major_engine_version not in default_option_group_options[engine_name]: @@ -620,6 +784,60 @@ class RDS2Backend(BaseBackend): self.option_groups[option_group_name].add_options(options_to_include) return self.option_groups[option_group_name] + def create_db_parameter_group(self, db_parameter_group_kwargs): + db_parameter_group_id = db_parameter_group_kwargs['name'] + if db_parameter_group_kwargs['name'] in self.db_parameter_groups: + raise RDSClientError('DBParameterGroupAlreadyExistsFault', + 'A DB parameter group named {0} already exists.'.format(db_parameter_group_kwargs['name'])) + if not db_parameter_group_kwargs.get('description'): + raise RDSClientError('InvalidParameterValue', + 'The parameter Description must be provided and must not be blank.') + if not db_parameter_group_kwargs.get('family'): + raise RDSClientError('InvalidParameterValue', + 'The parameter DBParameterGroupName must be provided and must not be blank.') + + db_parameter_group = DBParameterGroup(**db_parameter_group_kwargs) + self.db_parameter_groups[db_parameter_group_id] = db_parameter_group + return db_parameter_group + + def describe_db_parameter_groups(self, db_parameter_group_kwargs): + db_parameter_group_list = [] + + if db_parameter_group_kwargs.get('marker'): + marker = db_parameter_group_kwargs['marker'] + else: + marker = 0 + if db_parameter_group_kwargs.get('max_records'): + if db_parameter_group_kwargs['max_records'] < 20 or db_parameter_group_kwargs['max_records'] > 100: + raise RDSClientError('InvalidParameterValue', + 'Invalid value for max records. Must be between 20 and 100') + max_records = db_parameter_group_kwargs['max_records'] + else: + max_records = 100 + + for db_parameter_group_name, db_parameter_group in self.db_parameter_groups.items(): + if not db_parameter_group_kwargs.get('name') or db_parameter_group.name == db_parameter_group_kwargs.get('name'): + db_parameter_group_list.append(db_parameter_group) + else: + continue + + return db_parameter_group_list[marker:max_records+marker] + + def modify_db_parameter_group(self, db_parameter_group_name, db_parameter_group_parameters): + if db_parameter_group_name not in self.db_parameter_groups: + raise DBParameterGroupNotFoundError(db_parameter_group_name) + + db_parameter_group = self.db_parameter_groups[db_parameter_group_name] + db_parameter_group.update_parameters(db_parameter_group_parameters) + + return db_parameter_group + + def delete_db_parameter_group(self, db_parameter_group_name): + if db_parameter_group_name in self.db_parameter_groups: + return self.db_parameter_groups.pop(db_parameter_group_name) + else: + raise DBParameterGroupNotFoundError(db_parameter_group_name) + def list_tags_for_resource(self, arn): if self.arn_regex.match(arn): arn_breakdown = arn.split(':') @@ -635,19 +853,19 @@ class RDS2Backend(BaseBackend): if resource_name in self.option_groups: return self.option_groups[resource_name].get_tags() elif resource_type == 'pg': # Parameter Group - # TODO: Complete call to tags on resource type Parameter Group - return [] + if resource_name in self.db_parameter_groups: + return self.db_parameter_groups[resource_name].get_tags() elif resource_type == 'ri': # Reserved DB instance # TODO: Complete call to tags on resource type Reserved DB instance return [] elif resource_type == 'secgrp': # DB security group - if resource_type in self.security_groups: + if resource_name in self.security_groups: return self.security_groups[resource_name].get_tags() elif resource_type == 'snapshot': # DB Snapshot # TODO: Complete call to tags on resource type DB Snapshot return [] elif resource_type == 'subgrp': # DB subnet group - if resource_type in self.subnet_groups: + if resource_name in self.subnet_groups: return self.subnet_groups[resource_name].get_tags() else: raise RDSClientError('InvalidParameterValue', @@ -672,16 +890,16 @@ class RDS2Backend(BaseBackend): elif resource_type == 'ri': # Reserved DB instance return None elif resource_type == 'secgrp': # DB security group - if resource_type in self.security_groups: + if resource_name in self.security_groups: return self.security_groups[resource_name].remove_tags(tag_keys) elif resource_type == 'snapshot': # DB Snapshot return None elif resource_type == 'subgrp': # DB subnet group - if resource_type in self.subnet_groups: + if resource_name in self.subnet_groups: return self.subnet_groups[resource_name].remove_tags(tag_keys) else: raise RDSClientError('InvalidParameterValue', - 'Invalid resource name: {}'.format(arn)) + 'Invalid resource name: {0}'.format(arn)) def add_tags_to_resource(self, arn, tags): if self.arn_regex.match(arn): @@ -701,16 +919,16 @@ class RDS2Backend(BaseBackend): elif resource_type == 'ri': # Reserved DB instance return [] elif resource_type == 'secgrp': # DB security group - if resource_type in self.security_groups: + if resource_name in self.security_groups: return self.security_groups[resource_name].add_tags(tags) elif resource_type == 'snapshot': # DB Snapshot return [] elif resource_type == 'subgrp': # DB subnet group - if resource_type in self.subnet_groups: + if resource_name in self.subnet_groups: return self.subnet_groups[resource_name].add_tags(tags) else: raise RDSClientError('InvalidParameterValue', - 'Invalid resource name: {}'.format(arn)) + 'Invalid resource name: {0}'.format(arn)) class OptionGroup(object): @@ -736,6 +954,17 @@ class OptionGroup(object): }""") return template.render(option_group=self) + def to_xml(self): + template = Template(""" + {{ option_group.name }} + {{ option_group.vpc_and_non_vpc_instance_memberships }} + {{ option_group.major_engine_version }} + {{ option_group.engine_name }} + {{ option_group.description }} + + """) + return template.render(option_group=self) + def remove_options(self, options_to_remove): # TODO: Check for option in self.options and remove if exists. Raise error otherwise return @@ -758,11 +987,20 @@ class OptionGroup(object): class OptionGroupOption(object): - def __init__(self, engine_name, major_engine_version): - self.engine_name = engine_name - self.major_engine_version = major_engine_version - #TODO: Create validation for Options - #TODO: formulate way to store options settings + def __init__(self, **kwargs): + self.default_port = kwargs.get('default_port') + self.description = kwargs.get('description') + self.engine_name = kwargs.get('engine_name') + self.major_engine_version = kwargs.get('major_engine_version') + self.name = kwargs.get('name') + self.option_group_option_settings = self._make_option_group_option_settings(kwargs.get('option_group_option_settings', [])) + self.options_depended_on = kwargs.get('options_depended_on', []) + self.permanent = kwargs.get('permanent') + self.persistent = kwargs.get('persistent') + self.port_required = kwargs.get('port_required') + + def _make_option_group_option_settings(self, option_group_option_settings_kwargs): + return [OptionGroupOptionSetting(**setting_kwargs) for setting_kwargs in option_group_option_settings_kwargs] def to_json(self): template = Template("""{ "MinimumRequiredMinorEngineVersion": @@ -780,7 +1018,109 @@ class OptionGroupOption(object): }""") return template.render(option_group=self) + def to_xml(self): + template = Template(""" + {{ option_group.major_engine_version }} + {{ option_group.default_port }} + {{ option_group.port_required }} + {{ option_group.persistent }} + + {%- for option_name in option_group.options_depended_on -%} + {{ option_name }} + {%- endfor -%} + + {{ option_group.permanent }} + {{ option_group.description }} + {{ option_group.name }} + + {%- for setting in option_group.option_group_option_settings -%} + {{ setting.to_xml() }} + {%- endfor -%} + + {{ option_group.engine_name }} + {{ option_group.minimum_required_minor_engine_version }} +""") + return template.render(option_group=self) -rds2_backends = {} -for region in boto.rds2.regions(): - rds2_backends[region.name] = RDS2Backend() + +class OptionGroupOptionSetting(object): + def __init__(self, *kwargs): + self.allowed_values = kwargs.get('allowed_values') + self.apply_type = kwargs.get('apply_type') + self.default_value = kwargs.get('default_value') + self.is_modifiable = kwargs.get('is_modifiable') + self.setting_description = kwargs.get('setting_description') + self.setting_name = kwargs.get('setting_name') + + def to_xml(self): + template = Template(""" + {{ option_group_option_setting.allowed_values }} + {{ option_group_option_setting.apply_type }} + {{ option_group_option_setting.default_value }} + {{ option_group_option_setting.is_modifiable }} + {{ option_group_option_setting.setting_description }} + {{ option_group_option_setting.setting_name }} +""") + return template.render(option_group_option_setting=self) + +class DBParameterGroup(object): + def __init__(self, name, description, family, tags): + self.name = name + self.description = description + self.family = family + self.tags = tags + self.parameters = defaultdict(dict) + + def to_xml(self): + template = Template(""" + {{ param_group.name }} + {{ param_group.family }} + {{ param_group.description }} + """) + return template.render(param_group=self) + + def get_tags(self): + return self.tags + + def add_tags(self, tags): + new_keys = [tag_set['Key'] for tag_set in tags] + self.tags = [tag_set for tag_set in self.tags if tag_set['Key'] not in new_keys] + self.tags.extend(tags) + return self.tags + + def remove_tags(self, tag_keys): + self.tags = [tag_set for tag_set in self.tags if tag_set['Key'] not in tag_keys] + + def update_parameters(self, new_parameters): + for new_parameter in new_parameters: + parameter = self.parameters[new_parameter['ParameterName']] + parameter.update(new_parameter) + + def delete(self, region_name): + backend = rds2_backends[region_name] + backend.delete_db_parameter_group(self.name) + + @classmethod + def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name): + properties = cloudformation_json['Properties'] + + db_parameter_group_kwargs = { + 'description': properties['Description'], + 'family': properties['Family'], + 'name': resource_name.lower(), + 'tags': properties.get("Tags"), + } + db_parameter_group_parameters = [] + for db_parameter, db_parameter_value in properties.get('Parameters', {}).items(): + db_parameter_group_parameters.append({ + 'ParameterName': db_parameter, + 'ParameterValue': db_parameter_value, + }) + + rds2_backend = rds2_backends[region_name] + db_parameter_group = rds2_backend.create_db_parameter_group(db_parameter_group_kwargs) + db_parameter_group.update_parameters(db_parameter_group_parameters) + return db_parameter_group + + +rds2_backends = dict((region.name, RDS2Backend(region.name)) for region in boto.rds2.regions()) diff --git a/moto/rds2/responses.py b/moto/rds2/responses.py index bd51f6ea0..879edbdd3 100644 --- a/moto/rds2/responses.py +++ b/moto/rds2/responses.py @@ -1,8 +1,10 @@ from __future__ import unicode_literals +from collections import defaultdict from moto.core.responses import BaseResponse from moto.ec2.models import ec2_backends from .models import rds2_backends +from .exceptions import DBParameterGroupNotFoundError import json import re @@ -22,11 +24,12 @@ class RDS2Response(BaseResponse): "db_instance_class": self._get_param('DBInstanceClass'), "db_instance_identifier": self._get_param('DBInstanceIdentifier'), "db_name": self._get_param("DBName"), - # DBParameterGroupName + "db_parameter_group_name": self._get_param("DBParameterGroupName"), "db_subnet_group_name": self._get_param("DBSubnetGroupName"), "engine": self._get_param("Engine"), "engine_version": self._get_param("EngineVersion"), "iops": self._get_int_param("Iops"), + "kms_key_id": self._get_param("KmsKeyId"), "master_user_password": self._get_param('MasterUserPassword'), "master_username": self._get_param('MasterUsername'), "multi_az": self._get_bool_param("MultiAZ"), @@ -36,12 +39,13 @@ class RDS2Response(BaseResponse): # PreferredMaintenanceWindow "publicly_accessible": self._get_param("PubliclyAccessible"), "region": self.region, - "security_groups": self._get_multi_param('DBSecurityGroups.member'), + "security_groups": self._get_multi_param('DBSecurityGroups.DBSecurityGroupName'), + "storage_encrypted": self._get_param("StorageEncrypted"), "storage_type": self._get_param("StorageType"), # VpcSecurityGroupIds.member.N - "tags": list() + "tags": list(), } - args['tags'] = self.unpack_complex_list_params('Tags.member', ('Key', 'Value')) + args['tags'] = self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')) return args def _get_db_replica_kwargs(self): @@ -67,6 +71,14 @@ class RDS2Response(BaseResponse): 'name': self._get_param('OptionGroupName') } + def _get_db_parameter_group_kwargs(self): + return { + 'description': self._get_param('Description'), + 'family': self._get_param('DBParameterGroupFamily'), + 'name': self._get_param('DBParameterGroupName'), + 'tags': self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')), + } + def unpack_complex_list_params(self, label, names): unpacked_list = list() count = 1 @@ -150,7 +162,7 @@ class RDS2Response(BaseResponse): def add_tags_to_resource(self): arn = self._get_param('ResourceName') - tags = self.unpack_complex_list_params('Tags.member', ('Key', 'Value')) + tags = self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')) tags = self.backend.add_tags_to_resource(arn, tags) template = self.response_template(ADD_TAGS_TO_RESOURCE_TEMPLATE) return template.render(tags=tags) @@ -168,7 +180,8 @@ class RDS2Response(BaseResponse): def create_db_security_group(self): group_name = self._get_param('DBSecurityGroupName') description = self._get_param('DBSecurityGroupDescription') - security_group = self.backend.create_security_group(group_name, description) + tags = self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')) + security_group = self.backend.create_security_group(group_name, description, tags) template = self.response_template(CREATE_SECURITY_GROUP_TEMPLATE) return template.render(security_group=security_group) @@ -206,9 +219,10 @@ class RDS2Response(BaseResponse): def create_db_subnet_group(self): subnet_name = self._get_param('DBSubnetGroupName') description = self._get_param('DBSubnetGroupDescription') - subnet_ids = self._get_multi_param('SubnetIds.member') + subnet_ids = self._get_multi_param('SubnetIds.SubnetIdentifier') + tags = self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')) 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) + subnet_group = self.backend.create_subnet_group(subnet_name, description, subnets, tags) template = self.response_template(CREATE_SUBNET_GROUP_TEMPLATE) return template.render(subnet_group=subnet_group) @@ -283,225 +297,326 @@ class RDS2Response(BaseResponse): template = self.response_template(MODIFY_OPTION_GROUP_TEMPLATE) return template.render(option_group=option_group) + def create_dbparameter_group(self): + return self.create_db_parameter_group() -CREATE_DATABASE_TEMPLATE = """{ - "CreateDBInstanceResponse": { - "CreateDBInstanceResult": { - "DBInstance": {{ database.to_json() }} - }, - "ResponseMetadata": { "RequestId": "523e3218-afc7-11c3-90f5-f90431260ab4" } - } -}""" + def create_db_parameter_group(self): + kwargs = self._get_db_parameter_group_kwargs() + db_parameter_group = self.backend.create_db_parameter_group(kwargs) + template = self.response_template(CREATE_DB_PARAMETER_GROUP_TEMPLATE) + return template.render(db_parameter_group=db_parameter_group) -CREATE_DATABASE_REPLICA_TEMPLATE = """{"CreateDBInstanceReadReplicaResponse": { - "ResponseMetadata": { - "RequestId": "5e60c46d-a844-11e4-bb68-17f36418e58f" - }, - "CreateDBInstanceReadReplicaResult": { - "DBInstance": {{ database.to_json() }} - } -}}""" + def describe_dbparameter_groups(self): + return self.describe_db_parameter_groups() -DESCRIBE_DATABASES_TEMPLATE = """{ - "DescribeDBInstancesResponse": { - "DescribeDBInstancesResult": { - "DBInstances": [ - {%- for database in databases -%} - {%- if loop.index != 1 -%},{%- endif -%} - {{ database.to_json() }} + def describe_db_parameter_groups(self): + kwargs = self._get_db_parameter_group_kwargs() + kwargs['max_records'] = self._get_param('MaxRecords') + kwargs['marker'] = self._get_param('Marker') + db_parameter_groups = self.backend.describe_db_parameter_groups(kwargs) + template = self.response_template(DESCRIBE_DB_PARAMETER_GROUPS_TEMPLATE) + return template.render(db_parameter_groups=db_parameter_groups) + + def modify_dbparameter_group(self): + return self.modify_db_parameter_group() + + def modify_db_parameter_group(self): + db_parameter_group_name = self._get_param('DBParameterGroupName') + db_parameter_group_parameters = self._get_db_parameter_group_paramters() + db_parameter_group = self.backend.modify_db_parameter_group(db_parameter_group_name, + db_parameter_group_parameters) + template = self.response_template(MODIFY_DB_PARAMETER_GROUP_TEMPLATE) + return template.render(db_parameter_group=db_parameter_group) + + def _get_db_parameter_group_paramters(self): + parameter_group_parameters = defaultdict(dict) + for param_name, value in self.querystring.items(): + if not param_name.startswith('Parameters.Parameter'): + continue + + split_param_name = param_name.split('.') + param_id = split_param_name[2] + param_setting = split_param_name[3] + + parameter_group_parameters[param_id][param_setting] = value[0] + + return parameter_group_parameters.values() + + def describe_dbparameters(self): + return self.describe_db_parameters() + + def describe_db_parameters(self): + db_parameter_group_name = self._get_param('DBParameterGroupName') + db_parameter_groups = self.backend.describe_db_parameter_groups({'name': db_parameter_group_name}) + if not db_parameter_groups: + raise DBParameterGroupNotFoundError(db_parameter_group_name) + + template = self.response_template(DESCRIBE_DB_PARAMETERS_TEMPLATE) + return template.render(db_parameter_group=db_parameter_groups[0]) + + def delete_dbparameter_group(self): + return self.delete_db_parameter_group() + + def delete_db_parameter_group(self): + kwargs = self._get_db_parameter_group_kwargs() + db_parameter_group = self.backend.delete_db_parameter_group(kwargs['name']) + template = self.response_template(DELETE_DB_PARAMETER_GROUP_TEMPLATE) + return template.render(db_parameter_group=db_parameter_group) + + +CREATE_DATABASE_TEMPLATE = """ + + {{ database.to_xml() }} + + + 523e3218-afc7-11c3-90f5-f90431260ab4 + +""" + +CREATE_DATABASE_REPLICA_TEMPLATE = """ + + {{ database.to_xml() }} + + + 5e60c46d-a844-11e4-bb68-17f36418e58f + +""" + +DESCRIBE_DATABASES_TEMPLATE = """ + + + {%- for database in databases -%} + {{ database.to_xml() }} + {%- endfor -%} + + + + 523e3218-afc7-11c3-90f5-f90431260ab4 + +""" + +MODIFY_DATABASE_TEMPLATE = """ + + {{ database.to_xml() }} + + + bb58476c-a1a8-11e4-99cf-55e92d4bbada + +""" + +REBOOT_DATABASE_TEMPLATE = """ + + {{ database.to_xml() }} + + + d55711cb-a1ab-11e4-99cf-55e92d4bbada + +""" + + +DELETE_DATABASE_TEMPLATE = """ + + {{ database.to_xml() }} + + + 7369556f-b70d-11c3-faca-6ba18376ea1b + +""" + +CREATE_SECURITY_GROUP_TEMPLATE = """ + + {{ security_group.to_xml() }} + + + 462165d0-a77a-11e4-a5fa-75b30c556f97 + +""" + +DESCRIBE_SECURITY_GROUPS_TEMPLATE = """ + + + {% for security_group in security_groups %} + {{ security_group.to_xml() }} + {% endfor %} + + + + 5df2014e-a779-11e4-bdb0-594def064d0c + +""" + +DELETE_SECURITY_GROUP_TEMPLATE = """ + + 97e846bd-a77d-11e4-ac58-91351c0f3426 + +""" + +AUTHORIZE_SECURITY_GROUP_TEMPLATE = """ + + {{ security_group.to_xml() }} + + + 75d32fd5-a77e-11e4-8892-b10432f7a87d + +""" + +CREATE_SUBNET_GROUP_TEMPLATE = """ + + {{ subnet_group.to_xml() }} + + + 3a401b3f-bb9e-11d3-f4c6-37db295f7674 + +""" + +DESCRIBE_SUBNET_GROUPS_TEMPLATE = """ + + + {% for subnet_group in subnet_groups %} + {{ subnet_group.to_xml() }} + {% endfor %} + + + + b783db3b-b98c-11d3-fbc7-5c0aad74da7c + +""" + +DELETE_SUBNET_GROUP_TEMPLATE = """ + + 13785dd5-a7fc-11e4-bb9c-7f371d0859b0 + +""" + +CREATE_OPTION_GROUP_TEMPLATE = """ + + {{ option_group.to_xml() }} + + + 1e38dad4-9f50-11e4-87ea-a31c60ed2e36 + +""" + +DELETE_OPTION_GROUP_TEMPLATE = """ + + e2590367-9fa2-11e4-99cf-55e92d41c60e + +""" + +DESCRIBE_OPTION_GROUP_TEMPLATE = """ + + + {%- for option_group in option_groups -%} + {{ option_group.to_xml() }} + {%- endfor -%} + + + + 4caf445d-9fbc-11e4-87ea-a31c60ed2e36 + +""" + +DESCRIBE_OPTION_GROUP_OPTIONS_TEMPLATE = """ + + + {%- for option_group_option in option_group_options -%} + {{ option_group_option.to_xml() }} + {%- endfor -%} + + + + 457f7bb8-9fbf-11e4-9084-5754f80d5144 + +""" + +MODIFY_OPTION_GROUP_TEMPLATE = """ + + {{ option_group.to_xml() }} + + + ce9284a5-a0de-11e4-b984-a11a53e1f328 + +""" + +CREATE_DB_PARAMETER_GROUP_TEMPLATE = """ + + {{ db_parameter_group.to_xml() }} + + + 7805c127-af22-11c3-96ac-6999cc5f7e72 + +""" + +DESCRIBE_DB_PARAMETER_GROUPS_TEMPLATE = """ + + + {%- for db_parameter_group in db_parameter_groups -%} + {{ db_parameter_group.to_xml() }} + {%- endfor -%} + + + + b75d527a-b98c-11d3-f272-7cd6cce12cc5 + +""" + +MODIFY_DB_PARAMETER_GROUP_TEMPLATE = """ + + {{ db_parameter_group.name }} + + + 12d7435e-bba0-11d3-fe11-33d33a9bb7e3 + +""" + +DELETE_DB_PARAMETER_GROUP_TEMPLATE = """ + + cad6c267-ba25-11d3-fe11-33d33a9bb7e3 + +""" + +DESCRIBE_DB_PARAMETERS_TEMPLATE = """ + + + {%- for db_parameter_name, db_parameter in db_parameter_group.parameters.items() -%} + + {%- for parameter_name, parameter_value in db_parameter.items() -%} + <{{ parameter_name }}>{{ parameter_value }} {%- endfor -%} - ] - }, - "ResponseMetadata": { "RequestId": "523e3218-afc7-11c3-90f5-f90431260ab4" } - } -}""" + + {%- endfor -%} + + + + 8c40488f-b9ff-11d3-a15e-7ac49293f4fa + + +""" -MODIFY_DATABASE_TEMPLATE = """{"ModifyDBInstanceResponse": { - "ModifyDBInstanceResult": { - "DBInstance": {{ database.to_json() }}, - "ResponseMetadata": { - "RequestId": "bb58476c-a1a8-11e4-99cf-55e92d4bbada" - } - } - } -}""" +LIST_TAGS_FOR_RESOURCE_TEMPLATE = """ + + + {%- for tag in tags -%} + + {{ tag['Key'] }} + {{ tag['Value'] }} + + {%- endfor -%} + + + + 8c21ba39-a598-11e4-b688-194eaf8658fa + +""" -REBOOT_DATABASE_TEMPLATE = """{"RebootDBInstanceResponse": { - "RebootDBInstanceResult": { - "DBInstance": {{ database.to_json() }}, - "ResponseMetadata": { - "RequestId": "d55711cb-a1ab-11e4-99cf-55e92d4bbada" - } - } - } -}""" +ADD_TAGS_TO_RESOURCE_TEMPLATE = """ + + b194d9ca-a664-11e4-b688-194eaf8658fa + +""" - -DELETE_DATABASE_TEMPLATE = """{ "DeleteDBInstanceResponse": { - "DeleteDBInstanceResult": { - "DBInstance": {{ database.to_json() }} - }, - "ResponseMetadata": { - "RequestId": "523e3218-afc7-11c3-90f5-f90431260ab4" - } - } -}""" - -CREATE_SECURITY_GROUP_TEMPLATE = """{"CreateDBSecurityGroupResponse": { - "CreateDBSecurityGroupResult": { - "DBSecurityGroup": - {{ security_group.to_json() }}, - "ResponseMetadata": { - "RequestId": "462165d0-a77a-11e4-a5fa-75b30c556f97" - }} - } -}""" - -DESCRIBE_SECURITY_GROUPS_TEMPLATE = """{ - "DescribeDBSecurityGroupsResponse": { - "ResponseMetadata": { - "RequestId": "5df2014e-a779-11e4-bdb0-594def064d0c" - }, - "DescribeDBSecurityGroupsResult": { - "Marker": "null", - "DBSecurityGroups": [ - {% for security_group in security_groups %} - {%- if loop.index != 1 -%},{%- endif -%} - {{ security_group.to_json() }} - {% endfor %} - ] - } - } -}""" - -DELETE_SECURITY_GROUP_TEMPLATE = """{"DeleteDBSecurityGroupResponse": { - "ResponseMetadata": { - "RequestId": "97e846bd-a77d-11e4-ac58-91351c0f3426" - } -}}""" - -AUTHORIZE_SECURITY_GROUP_TEMPLATE = """{ - "AuthorizeDBSecurityGroupIngressResponse": { - "AuthorizeDBSecurityGroupIngressResult": { - "DBSecurityGroup": {{ security_group.to_json() }} - }, - "ResponseMetadata": { - "RequestId": "75d32fd5-a77e-11e4-8892-b10432f7a87d" - } - } -}""" - -CREATE_SUBNET_GROUP_TEMPLATE = """{ - "CreateDBSubnetGroupResponse": { - "CreateDBSubnetGroupResult": - { {{ subnet_group.to_json() }} }, - "ResponseMetadata": { "RequestId": "3a401b3f-bb9e-11d3-f4c6-37db295f7674" } - } -}""" - -DESCRIBE_SUBNET_GROUPS_TEMPLATE = """{ - "DescribeDBSubnetGroupsResponse": { - "DescribeDBSubnetGroupsResult": { - "DBSubnetGroups": [ - {% for subnet_group in subnet_groups %} - { {{ subnet_group.to_json() }} }{%- if not loop.last -%},{%- endif -%} - {% endfor %} - ], - "Marker": null - }, - "ResponseMetadata": { "RequestId": "b783db3b-b98c-11d3-fbc7-5c0aad74da7c" } - } -}""" - - -DELETE_SUBNET_GROUP_TEMPLATE = """{"DeleteDBSubnetGroupResponse": {"ResponseMetadata": {"RequestId": "13785dd5-a7fc-11e4-bb9c-7f371d0859b0"}}}""" - -CREATE_OPTION_GROUP_TEMPLATE = """{ - "CreateOptionGroupResponse": { - "CreateOptionGroupResult": { - "OptionGroup": {{ option_group.to_json() }} - }, - "ResponseMetadata": { - "RequestId": "1e38dad4-9f50-11e4-87ea-a31c60ed2e36" - } - } -}""" - -DELETE_OPTION_GROUP_TEMPLATE = \ - """{"DeleteOptionGroupResponse": {"ResponseMetadata": {"RequestId": "e2590367-9fa2-11e4-99cf-55e92d41c60e"}}}""" - -DESCRIBE_OPTION_GROUP_TEMPLATE = \ - """{"DescribeOptionGroupsResponse": { - "DescribeOptionGroupsResult": { - "Marker": null, - "OptionGroupsList": [ - {%- for option_group in option_groups -%} - {%- if loop.index != 1 -%},{%- endif -%} - {{ option_group.to_json() }} - {%- endfor -%} - ]}, - "ResponseMetadata": {"RequestId": "4caf445d-9fbc-11e4-87ea-a31c60ed2e36"} - }}""" - -DESCRIBE_OPTION_GROUP_OPTIONS_TEMPLATE = \ - """{"DescribeOptionGroupOptionsResponse": { - "DescribeOptionGroupOptionsResult": { - "Marker": null, - "OptionGroupOptions": [ - {%- for option_group_option in option_group_options -%} - {%- if loop.index != 1 -%},{%- endif -%} - {{ option_group_option.to_json() }} - {%- endfor -%} - ]}, - "ResponseMetadata": {"RequestId": "457f7bb8-9fbf-11e4-9084-5754f80d5144"} - }}""" - -MODIFY_OPTION_GROUP_TEMPLATE = \ - """{"ModifyOptionGroupResponse": { - "ResponseMetadata": { - "RequestId": "ce9284a5-a0de-11e4-b984-a11a53e1f328" - }, - "ModifyOptionGroupResult": - {{ option_group.to_json() }} - } - }""" - -LIST_TAGS_FOR_RESOURCE_TEMPLATE = \ - """{"ListTagsForResourceResponse": - {"ListTagsForResourceResult": - {"TagList": [ - {%- for tag in tags -%} - {%- if loop.index != 1 -%},{%- endif -%} - { - "Key": "{{ tag['Key'] }}", - "Value": "{{ tag['Value'] }}" - } - {%- endfor -%} - ]}, - "ResponseMetadata": { - "RequestId": "8c21ba39-a598-11e4-b688-194eaf8658fa" - } - } - }""" - -ADD_TAGS_TO_RESOURCE_TEMPLATE = \ - """{"ListTagsForResourceResponse": { - "ListTagsForResourceResult": { - "TagList": [ - {%- for tag in tags -%} - {%- if loop.index != 1 -%},{%- endif -%} - { - "Key": "{{ tag['Key'] }}", - "Value": "{{ tag['Value'] }}" - } - {%- endfor -%} - ]}, - "ResponseMetadata": { - "RequestId": "b194d9ca-a664-11e4-b688-194eaf8658fa" - } - } - }""" - -REMOVE_TAGS_FROM_RESOURCE_TEMPLATE = \ - """{"RemoveTagsFromResourceResponse": {"ResponseMetadata": {"RequestId": "c6499a01-a664-11e4-8069-fb454b71a80e"}}} - """ +REMOVE_TAGS_FROM_RESOURCE_TEMPLATE = """ + + b194d9ca-a664-11e4-b688-194eaf8658fa + +""" diff --git a/tests/test_cloudformation/fixtures/rds_mysql_with_db_parameter_group.py b/tests/test_cloudformation/fixtures/rds_mysql_with_db_parameter_group.py new file mode 100644 index 000000000..866197125 --- /dev/null +++ b/tests/test_cloudformation/fixtures/rds_mysql_with_db_parameter_group.py @@ -0,0 +1,201 @@ +from __future__ import unicode_literals + +template = { + "AWSTemplateFormatVersion" : "2010-09-09", + + "Description" : "AWS CloudFormation Sample Template RDS_MySQL_With_Read_Replica: Sample template showing how to create a highly-available, RDS DBInstance with a read replica. **WARNING** This template creates an Amazon Relational Database Service database instance and Amazon CloudWatch alarms. You will be billed for the AWS resources used if you create a stack from this template.", + + "Parameters": { + "DBName": { + "Default": "MyDatabase", + "Description" : "The database name", + "Type": "String", + "MinLength": "1", + "MaxLength": "64", + "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*", + "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters." + }, + + "DBInstanceIdentifier": { + "Type": "String" + }, + + "DBUser": { + "NoEcho": "true", + "Description" : "The database admin account username", + "Type": "String", + "MinLength": "1", + "MaxLength": "16", + "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*", + "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters." + }, + + "DBPassword": { + "NoEcho": "true", + "Description" : "The database admin account password", + "Type": "String", + "MinLength": "1", + "MaxLength": "41", + "AllowedPattern" : "[a-zA-Z0-9]+", + "ConstraintDescription" : "must contain only alphanumeric characters." + }, + + "DBAllocatedStorage": { + "Default": "5", + "Description" : "The size of the database (Gb)", + "Type": "Number", + "MinValue": "5", + "MaxValue": "1024", + "ConstraintDescription" : "must be between 5 and 1024Gb." + }, + + "DBInstanceClass": { + "Description" : "The database instance type", + "Type": "String", + "Default": "db.m1.small", + "AllowedValues" : [ "db.t1.micro", "db.m1.small", "db.m1.medium", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge", "db.m3.medium", "db.m3.large", "db.m3.xlarge", "db.m3.2xlarge", "db.r3.large", "db.r3.xlarge", "db.r3.2xlarge", "db.r3.4xlarge", "db.r3.8xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge", "db.cr1.8xlarge"] +, + "ConstraintDescription" : "must select a valid database instance type." + }, + + "EC2SecurityGroup": { + "Description" : "The EC2 security group that contains instances that need access to the database", + "Default": "default", + "Type": "String", + "AllowedPattern" : "[a-zA-Z0-9\\-]+", + "ConstraintDescription" : "must be a valid security group name." + }, + + "MultiAZ" : { + "Description" : "Multi-AZ master database", + "Type" : "String", + "Default" : "false", + "AllowedValues" : [ "true", "false" ], + "ConstraintDescription" : "must be true or false." + } + }, + + "Conditions" : { + "Is-EC2-VPC" : { "Fn::Or" : [ {"Fn::Equals" : [{"Ref" : "AWS::Region"}, "eu-central-1" ]}, + {"Fn::Equals" : [{"Ref" : "AWS::Region"}, "cn-north-1" ]}]}, + "Is-EC2-Classic" : { "Fn::Not" : [{ "Condition" : "Is-EC2-VPC"}]} + }, + + "Resources" : { + "DBParameterGroup": { + "Type": "AWS::RDS::DBParameterGroup", + "Properties" : { + "Description": "DB Parameter Goup", + "Family" : "MySQL5.1", + "Parameters": { + "BACKLOG_QUEUE_LIMIT": "2048" + } + } + }, + + "DBEC2SecurityGroup": { + "Type": "AWS::EC2::SecurityGroup", + "Condition" : "Is-EC2-VPC", + "Properties" : { + "GroupDescription": "Open database for access", + "SecurityGroupIngress" : [{ + "IpProtocol" : "tcp", + "FromPort" : "3306", + "ToPort" : "3306", + "SourceSecurityGroupName" : { "Ref" : "EC2SecurityGroup" } + }] + } + }, + + "DBSecurityGroup": { + "Type": "AWS::RDS::DBSecurityGroup", + "Condition" : "Is-EC2-Classic", + "Properties": { + "DBSecurityGroupIngress": [{ + "EC2SecurityGroupName": { "Ref": "EC2SecurityGroup" } + }], + "GroupDescription": "database access" + } + }, + + "my_vpc": { + "Type" : "AWS::EC2::VPC", + "Properties" : { + "CidrBlock" : "10.0.0.0/16", + } + }, + + "EC2Subnet": { + "Type" : "AWS::EC2::Subnet", + "Condition" : "Is-EC2-VPC", + "Properties" : { + "AvailabilityZone" : "eu-central-1a", + "CidrBlock" : "10.0.1.0/24", + "VpcId" : { "Ref" : "my_vpc" } + } + }, + + "DBSubnet": { + "Type": "AWS::RDS::DBSubnetGroup", + "Condition" : "Is-EC2-VPC", + "Properties": { + "DBSubnetGroupDescription": "my db subnet group", + "SubnetIds" : [ { "Ref": "EC2Subnet" } ], + } + }, + + "MasterDB" : { + "Type" : "AWS::RDS::DBInstance", + "Properties" : { + "DBInstanceIdentifier": { "Ref": "DBInstanceIdentifier" }, + "DBName" : { "Ref" : "DBName" }, + "AllocatedStorage" : { "Ref" : "DBAllocatedStorage" }, + "DBInstanceClass" : { "Ref" : "DBInstanceClass" }, + "Engine" : "MySQL", + "DBSubnetGroupName": {"Fn::If": ["Is-EC2-VPC", { "Ref": "DBSubnet" }, { "Ref": "AWS::NoValue" }]}, + "MasterUsername" : { "Ref" : "DBUser" }, + "MasterUserPassword" : { "Ref" : "DBPassword" }, + "MultiAZ" : { "Ref" : "MultiAZ" }, + "Tags" : [{ "Key" : "Name", "Value" : "Master Database" }], + "VPCSecurityGroups": { "Fn::If" : [ "Is-EC2-VPC", [ { "Fn::GetAtt": [ "DBEC2SecurityGroup", "GroupId" ] } ], { "Ref" : "AWS::NoValue"}]}, + "DBSecurityGroups": { "Fn::If" : [ "Is-EC2-Classic", [ { "Ref": "DBSecurityGroup" } ], { "Ref" : "AWS::NoValue"}]} + }, + "DeletionPolicy" : "Snapshot" + }, + + "ReplicaDB" : { + "Type" : "AWS::RDS::DBInstance", + "Properties" : { + "SourceDBInstanceIdentifier" : { "Ref" : "MasterDB" }, + "DBInstanceClass" : { "Ref" : "DBInstanceClass" }, + "Tags" : [{ "Key" : "Name", "Value" : "Read Replica Database" }] + } + } + }, + + "Outputs" : { + "EC2Platform" : { + "Description" : "Platform in which this stack is deployed", + "Value" : { "Fn::If" : [ "Is-EC2-VPC", "EC2-VPC", "EC2-Classic" ]} + }, + + "MasterJDBCConnectionString": { + "Description" : "JDBC connection string for the master database", + "Value" : { "Fn::Join": [ "", [ "jdbc:mysql://", + { "Fn::GetAtt": [ "MasterDB", "Endpoint.Address" ] }, + ":", + { "Fn::GetAtt": [ "MasterDB", "Endpoint.Port" ] }, + "/", + { "Ref": "DBName" }]]} + }, + "ReplicaJDBCConnectionString": { + "Description" : "JDBC connection string for the replica database", + "Value" : { "Fn::Join": [ "", [ "jdbc:mysql://", + { "Fn::GetAtt": [ "ReplicaDB", "Endpoint.Address" ] }, + ":", + { "Fn::GetAtt": [ "ReplicaDB", "Endpoint.Port" ] }, + "/", + { "Ref": "DBName" }]]} + } + } +} diff --git a/tests/test_cloudformation/fixtures/rds_mysql_with_read_replica.py b/tests/test_cloudformation/fixtures/rds_mysql_with_read_replica.py index b743f46f4..3e5efa04a 100644 --- a/tests/test_cloudformation/fixtures/rds_mysql_with_read_replica.py +++ b/tests/test_cloudformation/fixtures/rds_mysql_with_read_replica.py @@ -82,7 +82,6 @@ template = { }, "Resources" : { - "DBEC2SecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Condition" : "Is-EC2-VPC", @@ -101,9 +100,9 @@ template = { "Type": "AWS::RDS::DBSecurityGroup", "Condition" : "Is-EC2-Classic", "Properties": { - "DBSecurityGroupIngress": { + "DBSecurityGroupIngress": [{ "EC2SecurityGroupName": { "Ref": "EC2SecurityGroup" } - }, + }], "GroupDescription": "database access" } }, @@ -188,4 +187,4 @@ template = { { "Ref": "DBName" }]]} } } -} \ No newline at end of file +} diff --git a/tests/test_cloudformation/test_cloudformation_stack_integration.py b/tests/test_cloudformation/test_cloudformation_stack_integration.py index 0fb74bef9..ff2cad29e 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_integration.py +++ b/tests/test_cloudformation/test_cloudformation_stack_integration.py @@ -27,6 +27,7 @@ from moto import ( mock_kms, mock_lambda, mock_rds, + mock_rds2, mock_redshift, mock_route53, mock_sns, @@ -36,6 +37,7 @@ from moto import ( from .fixtures import ( ec2_classic_eip, fn_join, + rds_mysql_with_db_parameter_group, rds_mysql_with_read_replica, redshift, route53_ec2_instance_with_public_ip, @@ -693,6 +695,44 @@ def test_vpc_single_instance_in_subnet(): eip_resource = [resource for resource in resources if resource.resource_type == 'AWS::EC2::EIP'][0] eip_resource.physical_resource_id.should.equal(eip.allocation_id) +@mock_cloudformation() +@mock_ec2() +@mock_rds2() +def test_rds_db_parameter_groups(): + ec2_conn = boto.ec2.connect_to_region("us-west-1") + ec2_conn.create_security_group('application', 'Our Application Group') + + template_json = json.dumps(rds_mysql_with_db_parameter_group.template) + conn = boto.cloudformation.connect_to_region("us-west-1") + conn.create_stack( + "test_stack", + template_body=template_json, + parameters=[ + ("DBInstanceIdentifier", "master_db"), + ("DBName", "my_db"), + ("DBUser", "my_user"), + ("DBPassword", "my_password"), + ("DBAllocatedStorage", "20"), + ("DBInstanceClass", "db.m1.medium"), + ("EC2SecurityGroup", "application"), + ("MultiAZ", "true"), + ], + ) + + rds_conn = boto3.client('rds', region_name="us-west-1") + + db_parameter_groups = rds_conn.describe_db_parameter_groups() + len(db_parameter_groups['DBParameterGroups']).should.equal(1) + db_parameter_group_name = db_parameter_groups['DBParameterGroups'][0]['DBParameterGroupName'] + + found_cloudformation_set_parameter = False + for db_parameter in rds_conn.describe_db_parameters(DBParameterGroupName=db_parameter_group_name)['Parameters']: + if db_parameter['ParameterName'] == 'BACKLOG_QUEUE_LIMIT' and db_parameter['ParameterValue'] == '2048': + found_cloudformation_set_parameter = True + + found_cloudformation_set_parameter.should.equal(True) + + @mock_cloudformation() @mock_ec2() diff --git a/tests/test_rds/test_rds.py b/tests/test_rds/test_rds.py index df8ede179..6078b5f6b 100644 --- a/tests/test_rds/test_rds.py +++ b/tests/test_rds/test_rds.py @@ -238,6 +238,32 @@ def test_create_database_replica(): primary = conn.get_all_dbinstances("db-master-1")[0] list(primary.read_replica_dbinstance_identifiers).should.have.length_of(0) +@disable_on_py3() +@mock_rds +def test_create_cross_region_database_replica(): + west_1_conn = boto.rds.connect_to_region("us-west-1") + west_2_conn = boto.rds.connect_to_region("us-west-2") + + primary = west_1_conn.create_dbinstance("db-master-1", 10, 'db.m1.small', 'root', 'hunter2') + + primary_arn = "arn:aws:rds:us-west-1:1234567890:db:db-master-1" + replica = west_2_conn.create_dbinstance_read_replica( + "replica", + primary_arn, + "db.m1.small", + ) + + primary = west_1_conn.get_all_dbinstances("db-master-1")[0] + primary.read_replica_dbinstance_identifiers[0].should.equal("replica") + + replica = west_2_conn.get_all_dbinstances("replica")[0] + replica.instance_class.should.equal("db.m1.small") + + west_2_conn.delete_dbinstance("replica") + + primary = west_1_conn.get_all_dbinstances("db-master-1")[0] + list(primary.read_replica_dbinstance_identifiers).should.have.length_of(0) + @disable_on_py3() @mock_rds diff --git a/tests/test_rds2/test_rds2.py b/tests/test_rds2/test_rds2.py index 7ca48f0aa..4e1c2b73c 100644 --- a/tests/test_rds2/test_rds2.py +++ b/tests/test_rds2/test_rds2.py @@ -2,479 +2,648 @@ from __future__ import unicode_literals import boto.rds2 import boto.vpc -from boto.exception import BotoServerError +from botocore.exceptions import ClientError, ParamValidationError +import boto3 import sure # noqa -from moto import mock_ec2, mock_rds2 +from moto import mock_ec2, mock_kms, mock_rds2 from tests.helpers import disable_on_py3 @disable_on_py3() @mock_rds2 def test_create_database(): - conn = boto.rds2.connect_to_region("us-west-2") - database = conn.create_db_instance(db_instance_identifier='db-master-1', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"]) - database['CreateDBInstanceResponse']['CreateDBInstanceResult']['DBInstance']['DBInstanceStatus'].should.equal('available') - database['CreateDBInstanceResponse']['CreateDBInstanceResult']['DBInstance']['DBInstanceIdentifier'].should.equal("db-master-1") - database['CreateDBInstanceResponse']['CreateDBInstanceResult']['DBInstance']['AllocatedStorage'].should.equal('10') - database['CreateDBInstanceResponse']['CreateDBInstanceResult']['DBInstance']['DBInstanceClass'].should.equal("db.m1.small") - database['CreateDBInstanceResponse']['CreateDBInstanceResult']['DBInstance']['MasterUsername'].should.equal("root") - database['CreateDBInstanceResponse']['CreateDBInstanceResult']['DBInstance']['DBSecurityGroups'][0]['DBSecurityGroup']['DBSecurityGroupName'].should.equal('my_sg') + conn = boto3.client('rds', region_name='us-west-2') + database = conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + Engine='postgres', + DBInstanceClass='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=["my_sg"]) + database['DBInstance']['DBInstanceStatus'].should.equal('available') + database['DBInstance']['DBInstanceIdentifier'].should.equal("db-master-1") + database['DBInstance']['AllocatedStorage'].should.equal(10) + database['DBInstance']['DBInstanceClass'].should.equal("db.m1.small") + database['DBInstance']['MasterUsername'].should.equal("root") + database['DBInstance']['DBSecurityGroups'][0]['DBSecurityGroupName'].should.equal('my_sg') @disable_on_py3() @mock_rds2 def test_get_databases(): - conn = boto.rds2.connect_to_region("us-west-2") + conn = boto3.client('rds', region_name='us-west-2') instances = conn.describe_db_instances() - list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances']).should.have.length_of(0) + list(instances['DBInstances']).should.have.length_of(0) - conn.create_db_instance(db_instance_identifier='db-master-1', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"]) - conn.create_db_instance(db_instance_identifier='db-master-2', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"]) + conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=['my_sg']) + conn.create_db_instance(DBInstanceIdentifier='db-master-2', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=['my_sg']) instances = conn.describe_db_instances() - list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances']).should.have.length_of(2) + list(instances['DBInstances']).should.have.length_of(2) - instances = conn.describe_db_instances("db-master-1") - list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances']).should.have.length_of(1) - instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['DBInstanceIdentifier'].should.equal("db-master-1") + instances = conn.describe_db_instances(DBInstanceIdentifier="db-master-1") + list(instances['DBInstances']).should.have.length_of(1) + instances['DBInstances'][0]['DBInstanceIdentifier'].should.equal("db-master-1") @disable_on_py3() @mock_rds2 def test_describe_non_existant_database(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.describe_db_instances.when.called_with("not-a-db").should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.describe_db_instances.when.called_with(DBInstanceIdentifier="not-a-db").should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_modify_db_instance(): - conn = boto.rds2.connect_to_region("us-west-2") - database = conn.create_db_instance(db_instance_identifier='db-master-1', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"]) - instances = conn.describe_db_instances('db-master-1') - instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['AllocatedStorage'].should.equal('10') - conn.modify_db_instance(db_instance_identifier='db-master-1', allocated_storage=20, apply_immediately=True) - instances = conn.describe_db_instances('db-master-1') - instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['AllocatedStorage'].should.equal('20') + conn = boto3.client('rds', region_name='us-west-2') + database = conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=['my_sg']) + instances = conn.describe_db_instances(DBInstanceIdentifier='db-master-1') + instances['DBInstances'][0]['AllocatedStorage'].should.equal(10) + conn.modify_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=20, + ApplyImmediately=True) + instances = conn.describe_db_instances(DBInstanceIdentifier='db-master-1') + instances['DBInstances'][0]['AllocatedStorage'].should.equal(20) @disable_on_py3() @mock_rds2 def test_modify_non_existant_database(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.modify_db_instance.when.called_with(db_instance_identifier='not-a-db', - allocated_storage=20, - apply_immediately=True).should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.modify_db_instance.when.called_with(DBInstanceIdentifier='not-a-db', + AllocatedStorage=20, + ApplyImmediately=True).should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_reboot_db_instance(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_db_instance(db_instance_identifier='db-master-1', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"]) - database = conn.reboot_db_instance('db-master-1') - database['RebootDBInstanceResponse']['RebootDBInstanceResult']['DBInstance']['DBInstanceIdentifier'].should.equal("db-master-1") + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=['my_sg']) + database = conn.reboot_db_instance(DBInstanceIdentifier='db-master-1') + database['DBInstance']['DBInstanceIdentifier'].should.equal("db-master-1") @disable_on_py3() @mock_rds2 def test_reboot_non_existant_database(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.reboot_db_instance.when.called_with("not-a-db").should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.reboot_db_instance.when.called_with(DBInstanceIdentifier="not-a-db").should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_delete_database(): - conn = boto.rds2.connect_to_region("us-west-2") + conn = boto3.client('rds', region_name='us-west-2') instances = conn.describe_db_instances() - list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances']).should.have.length_of(0) - conn.create_db_instance(db_instance_identifier='db-master-1', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"]) + list(instances['DBInstances']).should.have.length_of(0) + conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=['my_sg']) instances = conn.describe_db_instances() - list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances']).should.have.length_of(1) + list(instances['DBInstances']).should.have.length_of(1) - conn.delete_db_instance("db-master-1") + conn.delete_db_instance(DBInstanceIdentifier="db-master-1") instances = conn.describe_db_instances() - list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances']).should.have.length_of(0) + list(instances['DBInstances']).should.have.length_of(0) @disable_on_py3() @mock_rds2 def test_delete_non_existant_database(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.delete_db_instance.when.called_with("not-a-db").should.throw(BotoServerError) + conn = boto3.client('rds2', region_name="us-west-2") + conn.delete_db_instance.when.called_with(DBInstanceIdentifier="not-a-db").should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_create_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - option_group = conn.create_option_group('test', 'mysql', '5.6', 'test option group') - option_group['CreateOptionGroupResponse']['CreateOptionGroupResult']['OptionGroup']['OptionGroupName'].should.equal('test') - option_group['CreateOptionGroupResponse']['CreateOptionGroupResult']['OptionGroup']['EngineName'].should.equal('mysql') - option_group['CreateOptionGroupResponse']['CreateOptionGroupResult']['OptionGroup']['OptionGroupDescription'].should.equal('test option group') - option_group['CreateOptionGroupResponse']['CreateOptionGroupResult']['OptionGroup']['MajorEngineVersion'].should.equal('5.6') + conn = boto3.client('rds', region_name='us-west-2') + option_group = conn.create_option_group(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='5.6', + OptionGroupDescription='test option group') + option_group['OptionGroup']['OptionGroupName'].should.equal('test') + option_group['OptionGroup']['EngineName'].should.equal('mysql') + option_group['OptionGroup']['OptionGroupDescription'].should.equal('test option group') + option_group['OptionGroup']['MajorEngineVersion'].should.equal('5.6') @disable_on_py3() @mock_rds2 def test_create_option_group_bad_engine_name(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group.when.called_with('test', 'invalid_engine', '5.6', 'test invalid engine').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group.when.called_with(OptionGroupName='test', + EngineName='invalid_engine', + MajorEngineVersion='5.6', + OptionGroupDescription='test invalid engine').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_create_option_group_bad_engine_major_version(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group.when.called_with('test', 'mysql', '6.6.6', 'test invalid engine version').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group.when.called_with(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='6.6.6', + OptionGroupDescription='test invalid engine version').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_create_option_group_empty_description(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group.when.called_with('test', 'mysql', '5.6', '').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group.when.called_with(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='5.6', + OptionGroupDescription='').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_create_option_group_duplicate(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group('test', 'mysql', '5.6', 'test option group') - conn.create_option_group.when.called_with('test', 'mysql', '5.6', 'foo').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='5.6', + OptionGroupDescription='test option group') + conn.create_option_group.when.called_with(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='5.6', + OptionGroupDescription='test option group').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_describe_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group('test', 'mysql', '5.6', 'test option group') - option_groups = conn.describe_option_groups('test') - option_groups['DescribeOptionGroupsResponse']['DescribeOptionGroupsResult']['OptionGroupsList'][0]['OptionGroupName'].should.equal('test') + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='5.6', + OptionGroupDescription='test option group') + option_groups = conn.describe_option_groups(OptionGroupName='test') + option_groups['OptionGroupsList'][0]['OptionGroupName'].should.equal('test') @disable_on_py3() @mock_rds2 def test_describe_non_existant_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.describe_option_groups.when.called_with("not-a-option-group").should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.describe_option_groups.when.called_with(OptionGroupName="not-a-option-group").should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_delete_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group('test', 'mysql', '5.6', 'test option group') - option_groups = conn.describe_option_groups('test') - option_groups['DescribeOptionGroupsResponse']['DescribeOptionGroupsResult']['OptionGroupsList'][0]['OptionGroupName'].should.equal('test') - conn.delete_option_group('test') - conn.describe_option_groups.when.called_with('test').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='5.6', + OptionGroupDescription='test option group') + option_groups = conn.describe_option_groups(OptionGroupName='test') + option_groups['OptionGroupsList'][0]['OptionGroupName'].should.equal('test') + conn.delete_option_group(OptionGroupName='test') + conn.describe_option_groups.when.called_with(OptionGroupName='test').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_delete_non_existant_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.delete_option_group.when.called_with('non-existant').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.delete_option_group.when.called_with(OptionGroupName='non-existant').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_describe_option_group_options(): - conn = boto.rds2.connect_to_region("us-west-2") - option_group_options = conn.describe_option_group_options('sqlserver-ee') - len(option_group_options['DescribeOptionGroupOptionsResponse']['DescribeOptionGroupOptionsResult']['OptionGroupOptions']).should.equal(4) - option_group_options = conn.describe_option_group_options('sqlserver-ee', '11.00') - len(option_group_options['DescribeOptionGroupOptionsResponse']['DescribeOptionGroupOptionsResult']['OptionGroupOptions']).should.equal(2) - option_group_options = conn.describe_option_group_options('mysql', '5.6') - len(option_group_options['DescribeOptionGroupOptionsResponse']['DescribeOptionGroupOptionsResult']['OptionGroupOptions']).should.equal(1) - conn.describe_option_group_options.when.called_with('non-existent').should.throw(BotoServerError) - conn.describe_option_group_options.when.called_with('mysql', 'non-existent').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + option_group_options = conn.describe_option_group_options(EngineName='sqlserver-ee') + len(option_group_options['OptionGroupOptions']).should.equal(4) + option_group_options = conn.describe_option_group_options(EngineName='sqlserver-ee', MajorEngineVersion='11.00') + len(option_group_options['OptionGroupOptions']).should.equal(2) + option_group_options = conn.describe_option_group_options(EngineName='mysql', MajorEngineVersion='5.6') + len(option_group_options['OptionGroupOptions']).should.equal(1) + conn.describe_option_group_options.when.called_with(EngineName='non-existent').should.throw(ClientError) + conn.describe_option_group_options.when.called_with(EngineName='mysql', MajorEngineVersion='non-existent').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_modify_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group('test', 'mysql', '5.6', 'test option group') + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group(OptionGroupName='test', EngineName='mysql', MajorEngineVersion='5.6', OptionGroupDescription='test option group') # TODO: create option and validate before deleting. # if Someone can tell me how the hell to use this function # to add options to an option_group, I can finish coding this. - result = conn.modify_option_group('test', [], ['MEMCACHED'], True) - result['ModifyOptionGroupResponse']['ModifyOptionGroupResult']['EngineName'].should.equal('mysql') - result['ModifyOptionGroupResponse']['ModifyOptionGroupResult']['Options'].should.equal([]) - result['ModifyOptionGroupResponse']['ModifyOptionGroupResult']['OptionGroupName'].should.equal('test') + result = conn.modify_option_group(OptionGroupName='test', OptionsToInclude=[], OptionsToRemove=['MEMCACHED'], ApplyImmediately=True) + result['OptionGroup']['EngineName'].should.equal('mysql') + result['OptionGroup']['Options'].should.equal([]) + result['OptionGroup']['OptionGroupName'].should.equal('test') @disable_on_py3() @mock_rds2 def test_modify_option_group_no_options(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group('test', 'mysql', '5.6', 'test option group') - conn.modify_option_group.when.called_with('test').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group(OptionGroupName='test', EngineName='mysql', MajorEngineVersion='5.6', OptionGroupDescription='test option group') + conn.modify_option_group.when.called_with(OptionGroupName='test').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_modify_non_existant_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.modify_option_group.when.called_with('non-existant', [('OptionName', 'Port', 'DBSecurityGroupMemberships', 'VpcSecurityGroupMemberships', 'OptionSettings')]).should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.modify_option_group.when.called_with(OptionGroupName='non-existant', OptionsToInclude=[('OptionName', 'Port', 'DBSecurityGroupMemberships', 'VpcSecurityGroupMemberships', 'OptionSettings')]).should.throw(ParamValidationError) @disable_on_py3() @mock_rds2 def test_delete_non_existant_database(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.delete_db_instance.when.called_with("not-a-db").should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.delete_db_instance.when.called_with(DBInstanceIdentifier="not-a-db").should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_list_tags_invalid_arn(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.list_tags_for_resource.when.called_with('arn:aws:rds:bad-arn').should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.list_tags_for_resource.when.called_with(ResourceName='arn:aws:rds:bad-arn').should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_list_tags_db(): - conn = boto.rds2.connect_to_region("us-west-2") - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:db:foo') - result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList'].should.equal([]) - conn.create_db_instance(db_instance_identifier='db-with-tags', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"], - tags=[('foo', 'bar'), ('foo1', 'bar1')]) - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:db:db-with-tags') - result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList'].should.equal([{'Value': 'bar', - 'Key': 'foo'}, - {'Value': 'bar1', - 'Key': 'foo1'}]) + conn = boto3.client('rds', region_name='us-west-2') + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:db:foo') + result['TagList'].should.equal([]) + conn.create_db_instance(DBInstanceIdentifier='db-with-tags', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=['my_sg'], + Tags=[ + { + 'Key': 'foo', + 'Value': 'bar', + }, + { + 'Key': 'foo1', + 'Value': 'bar1', + }, + ]) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:db:db-with-tags') + result['TagList'].should.equal([{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}]) @disable_on_py3() @mock_rds2 def test_add_tags_db(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_db_instance(db_instance_identifier='db-without-tags', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"], - tags=[('foo', 'bar'), ('foo1', 'bar1')]) - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:db:db-without-tags') - list(result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList']).should.have.length_of(2) - conn.add_tags_to_resource('arn:aws:rds:us-west-2:1234567890:db:db-without-tags', - [('foo', 'fish'), ('foo2', 'bar2')]) - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:db:db-without-tags') - list(result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList']).should.have.length_of(3) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_instance(DBInstanceIdentifier='db-without-tags', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=['my_sg'], + Tags=[ + { + 'Key': 'foo', + 'Value': 'bar', + }, + { + 'Key': 'foo1', + 'Value': 'bar1', + }, + ]) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:db:db-without-tags') + list(result['TagList']).should.have.length_of(2) + conn.add_tags_to_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:db:db-without-tags', + Tags=[ + { + 'Key': 'foo', + 'Value': 'fish', + }, + { + 'Key': 'foo2', + 'Value': 'bar2', + }, + ]) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:db:db-without-tags') + list(result['TagList']).should.have.length_of(3) @disable_on_py3() @mock_rds2 def test_remove_tags_db(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_db_instance(db_instance_identifier='db-with-tags', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"], - tags=[('foo', 'bar'), ('foo1', 'bar1')]) - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:db:db-with-tags') - len(result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList']).should.equal(2) - conn.remove_tags_from_resource('arn:aws:rds:us-west-2:1234567890:db:db-with-tags', ['foo']) - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:db:db-with-tags') - len(result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList']).should.equal(1) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_instance(DBInstanceIdentifier='db-with-tags', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=['my_sg'], + Tags=[ + { + 'Key': 'foo', + 'Value': 'bar', + }, + { + 'Key': 'foo1', + 'Value': 'bar1', + }, + ]) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:db:db-with-tags') + list(result['TagList']).should.have.length_of(2) + conn.remove_tags_from_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:db:db-with-tags', TagKeys=['foo']) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:db:db-with-tags') + len(result['TagList']).should.equal(1) @disable_on_py3() @mock_rds2 def test_add_tags_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group('test', 'mysql', '5.6', 'test option group') - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:og:test') - list(result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList']).should.have.length_of(0) - conn.add_tags_to_resource('arn:aws:rds:us-west-2:1234567890:og:test', - [('foo', 'fish'), ('foo2', 'bar2')]) - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:og:test') - list(result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList']).should.have.length_of(2) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='5.6', + OptionGroupDescription='test option group') + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:og:test') + list(result['TagList']).should.have.length_of(0) + conn.add_tags_to_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:og:test', + Tags=[ + { + 'Key': 'foo', + 'Value': 'fish', + }, + { + 'Key': 'foo2', + 'Value': 'bar2', + }]) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:og:test') + list(result['TagList']).should.have.length_of(2) @disable_on_py3() @mock_rds2 def test_remove_tags_option_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_option_group('test', 'mysql', '5.6', 'test option group') - conn.add_tags_to_resource('arn:aws:rds:us-west-2:1234567890:og:test', - [('foo', 'fish'), ('foo2', 'bar2')]) - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:og:test') - list(result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList']).should.have.length_of(2) - conn.remove_tags_from_resource('arn:aws:rds:us-west-2:1234567890:og:test', - ['foo']) - result = conn.list_tags_for_resource('arn:aws:rds:us-west-2:1234567890:og:test') - list(result['ListTagsForResourceResponse']['ListTagsForResourceResult']['TagList']).should.have.length_of(1) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_option_group(OptionGroupName='test', + EngineName='mysql', + MajorEngineVersion='5.6', + OptionGroupDescription='test option group') + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:og:test') + conn.add_tags_to_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:og:test', + Tags=[ + { + 'Key': 'foo', + 'Value': 'fish', + }, + { + 'Key': 'foo2', + 'Value': 'bar2', + }]) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:og:test') + list(result['TagList']).should.have.length_of(2) + conn.remove_tags_from_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:og:test', + TagKeys=['foo']) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:og:test') + list(result['TagList']).should.have.length_of(1) @disable_on_py3() @mock_rds2 def test_create_database_security_group(): - conn = boto.rds2.connect_to_region("us-west-2") + conn = boto3.client('rds', region_name='us-west-2') - result = conn.create_db_security_group('db_sg', 'DB Security Group') - result['CreateDBSecurityGroupResponse']['CreateDBSecurityGroupResult']['DBSecurityGroup']['DBSecurityGroupName'].should.equal("db_sg") - result['CreateDBSecurityGroupResponse']['CreateDBSecurityGroupResult']['DBSecurityGroup']['DBSecurityGroupDescription'].should.equal("DB Security Group") - result['CreateDBSecurityGroupResponse']['CreateDBSecurityGroupResult']['DBSecurityGroup']['IPRanges'].should.equal([]) + result = conn.create_db_security_group(DBSecurityGroupName='db_sg', DBSecurityGroupDescription='DB Security Group') + result['DBSecurityGroup']['DBSecurityGroupName'].should.equal("db_sg") + result['DBSecurityGroup']['DBSecurityGroupDescription'].should.equal("DB Security Group") + result['DBSecurityGroup']['IPRanges'].should.equal([]) @disable_on_py3() @mock_rds2 def test_get_security_groups(): - conn = boto.rds2.connect_to_region("us-west-2") + conn = boto3.client('rds', region_name='us-west-2') result = conn.describe_db_security_groups() - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'].should.have.length_of(0) + result['DBSecurityGroups'].should.have.length_of(0) - conn.create_db_security_group('db_sg1', 'DB Security Group') - conn.create_db_security_group('db_sg2', 'DB Security Group') + conn.create_db_security_group(DBSecurityGroupName='db_sg1', DBSecurityGroupDescription='DB Security Group') + conn.create_db_security_group(DBSecurityGroupName='db_sg2', DBSecurityGroupDescription='DB Security Group') result = conn.describe_db_security_groups() - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'].should.have.length_of(2) + result['DBSecurityGroups'].should.have.length_of(2) - result = conn.describe_db_security_groups("db_sg1") - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'].should.have.length_of(1) - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'][0]['DBSecurityGroupName'].should.equal("db_sg1") + result = conn.describe_db_security_groups(DBSecurityGroupName="db_sg1") + result['DBSecurityGroups'].should.have.length_of(1) + result['DBSecurityGroups'][0]['DBSecurityGroupName'].should.equal("db_sg1") @disable_on_py3() @mock_rds2 def test_get_non_existant_security_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.describe_db_security_groups.when.called_with("not-a-sg").should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.describe_db_security_groups.when.called_with(DBSecurityGroupName="not-a-sg").should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_delete_database_security_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_db_security_group('db_sg', 'DB Security Group') + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_security_group(DBSecurityGroupName='db_sg', DBSecurityGroupDescription='DB Security Group') result = conn.describe_db_security_groups() - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'].should.have.length_of(1) + result['DBSecurityGroups'].should.have.length_of(1) - conn.delete_db_security_group("db_sg") + conn.delete_db_security_group(DBSecurityGroupName="db_sg") result = conn.describe_db_security_groups() - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'].should.have.length_of(0) + result['DBSecurityGroups'].should.have.length_of(0) @disable_on_py3() @mock_rds2 def test_delete_non_existant_security_group(): - conn = boto.rds2.connect_to_region("us-west-2") - conn.delete_db_security_group.when.called_with("not-a-db").should.throw(BotoServerError) + conn = boto3.client('rds', region_name='us-west-2') + conn.delete_db_security_group.when.called_with(DBSecurityGroupName="not-a-db").should.throw(ClientError) @disable_on_py3() @mock_rds2 def test_security_group_authorize(): - conn = boto.rds2.connect_to_region("us-west-2") - security_group = conn.create_db_security_group('db_sg', 'DB Security Group') - security_group['CreateDBSecurityGroupResponse']['CreateDBSecurityGroupResult']['DBSecurityGroup']['IPRanges'].should.equal([]) + conn = boto3.client('rds', region_name='us-west-2') + security_group = conn.create_db_security_group(DBSecurityGroupName='db_sg', + DBSecurityGroupDescription='DB Security Group') + security_group['DBSecurityGroup']['IPRanges'].should.equal([]) - conn.authorize_db_security_group_ingress(db_security_group_name='db_sg', - cidrip='10.3.2.45/32') + conn.authorize_db_security_group_ingress(DBSecurityGroupName='db_sg', + CIDRIP='10.3.2.45/32') - result = conn.describe_db_security_groups("db_sg") - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'][0]['IPRanges'].should.have.length_of(1) - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'][0]['IPRanges'].should.equal(['10.3.2.45/32']) + result = conn.describe_db_security_groups(DBSecurityGroupName="db_sg") + result['DBSecurityGroups'][0]['IPRanges'].should.have.length_of(1) + result['DBSecurityGroups'][0]['IPRanges'].should.equal([{'Status': 'authorized', 'CIDRIP': '10.3.2.45/32'}]) - conn.authorize_db_security_group_ingress(db_security_group_name='db_sg', - cidrip='10.3.2.46/32') - result = conn.describe_db_security_groups("db_sg") - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'][0]['IPRanges'].should.have.length_of(2) - result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'][0]['IPRanges'].should.equal(['10.3.2.45/32', '10.3.2.46/32']) + conn.authorize_db_security_group_ingress(DBSecurityGroupName='db_sg', + CIDRIP='10.3.2.46/32') + result = conn.describe_db_security_groups(DBSecurityGroupName="db_sg") + result['DBSecurityGroups'][0]['IPRanges'].should.have.length_of(2) + result['DBSecurityGroups'][0]['IPRanges'].should.equal([ + {'Status': 'authorized', 'CIDRIP': '10.3.2.45/32'}, + {'Status': 'authorized', 'CIDRIP': '10.3.2.46/32'}, + ]) @disable_on_py3() @mock_rds2 def test_add_security_group_to_database(): - conn = boto.rds2.connect_to_region("us-west-2") + conn = boto3.client('rds', region_name='us-west-2') + + conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + DBInstanceClass='postgres', + Engine='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234) - conn.create_db_instance(db_instance_identifier='db-master-1', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2') result = conn.describe_db_instances() - result['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['DBSecurityGroups'].should.equal([]) - conn.create_db_security_group('db_sg', 'DB Security Group') - conn.modify_db_instance(db_instance_identifier='db-master-1', - db_security_groups=['db_sg']) + result['DBInstances'][0]['DBSecurityGroups'].should.equal([]) + conn.create_db_security_group(DBSecurityGroupName='db_sg', + DBSecurityGroupDescription='DB Security Group') + conn.modify_db_instance(DBInstanceIdentifier='db-master-1', + DBSecurityGroups=['db_sg']) result = conn.describe_db_instances() - result['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['DBSecurityGroups'][0]['DBSecurityGroup']['DBSecurityGroupName'].should.equal('db_sg') + result['DBInstances'][0]['DBSecurityGroups'][0]['DBSecurityGroupName'].should.equal('db_sg') + + +@disable_on_py3() +@mock_rds2 +def test_list_tags_security_group(): + conn = boto3.client('rds', region_name='us-west-2') + result = conn.describe_db_subnet_groups() + result['DBSubnetGroups'].should.have.length_of(0) + + security_group = conn.create_db_security_group(DBSecurityGroupName="db_sg", + DBSecurityGroupDescription='DB Security Group', + Tags=[{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}])['DBSecurityGroup']['DBSecurityGroupName'] + resource = 'arn:aws:rds:us-west-2:1234567890:secgrp:{0}'.format(security_group) + result = conn.list_tags_for_resource(ResourceName=resource) + result['TagList'].should.equal([{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}]) + + +@disable_on_py3() +@mock_rds2 +def test_add_tags_security_group(): + conn = boto3.client('rds', region_name='us-west-2') + result = conn.describe_db_subnet_groups() + result['DBSubnetGroups'].should.have.length_of(0) + + security_group = conn.create_db_security_group(DBSecurityGroupName="db_sg", + DBSecurityGroupDescription='DB Security Group')['DBSecurityGroup']['DBSecurityGroupName'] + + resource = 'arn:aws:rds:us-west-2:1234567890:secgrp:{0}'.format(security_group) + conn.add_tags_to_resource(ResourceName=resource, + Tags=[{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}]) + + result = conn.list_tags_for_resource(ResourceName=resource) + result['TagList'].should.equal([{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}]) + +@disable_on_py3() +@mock_rds2 +def test_remove_tags_security_group(): + conn = boto3.client('rds', region_name='us-west-2') + result = conn.describe_db_subnet_groups() + result['DBSubnetGroups'].should.have.length_of(0) + + security_group = conn.create_db_security_group(DBSecurityGroupName="db_sg", + DBSecurityGroupDescription='DB Security Group', + Tags=[{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}])['DBSecurityGroup']['DBSecurityGroupName'] + + resource = 'arn:aws:rds:us-west-2:1234567890:secgrp:{0}'.format(security_group) + conn.remove_tags_from_resource(ResourceName=resource, TagKeys=['foo']) + + result = conn.list_tags_for_resource(ResourceName=resource) + result['TagList'].should.equal([{'Value': 'bar1', 'Key': 'foo1'}]) @disable_on_py3() @mock_ec2 @mock_rds2 def test_create_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") + vpc_conn = boto3.client('ec2', 'us-west-2') + vpc = vpc_conn.create_vpc(CidrBlock='10.0.0.0/16')['Vpc'] + subnet1 = vpc_conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.1.0.0/24')['Subnet'] + subnet2 = vpc_conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.1.0.0/26')['Subnet'] - subnet_ids = [subnet1.id, subnet2.id] - conn = boto.rds2.connect_to_region("us-west-2") - result = conn.create_db_subnet_group("db_subnet", "my db subnet", subnet_ids) - result['CreateDBSubnetGroupResponse']['CreateDBSubnetGroupResult']['DBSubnetGroup']['DBSubnetGroupName'].should.equal("db_subnet") - result['CreateDBSubnetGroupResponse']['CreateDBSubnetGroupResult']['DBSubnetGroup']['DBSubnetGroupDescription'].should.equal("my db subnet") - subnets = result['CreateDBSubnetGroupResponse']['CreateDBSubnetGroupResult']['DBSubnetGroup']['Subnets'] - subnet_group_ids = [subnets['Subnet'][0]['SubnetIdentifier'], subnets['Subnet'][1]['SubnetIdentifier']] + subnet_ids = [subnet1['SubnetId'], subnet2['SubnetId']] + conn = boto3.client('rds', region_name='us-west-2') + result = conn.create_db_subnet_group(DBSubnetGroupName='db_subnet', + DBSubnetGroupDescription='my db subnet', + SubnetIds=subnet_ids) + result['DBSubnetGroup']['DBSubnetGroupName'].should.equal("db_subnet") + result['DBSubnetGroup']['DBSubnetGroupDescription'].should.equal("my db subnet") + subnets = result['DBSubnetGroup']['Subnets'] + subnet_group_ids = [subnets[0]['SubnetIdentifier'], subnets[1]['SubnetIdentifier']] list(subnet_group_ids).should.equal(subnet_ids) @@ -482,96 +651,370 @@ def test_create_database_subnet_group(): @mock_ec2 @mock_rds2 def test_create_database_in_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") + vpc_conn = boto3.client('ec2', 'us-west-2') + vpc = vpc_conn.create_vpc(CidrBlock='10.0.0.0/16')['Vpc'] + subnet = vpc_conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.1.0.0/24')['Subnet'] - conn = boto.rds2.connect_to_region("us-west-2") - conn.create_db_subnet_group("db_subnet1", "my db subnet", [subnet.id]) - conn.create_db_instance(db_instance_identifier='db-master-1', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_subnet_group_name='db_subnet1') - result = conn.describe_db_instances("db-master-1") - result['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['DBSubnetGroup']['DBSubnetGroupName'].should.equal("db_subnet1") + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_subnet_group(DBSubnetGroupName='db_subnet1', + DBSubnetGroupDescription='my db subnet', + SubnetIds=[subnet['SubnetId']]) + conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + Engine='postgres', + DBInstanceClass='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSubnetGroupName='db_subnet1') + result = conn.describe_db_instances(DBInstanceIdentifier='db-master-1') + result['DBInstances'][0]['DBSubnetGroup']['DBSubnetGroupName'].should.equal('db_subnet1') @disable_on_py3() @mock_ec2 @mock_rds2 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") + vpc_conn = boto3.client('ec2', 'us-west-2') + vpc = vpc_conn.create_vpc(CidrBlock='10.0.0.0/16')['Vpc'] + subnet = vpc_conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.1.0.0/24')['Subnet'] - conn = boto.rds2.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]) + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_subnet_group(DBSubnetGroupName="db_subnet1", + DBSubnetGroupDescription='my db subnet', + SubnetIds=[subnet['SubnetId']]) + conn.create_db_subnet_group(DBSubnetGroupName='db_subnet2', + DBSubnetGroupDescription='my db subnet', + SubnetIds=[subnet['SubnetId']]) - resp = conn.describe_db_subnet_groups() - groups_resp = resp['DescribeDBSubnetGroupsResponse'] + resp = conn.describe_db_subnet_groups() + resp['DBSubnetGroups'].should.have.length_of(2) - subnet_groups = groups_resp['DescribeDBSubnetGroupsResult']['DBSubnetGroups'] - subnet_groups.should.have.length_of(2) + subnets = resp['DBSubnetGroups'][0]['Subnets'] + subnets.should.have.length_of(1) - subnets = groups_resp['DescribeDBSubnetGroupsResult']['DBSubnetGroups'][0]['DBSubnetGroup']['Subnets'] - subnets.should.have.length_of(1) + list(conn.describe_db_subnet_groups(DBSubnetGroupName="db_subnet1")['DBSubnetGroups']).should.have.length_of(1) - list(resp).should.have.length_of(1) - list(groups_resp).should.have.length_of(2) - list(conn.describe_db_subnet_groups("db_subnet1")).should.have.length_of(1) - - conn.describe_db_subnet_groups.when.called_with("not-a-subnet").should.throw(BotoServerError) + conn.describe_db_subnet_groups.when.called_with(DBSubnetGroupName="not-a-subnet").should.throw(ClientError) @disable_on_py3() @mock_ec2 @mock_rds2 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") + vpc_conn = boto3.client('ec2', 'us-west-2') + vpc = vpc_conn.create_vpc(CidrBlock='10.0.0.0/16')['Vpc'] + subnet = vpc_conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.1.0.0/24')['Subnet'] - conn = boto.rds2.connect_to_region("us-west-2") + conn = boto3.client('rds', region_name='us-west-2') result = conn.describe_db_subnet_groups() - result['DescribeDBSubnetGroupsResponse']['DescribeDBSubnetGroupsResult']['DBSubnetGroups'].should.have.length_of(0) + result['DBSubnetGroups'].should.have.length_of(0) - conn.create_db_subnet_group("db_subnet1", "my db subnet", [subnet.id]) + conn.create_db_subnet_group(DBSubnetGroupName="db_subnet1", + DBSubnetGroupDescription='my db subnet', + SubnetIds=[subnet['SubnetId']]) result = conn.describe_db_subnet_groups() - result['DescribeDBSubnetGroupsResponse']['DescribeDBSubnetGroupsResult']['DBSubnetGroups'].should.have.length_of(1) + result['DBSubnetGroups'].should.have.length_of(1) - conn.delete_db_subnet_group("db_subnet1") + conn.delete_db_subnet_group(DBSubnetGroupName="db_subnet1") result = conn.describe_db_subnet_groups() - result['DescribeDBSubnetGroupsResponse']['DescribeDBSubnetGroupsResult']['DBSubnetGroups'].should.have.length_of(0) + result['DBSubnetGroups'].should.have.length_of(0) - conn.delete_db_subnet_group.when.called_with("db_subnet1").should.throw(BotoServerError) + conn.delete_db_subnet_group.when.called_with(DBSubnetGroupName="db_subnet1").should.throw(ClientError) + + +@disable_on_py3() +@mock_ec2 +@mock_rds2 +def test_list_tags_database_subnet_group(): + vpc_conn = boto3.client('ec2', 'us-west-2') + vpc = vpc_conn.create_vpc(CidrBlock='10.0.0.0/16')['Vpc'] + subnet = vpc_conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.1.0.0/24')['Subnet'] + + conn = boto3.client('rds', region_name='us-west-2') + result = conn.describe_db_subnet_groups() + result['DBSubnetGroups'].should.have.length_of(0) + + subnet = conn.create_db_subnet_group(DBSubnetGroupName="db_subnet1", + DBSubnetGroupDescription='my db subnet', + SubnetIds=[subnet['SubnetId']], + Tags=[{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}])['DBSubnetGroup']['DBSubnetGroupName'] + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:subgrp:{0}'.format(subnet)) + result['TagList'].should.equal([{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}]) + +@disable_on_py3() +@mock_ec2 +@mock_rds2 +def test_add_tags_database_subnet_group(): + vpc_conn = boto3.client('ec2', 'us-west-2') + vpc = vpc_conn.create_vpc(CidrBlock='10.0.0.0/16')['Vpc'] + subnet = vpc_conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.1.0.0/24')['Subnet'] + + conn = boto3.client('rds', region_name='us-west-2') + result = conn.describe_db_subnet_groups() + result['DBSubnetGroups'].should.have.length_of(0) + + subnet = conn.create_db_subnet_group(DBSubnetGroupName="db_subnet1", + DBSubnetGroupDescription='my db subnet', + SubnetIds=[subnet['SubnetId']], + Tags=[])['DBSubnetGroup']['DBSubnetGroupName'] + resource = 'arn:aws:rds:us-west-2:1234567890:subgrp:{0}'.format(subnet) + + conn.add_tags_to_resource(ResourceName=resource, + Tags=[{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}]) + + result = conn.list_tags_for_resource(ResourceName=resource) + result['TagList'].should.equal([{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}]) + +@disable_on_py3() +@mock_ec2 +@mock_rds2 +def test_remove_tags_database_subnet_group(): + vpc_conn = boto3.client('ec2', 'us-west-2') + vpc = vpc_conn.create_vpc(CidrBlock='10.0.0.0/16')['Vpc'] + subnet = vpc_conn.create_subnet(VpcId=vpc['VpcId'], CidrBlock='10.1.0.0/24')['Subnet'] + + conn = boto3.client('rds', region_name='us-west-2') + result = conn.describe_db_subnet_groups() + result['DBSubnetGroups'].should.have.length_of(0) + + subnet = conn.create_db_subnet_group(DBSubnetGroupName="db_subnet1", + DBSubnetGroupDescription='my db subnet', + SubnetIds=[subnet['SubnetId']], + Tags=[{'Value': 'bar', + 'Key': 'foo'}, + {'Value': 'bar1', + 'Key': 'foo1'}])['DBSubnetGroup']['DBSubnetGroupName'] + resource = 'arn:aws:rds:us-west-2:1234567890:subgrp:{0}'.format(subnet) + + conn.remove_tags_from_resource(ResourceName=resource, TagKeys=['foo']) + + result = conn.list_tags_for_resource(ResourceName=resource) + result['TagList'].should.equal([{'Value': 'bar1', 'Key': 'foo1'}]) @disable_on_py3() @mock_rds2 def test_create_database_replica(): - conn = boto.rds2.connect_to_region("us-west-2") + conn = boto3.client('rds', region_name='us-west-2') - conn.create_db_instance(db_instance_identifier='db-master-1', - allocated_storage=10, - engine='postgres', - db_instance_class='db.m1.small', - master_username='root', - master_user_password='hunter2', - db_security_groups=["my_sg"]) + database = conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + Engine='postgres', + DBInstanceClass='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=["my_sg"]) - replica = conn.create_db_instance_read_replica("db-replica-1", "db-master-1", "db.m1.small") - replica['CreateDBInstanceReadReplicaResponse']['CreateDBInstanceReadReplicaResult']['DBInstance']['ReadReplicaSourceDBInstanceIdentifier'].should.equal('db-master-1') - replica['CreateDBInstanceReadReplicaResponse']['CreateDBInstanceReadReplicaResult']['DBInstance']['DBInstanceClass'].should.equal('db.m1.small') - replica['CreateDBInstanceReadReplicaResponse']['CreateDBInstanceReadReplicaResult']['DBInstance']['DBInstanceIdentifier'].should.equal('db-replica-1') + replica = conn.create_db_instance_read_replica(DBInstanceIdentifier="db-replica-1", + SourceDBInstanceIdentifier="db-master-1", + DBInstanceClass="db.m1.small") + replica['DBInstance']['ReadReplicaSourceDBInstanceIdentifier'].should.equal('db-master-1') + replica['DBInstance']['DBInstanceClass'].should.equal('db.m1.small') + replica['DBInstance']['DBInstanceIdentifier'].should.equal('db-replica-1') - master = conn.describe_db_instances("db-master-1") - master['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['ReadReplicaDBInstanceIdentifiers'].should.equal(['db-replica-1']) + master = conn.describe_db_instances(DBInstanceIdentifier="db-master-1") + master['DBInstances'][0]['ReadReplicaDBInstanceIdentifiers'].should.equal(['db-replica-1']) - conn.delete_db_instance("db-replica-1") + conn.delete_db_instance(DBInstanceIdentifier="db-replica-1", SkipFinalSnapshot=True) - master = conn.describe_db_instances("db-master-1") - master['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['ReadReplicaDBInstanceIdentifiers'].should.equal([]) + master = conn.describe_db_instances(DBInstanceIdentifier="db-master-1") + master['DBInstances'][0]['ReadReplicaDBInstanceIdentifiers'].should.equal([]) + +@disable_on_py3() +@mock_rds2 +@mock_kms +def test_create_database_with_encrypted_storage(): + kms_conn = boto3.client('kms', region_name='us-west-2') + key = kms_conn.create_key(Policy='my RDS encryption policy', + Description='RDS encryption key', + KeyUsage='ENCRYPT_DECRYPT') + + conn = boto3.client('rds', region_name='us-west-2') + database = conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + Engine='postgres', + DBInstanceClass='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234, + DBSecurityGroups=["my_sg"], + StorageEncrypted=True, + KmsKeyId=key['KeyMetadata']['KeyId']) + + database['DBInstance']['StorageEncrypted'].should.equal(True) + database['DBInstance']['KmsKeyId'].should.equal(key['KeyMetadata']['KeyId']) + +@disable_on_py3() +@mock_rds2 +def test_create_db_parameter_group(): + conn = boto3.client('rds', region_name='us-west-2') + db_parameter_group = conn.create_db_parameter_group(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group') + + db_parameter_group['DBParameterGroup']['DBParameterGroupName'].should.equal('test') + db_parameter_group['DBParameterGroup']['DBParameterGroupFamily'].should.equal('mysql5.6') + db_parameter_group['DBParameterGroup']['Description'].should.equal('test parameter group') + +@disable_on_py3() +@mock_rds2 +def test_create_db_instance_with_parameter_group(): + conn = boto3.client('rds', region_name='us-west-2') + db_parameter_group = conn.create_db_parameter_group(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group') + + database = conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + Engine='mysql', + DBInstanceClass='db.m1.small', + DBParameterGroupName='test', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234) + + len(database['DBInstance']['DBParameterGroups']).should.equal(1) + database['DBInstance']['DBParameterGroups'][0]['DBParameterGroupName'].should.equal('test') + database['DBInstance']['DBParameterGroups'][0]['ParameterApplyStatus'].should.equal('in-sync') + +@disable_on_py3() +@mock_rds2 +def test_modify_db_instance_with_parameter_group(): + conn = boto3.client('rds', region_name='us-west-2') + database = conn.create_db_instance(DBInstanceIdentifier='db-master-1', + AllocatedStorage=10, + Engine='mysql', + DBInstanceClass='db.m1.small', + MasterUsername='root', + MasterUserPassword='hunter2', + Port=1234) + + len(database['DBInstance']['DBParameterGroups']).should.equal(1) + database['DBInstance']['DBParameterGroups'][0]['DBParameterGroupName'].should.equal('default.mysql5.6') + database['DBInstance']['DBParameterGroups'][0]['ParameterApplyStatus'].should.equal('in-sync') + + db_parameter_group = conn.create_db_parameter_group(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group') + conn.modify_db_instance(DBInstanceIdentifier='db-master-1', + DBParameterGroupName='test', + ApplyImmediately=True) + + database = conn.describe_db_instances(DBInstanceIdentifier='db-master-1')['DBInstances'][0] + len(database['DBParameterGroups']).should.equal(1) + database['DBParameterGroups'][0]['DBParameterGroupName'].should.equal('test') + database['DBParameterGroups'][0]['ParameterApplyStatus'].should.equal('in-sync') + + +@disable_on_py3() +@mock_rds2 +def test_create_db_parameter_group_empty_description(): + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_parameter_group.when.called_with(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='').should.throw(ClientError) + + +@disable_on_py3() +@mock_rds2 +def test_create_db_parameter_group_duplicate(): + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_parameter_group(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group') + conn.create_db_parameter_group.when.called_with(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group').should.throw(ClientError) + + +@disable_on_py3() +@mock_rds2 +def test_describe_db_parameter_group(): + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_parameter_group(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group') + db_parameter_groups = conn.describe_db_parameter_groups(DBParameterGroupName='test') + db_parameter_groups['DBParameterGroups'][0]['DBParameterGroupName'].should.equal('test') + + +@disable_on_py3() +@mock_rds2 +def test_describe_non_existant_db_parameter_group(): + conn = boto3.client('rds', region_name='us-west-2') + db_parameter_groups = conn.describe_db_parameter_groups(DBParameterGroupName='test') + len(db_parameter_groups['DBParameterGroups']).should.equal(0) + + +@disable_on_py3() +@mock_rds2 +def test_delete_db_parameter_group(): + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_parameter_group(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group') + db_parameter_groups = conn.describe_db_parameter_groups(DBParameterGroupName='test') + db_parameter_groups['DBParameterGroups'][0]['DBParameterGroupName'].should.equal('test') + conn.delete_db_parameter_group(DBParameterGroupName='test') + db_parameter_groups = conn.describe_db_parameter_groups(DBParameterGroupName='test') + len(db_parameter_groups['DBParameterGroups']).should.equal(0) + +@disable_on_py3() +@mock_rds2 +def test_modify_db_parameter_group(): + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_parameter_group(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group') + + modify_result = conn.modify_db_parameter_group(DBParameterGroupName='test', + Parameters=[{ + 'ParameterName': 'foo', + 'ParameterValue': 'foo_val', + 'Description': 'test param', + 'ApplyMethod': 'immediate' + }] + ) + + modify_result['DBParameterGroupName'].should.equal('test') + + db_parameters = conn.describe_db_parameters(DBParameterGroupName='test') + db_parameters['Parameters'][0]['ParameterName'].should.equal('foo') + db_parameters['Parameters'][0]['ParameterValue'].should.equal('foo_val') + db_parameters['Parameters'][0]['Description'].should.equal('test param') + db_parameters['Parameters'][0]['ApplyMethod'].should.equal('immediate') + + +@disable_on_py3() +@mock_rds2 +def test_delete_non_existant_db_parameter_group(): + conn = boto3.client('rds', region_name='us-west-2') + conn.delete_db_parameter_group.when.called_with(DBParameterGroupName='non-existant').should.throw(ClientError) + +@disable_on_py3() +@mock_rds2 +def test_create_parameter_group_with_tags(): + conn = boto3.client('rds', region_name='us-west-2') + conn.create_db_parameter_group(DBParameterGroupName='test', + DBParameterGroupFamily='mysql5.6', + Description='test parameter group', + Tags=[{ + 'Key': 'foo', + 'Value': 'bar', + }]) + result = conn.list_tags_for_resource(ResourceName='arn:aws:rds:us-west-2:1234567890:pg:test') + result['TagList'].should.equal([{'Value': 'bar', 'Key': 'foo'}])