diff --git a/AUTHORS.md b/AUTHORS.md
index 8b086229e004..fa286f1a4e56 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -33,3 +33,5 @@ Moto is written by Steve Pulec with contributions from:
* [Peter](https://github.com/pvbouwel)
* [Tyler Sanders](https://github.com/tsanders)
* [Gary Dalton](https://github.com/gary-dalton)
+* [Chris Henry](https://github.com/chrishenry)
+* [Mike Fuller](https://github.com/mfulleratlassian)
diff --git a/README.md b/README.md
index dc582b608226..fb6b43593831 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,8 @@ It gets even better! Moto isn't just S3. Here's the status of the other AWS serv
|------------------------------------------------------------------------------|
| RDS | @mock_rds | core endpoints done |
|------------------------------------------------------------------------------|
+| RDS2 | @mock_rds2 | core endpoints done |
+|------------------------------------------------------------------------------|
| Route53 | @mock_route53 | core endpoints done |
|------------------------------------------------------------------------------|
| S3 | @mock_s3 | core endpoints done |
diff --git a/moto/__init__.py b/moto/__init__.py
index 965eaf4ee09c..0b0137d451bc 100644
--- a/moto/__init__.py
+++ b/moto/__init__.py
@@ -13,6 +13,7 @@
from .iam import mock_iam # flake8: noqa
from .kinesis import mock_kinesis # flake8: noqa
from .rds import mock_rds # flake8: noqa
+from .rds2 import mock_rds2 # flake8: noqa
from .redshift import mock_redshift # flake8: noqa
from .s3 import mock_s3 # flake8: noqa
from .s3bucket_path import mock_s3bucket_path # flake8: noqa
diff --git a/moto/rds2/__init__.py b/moto/rds2/__init__.py
new file mode 100644
index 000000000000..602c21ede630
--- /dev/null
+++ b/moto/rds2/__init__.py
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+from .models import rds2_backends
+from ..core.models import MockAWS
+
+rds2_backend = rds2_backends['us-west-1']
+
+
+def mock_rds2(func=None):
+ if func:
+ return MockAWS(rds2_backends)(func)
+ else:
+ return MockAWS(rds2_backends)
diff --git a/moto/rds2/exceptions.py b/moto/rds2/exceptions.py
new file mode 100644
index 000000000000..a5c9356593f8
--- /dev/null
+++ b/moto/rds2/exceptions.py
@@ -0,0 +1,39 @@
+from __future__ import unicode_literals
+
+import json
+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',
+ })
+
+
+class DBInstanceNotFoundError(RDSClientError):
+ def __init__(self, database_identifier):
+ super(DBInstanceNotFoundError, self).__init__(
+ 'DBInstanceNotFound',
+ "Database {0} not found.".format(database_identifier))
+
+
+class DBSecurityGroupNotFoundError(RDSClientError):
+ def __init__(self, security_group_name):
+ super(DBSecurityGroupNotFoundError, self).__init__(
+ 'DBSecurityGroupNotFound',
+ "Security Group {0} not found.".format(security_group_name))
+
+
+class DBSubnetGroupNotFoundError(RDSClientError):
+ def __init__(self, subnet_group_name):
+ super(DBSubnetGroupNotFoundError, self).__init__(
+ 'DBSubnetGroupNotFound',
+ "Subnet Group {0} not found.".format(subnet_group_name))
+
diff --git a/moto/rds2/models.py b/moto/rds2/models.py
new file mode 100644
index 000000000000..21155834b71c
--- /dev/null
+++ b/moto/rds2/models.py
@@ -0,0 +1,786 @@
+from __future__ import unicode_literals
+
+import copy
+
+import boto.rds2
+import json
+from jinja2 import Template
+from re import compile as re_compile
+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
+
+
+class Database(object):
+ def __init__(self, **kwargs):
+ self.status = "available"
+ self.is_replica = False
+ self.replicas = []
+ self.region = kwargs.get('region')
+ self.engine = kwargs.get("engine")
+ self.engine_version = kwargs.get("engine_version", None)
+ self.default_engine_versions = {"MySQL": "5.6.21",
+ "mysql": "5.6.21",
+ "oracle-se1": "11.2.0.4.v3",
+ "oracle-se": "11.2.0.4.v3",
+ "oracle-ee": "11.2.0.4.v3",
+ "sqlserver-ee": "11.00.2100.60.v1",
+ "sqlserver-se": "11.00.2100.60.v1",
+ "sqlserver-ex": "11.00.2100.60.v1",
+ "sqlserver-web": "11.00.2100.60.v1",
+ "postgres": "9.3.3"
+ }
+ 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_type = kwargs.get("storage_type")
+ self.master_username = kwargs.get('master_username')
+ self.master_user_password = kwargs.get('master_user_password')
+ self.auto_minor_version_upgrade = kwargs.get('auto_minor_version_upgrade')
+ if self.auto_minor_version_upgrade is None:
+ self.auto_minor_version_upgrade = True
+ self.allocated_storage = kwargs.get('allocated_storage')
+ self.db_instance_identifier = kwargs.get('db_instance_identifier')
+ self.source_db_identifier = kwargs.get("source_db_identifier")
+ self.db_instance_class = kwargs.get('db_instance_class')
+ self.port = kwargs.get('port')
+ self.db_instance_identifier = kwargs.get('db_instance_identifier')
+ self.db_name = kwargs.get("db_name")
+ self.publicly_accessible = kwargs.get("publicly_accessible")
+ if self.publicly_accessible is None:
+ self.publicly_accessible = True
+ self.backup_retention_period = kwargs.get("backup_retention_period")
+ if self.backup_retention_period is None:
+ self.backup_retention_period = 1
+ self.availability_zone = kwargs.get("availability_zone")
+ self.multi_az = kwargs.get("multi_az")
+ self.db_subnet_group_name = kwargs.get("db_subnet_group_name")
+ if self.db_subnet_group_name:
+ self.db_subnet_group = rds2_backends[self.region].describe_subnet_groups(self.db_subnet_group_name)[0]
+ else:
+ self.db_subnet_group = None
+ 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.preferred_backup_window = kwargs.get('preferred_backup_window', '13:14-13:44')
+ self.license_model = kwargs.get('license_model', 'general-public-license')
+ self.option_group_name = kwargs.get('option_group_name', None)
+ self.default_option_groups = {"MySQL": "default.mysql5.6",
+ "mysql": "default.mysql5.6",
+ "postgres": "default.postgres9.3"
+ }
+ if not self.option_group_name and self.engine in self.default_option_groups:
+ self.option_group_name = self.default_option_groups[self.engine]
+ self.character_set_name = kwargs.get('character_set_name', None)
+ self.tags = kwargs.get('tags', [])
+
+ @property
+ def address(self):
+ return "{0}.aaaaaaaaaa.{1}.rds.amazonaws.com".format(self.db_instance_identifier, self.region)
+
+ def add_replica(self, replica):
+ self.replicas.append(replica.db_instance_identifier)
+
+ def remove_replica(self, replica):
+ self.replicas.remove(replica.db_instance_identifier)
+
+ def set_as_replica(self):
+ self.is_replica = True
+ self.replicas = []
+
+ def update(self, db_kwargs):
+ for key, value in db_kwargs.items():
+ if value is not None:
+ setattr(self, key, value)
+
+ def get_cfn_attribute(self, attribute_name):
+ if attribute_name == 'Endpoint.Address':
+ return self.address
+ elif attribute_name == 'Endpoint.Port':
+ return self.port
+ raise UnformattedGetAttTemplateException()
+
+ @classmethod
+ def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
+ properties = cloudformation_json['Properties']
+
+ db_instance_identifier = properties.get('DBInstanceIdentifier')
+ if not db_instance_identifier:
+ db_instance_identifier = resource_name.lower() + get_random_hex(12)
+ db_security_groups = properties.get('DBSecurityGroups')
+ if not db_security_groups:
+ db_security_groups = []
+ security_groups = [group.group_name for group in db_security_groups]
+ db_subnet_group = properties.get("DBSubnetGroupName")
+ db_subnet_group_name = db_subnet_group.subnet_name if db_subnet_group else None
+ db_kwargs = {
+ "auto_minor_version_upgrade": properties.get('AutoMinorVersionUpgrade'),
+ "allocated_storage": properties.get('AllocatedStorage'),
+ "availability_zone": properties.get("AvailabilityZone"),
+ "backup_retention_period": properties.get("BackupRetentionPeriod"),
+ "db_instance_class": properties.get('DBInstanceClass'),
+ "db_instance_identifier": db_instance_identifier,
+ "db_name": properties.get("DBName"),
+ "db_subnet_group_name": db_subnet_group_name,
+ "engine": properties.get("Engine"),
+ "engine_version": properties.get("EngineVersion"),
+ "iops": properties.get("Iops"),
+ "master_password": properties.get('MasterUserPassword'),
+ "master_username": properties.get('MasterUsername'),
+ "multi_az": properties.get("MultiAZ"),
+ "port": properties.get('Port', 3306),
+ "publicly_accessible": properties.get("PubliclyAccessible"),
+ "region": region_name,
+ "security_groups": security_groups,
+ "storage_type": properties.get("StorageType"),
+ }
+
+ 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
+ database = rds2_backend.create_database_replica(db_kwargs)
+ else:
+ database = rds2_backend.create_database(db_kwargs)
+ return database
+
+ def to_json(self):
+ template = Template("""{
+ "AllocatedStorage": 10,
+ "AutoMinorVersionUpgrade": "{{ database.auto_minor_version_upgrade }}",
+ "AvailabilityZone": "{{ database.availability_zone }}",
+ "BackupRetentionPeriod": "{{ database.backup_retention_period }}",
+ "CharacterSetName": {%- if database.character_set_name -%}{{ database.character_set_name }}{%- else %} null{%- endif -%},
+ "DBInstanceClass": "{{ database.db_instance_class }}",
+ "DBInstanceIdentifier": "{{ database.db_instance_identifier }}",
+ "DBInstanceStatus": "{{ database.status }}",
+ "DBName": {%- if database.db_name -%}{{ database.db_name }}{%- else %} null{%- endif -%},
+ {% if database.db_parameter_group_name -%}"DBParameterGroups": {
+ "DBParameterGroup": {
+ "ParameterApplyStatus": "in-sync",
+ "DBParameterGroupName": "{{ database.db_parameter_group_name }}"
+ }
+ },{%- endif %}
+ "DBSecurityGroups": [
+ {% for security_group in database.security_groups -%}{%- if loop.index != 1 -%},{%- endif -%}
+ {"DBSecurityGroup": {
+ "Status": "active",
+ "DBSecurityGroupName": "{{ security_group }}"
+ }}{% endfor %}
+ ],
+ {%- if database.db_subnet_group -%}{{ database.db_subnet_group.to_json() }},{%- endif %}
+ "Engine": "{{ database.engine }}",
+ "EngineVersion": "{{ database.engine_version }}",
+ "LatestRestorableTime": null,
+ "LicenseModel": "{{ database.license_model }}",
+ "MasterUsername": "{{ database.master_username }}",
+ "MultiAZ": "{{ database.multi_az }}",{% if database.option_group_name %}
+ "OptionGroupMemberships": [{
+ "OptionGroupMembership": {
+ "OptionGroupName": "{{ database.option_group_name }}",
+ "Status": "in-sync"
+ }
+ }],{%- endif %}
+ "PendingModifiedValues": { "MasterUserPassword": "****" },
+ "PreferredBackupWindow": "{{ database.preferred_backup_window }}",
+ "PreferredMaintenanceWindow": "{{ database.preferred_maintenance_window }}",
+ "PubliclyAccessible": "{{ database.publicly_accessible }}",
+ "AllocatedStorage": "{{ database.allocated_storage }}",
+ "Endpoint": {
+ "Address": "{{ database.address }}",
+ "Port": "{{ database.port }}"
+ },
+ "InstanceCreateTime": null,
+ "Iops": null,
+ "ReadReplicaDBInstanceIdentifiers": [{%- for replica in database.replicas -%}
+ {%- if not loop.first -%},{%- endif -%}
+ "{{ replica }}"
+ {%- endfor -%}
+ ],
+ {%- if database.source_db_identifier -%}
+ "ReadReplicaSourceDBInstanceIdentifier": "{{ database.source_db_identifier }}",
+ {%- else -%}
+ "ReadReplicaSourceDBInstanceIdentifier": null,
+ {%- endif -%}
+ "SecondaryAvailabilityZone": null,
+ "StatusInfos": null,
+ "VpcSecurityGroups": [
+ {
+ "Status": "active",
+ "VpcSecurityGroupId": "sg-123456"
+ }
+ ]
+ }""")
+ return template.render(database=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]
+
+
+class SecurityGroup(object):
+ def __init__(self, group_name, description):
+ self.group_name = group_name
+ self.description = description
+ self.status = "authorized"
+ self.ip_ranges = []
+ self.ec2_security_groups = []
+ self.tags = []
+ self.owner_id = '1234567890'
+ self.vpc_id = None
+
+ def to_xml(self):
+ template = Template("""
+
+ {% for security_group in security_group.ec2_security_groups %}
+
+ {{ security_group.id }}
+ {{ security_group.name }}
+ {{ security_group.owner_id }}
+ authorized
+
+ {% endfor %}
+
+
+ {{ security_group.description }}
+
+ {% for ip_range in security_group.ip_ranges %}
+
+ {{ ip_range }}
+ authorized
+
+ {% endfor %}
+
+ {{ security_group.ownder_id }}
+ {{ security_group.group_name }}
+ """)
+ return template.render(security_group=self)
+
+ def to_json(self):
+ template = Template("""{
+ "DBSecurityGroupDescription": "{{ security_group.description }}",
+ "DBSecurityGroupName": "{{ security_group.group_name }}",
+ "EC2SecurityGroups": {{ security_group.ec2_security_groups }},
+ "IPRanges": [{%- for ip in security_group.ip_ranges -%}
+ {%- if loop.index != 1 -%},{%- endif -%}
+ "{{ ip }}"
+ {%- endfor -%}
+ ],
+ "OwnerId": "{{ security_group.owner_id }}",
+ "VpcId": "{{ security_group.vpc_id }}"
+ }""")
+ return template.render(security_group=self)
+
+ def authorize_cidr(self, cidr_ip):
+ self.ip_ranges.append(cidr_ip)
+
+ def authorize_security_group(self, security_group):
+ self.ec2_security_groups.append(security_group)
+
+ @classmethod
+ def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
+ properties = cloudformation_json['Properties']
+ group_name = resource_name.lower() + get_random_hex(12)
+ description = properties['GroupDescription']
+ security_group_ingress = properties['DBSecurityGroupIngress']
+
+ ec2_backend = ec2_backends[region_name]
+ rds2_backend = rds2_backends[region_name]
+ security_group = rds2_backend.create_security_group(
+ group_name,
+ description,
+ )
+ 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):
+ 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]
+
+
+class SubnetGroup(object):
+ def __init__(self, subnet_name, description, subnets):
+ self.subnet_name = subnet_name
+ self.description = description
+ self.subnets = subnets
+ self.status = "Complete"
+ self.tags = []
+ self.vpc_id = self.subnets[0].vpc_id
+
+ def to_xml(self):
+ template = Template("""
+ {{ subnet_group.vpc_id }}
+ {{ subnet_group.status }}
+ {{ subnet_group.description }}
+ {{ subnet_group.subnet_name }}
+
+ {% for subnet in subnet_group.subnets %}
+
+ Active
+ {{ subnet.id }}
+
+ {{ subnet.availability_zone }}
+ false
+
+
+ {% endfor %}
+
+ """)
+ return template.render(subnet_group=self)
+
+ def to_json(self):
+ template = Template(""""DBSubnetGroup": {
+ "VpcId": "{{ subnet_group.vpc_id }}",
+ "SubnetGroupStatus": "{{ subnet_group.status }}",
+ "DBSubnetGroupDescription": "{{ subnet_group.description }}",
+ "DBSubnetGroupName": "{{ subnet_group.subnet_name }}",
+ "Subnets": {
+ "Subnet": [
+ {% for subnet in subnet_group.subnets %}{
+ "SubnetStatus": "Active",
+ "SubnetIdentifier": "{{ subnet.id }}",
+ "SubnetAvailabilityZone": {
+ "Name": "{{ subnet.availability_zone }}",
+ "ProvisionedIopsCapable": "false"
+ }
+ }{%- if not loop.last -%},{%- endif -%}{% endfor %}
+ ]
+ }
+ }""")
+ return template.render(subnet_group=self)
+
+ @classmethod
+ def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
+ properties = cloudformation_json['Properties']
+
+ subnet_name = resource_name.lower() + get_random_hex(12)
+ description = properties['DBSubnetGroupDescription']
+ subnet_ids = properties['SubnetIds']
+
+ ec2_backend = ec2_backends[region_name]
+ subnets = [ec2_backend.get_subnet(subnet_id) for subnet_id in subnet_ids]
+ rds2_backend = rds2_backends[region_name]
+ subnet_group = rds2_backend.create_subnet_group(
+ subnet_name,
+ description,
+ subnets,
+ )
+ return subnet_group
+
+ def get_tags(self):
+ # TODO: Write tags add/remove/list tests for SubnetGroups
+ 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]
+
+
+class RDS2Backend(BaseBackend):
+
+ def __init__(self):
+ self.arn_regex = re_compile(r'^arn:aws:rds:.*:[0-9]*:(db|es|og|pg|ri|secgrp|snapshot|subgrp):.*$')
+ self.databases = {}
+ self.security_groups = {}
+ self.subnet_groups = {}
+ self.option_groups = {}
+
+ 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 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 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 modify_database(self, db_instance_identifier, db_kwargs):
+ database = self.describe_databases(db_instance_identifier)[0]
+ database.update(db_kwargs)
+ return database
+
+ def reboot_db_instance(self, db_instance_identifier):
+ database = self.describe_databases(db_instance_identifier)[0]
+ 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)
+ 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)
+
+ def create_option_group(self, option_group_kwargs):
+ option_group_id = option_group_kwargs['name']
+ valid_option_group_engines = {'mysql': ['5.6'],
+ 'oracle-se1': ['11.2'],
+ 'oracle-se': ['11.2'],
+ 'oracle-ee': ['11.2'],
+ 'sqlserver-se': ['10.50', '11.00'],
+ 'sqlserver-ee': ['10.50', '11.00']
+ }
+ if option_group_kwargs['name'] in self.option_groups:
+ raise RDSClientError('OptionGroupAlreadyExistsFault',
+ 'An option group named {0} already exists.'.format(option_group_kwargs['name']))
+ if 'description' not in option_group_kwargs or not option_group_kwargs['description']:
+ raise RDSClientError('InvalidParameterValue',
+ 'The parameter OptionGroupDescription must be provided and must not be blank.')
+ if option_group_kwargs['engine_name'] not in valid_option_group_engines.keys():
+ raise RDSClientError('InvalidParameterValue', 'Invalid DB engine: non-existant')
+ if option_group_kwargs['major_engine_version'] not in\
+ valid_option_group_engines[option_group_kwargs['engine_name']]:
+ raise RDSClientError('InvalidParameterCombination',
+ 'Cannot find major version {0} for {1}'.format(
+ option_group_kwargs['major_engine_version'],
+ option_group_kwargs['engine_name']
+ ))
+ option_group = OptionGroup(**option_group_kwargs)
+ self.option_groups[option_group_id] = option_group
+ return option_group
+
+ def delete_option_group(self, option_group_name):
+ if option_group_name in self.option_groups:
+ return self.option_groups.pop(option_group_name)
+ else:
+ raise RDSClientError('OptionGroupNotFoundFault', 'Specified OptionGroupName: {0} not found.'.format(option_group_name))
+
+ def describe_option_groups(self, option_group_kwargs):
+ option_group_list = []
+
+ if option_group_kwargs['marker']:
+ marker = option_group_kwargs['marker']
+ else:
+ marker = 0
+ if option_group_kwargs['max_records']:
+ if option_group_kwargs['max_records'] < 20 or option_group_kwargs['max_records'] > 100:
+ raise RDSClientError('InvalidParameterValue',
+ 'Invalid value for max records. Must be between 20 and 100')
+ max_records = option_group_kwargs['max_records']
+ else:
+ max_records = 100
+
+ for option_group_name, option_group in self.option_groups.items():
+ if option_group_kwargs['name'] and option_group.name != option_group_kwargs['name']:
+ continue
+ elif option_group_kwargs['engine_name'] and \
+ option_group.engine_name != option_group_kwargs['engine_name']:
+ continue
+ elif option_group_kwargs['major_engine_version'] and \
+ option_group.major_engine_version != option_group_kwargs['major_engine_version']:
+ continue
+ else:
+ option_group_list.append(option_group)
+ if not len(option_group_list):
+ raise RDSClientError('OptionGroupNotFoundFault',
+ 'Specified OptionGroupName: {0} not found.'.format(option_group_kwargs['name']))
+ return option_group_list[marker:max_records+marker]
+
+ @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"}}}'
+ }
+ }
+ 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]:
+ raise RDSClientError('InvalidParameterCombination',
+ 'Cannot find major version {0} for {1}'.format(major_engine_version, engine_name))
+ if major_engine_version:
+ return default_option_group_options[engine_name][major_engine_version]
+ return default_option_group_options[engine_name]['all']
+
+ def modify_option_group(self, option_group_name, options_to_include=None, options_to_remove=None, apply_immediately=None):
+ if option_group_name not in self.option_groups:
+ raise RDSClientError('OptionGroupNotFoundFault',
+ 'Specified OptionGroupName: {0} not found.'.format(option_group_name))
+ if not options_to_include and not options_to_remove:
+ raise RDSClientError('InvalidParameterValue',
+ 'At least one option must be added, modified, or removed.')
+ if options_to_remove:
+ self.option_groups[option_group_name].remove_options(options_to_remove)
+ if options_to_include:
+ self.option_groups[option_group_name].add_options(options_to_include)
+ return self.option_groups[option_group_name]
+
+ def list_tags_for_resource(self, arn):
+ if self.arn_regex.match(arn):
+ arn_breakdown = arn.split(':')
+ resource_type = arn_breakdown[len(arn_breakdown)-2]
+ resource_name = arn_breakdown[len(arn_breakdown)-1]
+ if resource_type == 'db': # Database
+ if resource_name in self.databases:
+ return self.databases[resource_name].get_tags()
+ elif resource_type == 'es': # Event Subscription
+ # TODO: Complete call to tags on resource type Event Subscription
+ return []
+ elif resource_type == 'og': # Option Group
+ 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 []
+ 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:
+ 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:
+ return self.subnet_groups[resource_name].get_tags()
+ else:
+ raise RDSClientError('InvalidParameterValue',
+ 'Invalid resource name: {0}'.format(arn))
+ return []
+
+ def remove_tags_from_resource(self, arn, tag_keys):
+ if self.arn_regex.match(arn):
+ arn_breakdown = arn.split(':')
+ resource_type = arn_breakdown[len(arn_breakdown)-2]
+ resource_name = arn_breakdown[len(arn_breakdown)-1]
+ if resource_type == 'db': # Database
+ if resource_name in self.databases:
+ self.databases[resource_name].remove_tags(tag_keys)
+ elif resource_type == 'es': # Event Subscription
+ return None
+ elif resource_type == 'og': # Option Group
+ if resource_name in self.option_groups:
+ return self.option_groups[resource_name].remove_tags(tag_keys)
+ elif resource_type == 'pg': # Parameter Group
+ return None
+ elif resource_type == 'ri': # Reserved DB instance
+ return None
+ elif resource_type == 'secgrp': # DB security group
+ if resource_type 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:
+ return self.subnet_groups[resource_name].remove_tags(tag_keys)
+ else:
+ raise RDSClientError('InvalidParameterValue',
+ 'Invalid resource name: {}'.format(arn))
+
+ def add_tags_to_resource(self, arn, tags):
+ if self.arn_regex.match(arn):
+ arn_breakdown = arn.split(':')
+ resource_type = arn_breakdown[len(arn_breakdown)-2]
+ resource_name = arn_breakdown[len(arn_breakdown)-1]
+ if resource_type == 'db': # Database
+ if resource_name in self.databases:
+ return self.databases[resource_name].add_tags(tags)
+ elif resource_type == 'es': # Event Subscription
+ return []
+ elif resource_type == 'og': # Option Group
+ if resource_name in self.option_groups:
+ return self.option_groups[resource_name].add_tags(tags)
+ elif resource_type == 'pg': # Parameter Group
+ return []
+ elif resource_type == 'ri': # Reserved DB instance
+ return []
+ elif resource_type == 'secgrp': # DB security group
+ if resource_type 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:
+ return self.subnet_groups[resource_name].add_tags(tags)
+ else:
+ raise RDSClientError('InvalidParameterValue',
+ 'Invalid resource name: {}'.format(arn))
+
+
+class OptionGroup(object):
+ def __init__(self, name, engine_name, major_engine_version, description=None):
+ self.engine_name = engine_name
+ self.major_engine_version = major_engine_version
+ self.description = description
+ self.name = name
+ self.vpc_and_non_vpc_instance_memberships = False
+ self.options = {}
+ self.vpcId = 'null'
+ self.tags = []
+
+ def to_json(self):
+ template = Template("""{
+ "VpcId": null,
+ "MajorEngineVersion": "{{ option_group.major_engine_version }}",
+ "OptionGroupDescription": "{{ option_group.description }}",
+ "AllowsVpcAndNonVpcInstanceMemberships": "{{ option_group.vpc_and_non_vpc_instance_memberships }}",
+ "EngineName": "{{ option_group.engine_name }}",
+ "Options": [],
+ "OptionGroupName": "{{ option_group.name }}"
+}""")
+ 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
+
+ def add_options(self, options_to_add):
+ # TODO: Validate option and add it to self.options. If invalid raise error
+ return
+
+ 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]
+
+
+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 to_json(self):
+ template = Template("""{ "MinimumRequiredMinorEngineVersion":
+ "2789.0.v1",
+ "OptionsDependedOn": [],
+ "MajorEngineVersion": "10.50",
+ "Persistent": false,
+ "DefaultPort": null,
+ "Permanent": false,
+ "OptionGroupOptionSettings": [],
+ "EngineName": "sqlserver-se",
+ "Name": "Mirroring",
+ "PortRequired": false,
+ "Description": "SQLServer Database Mirroring"
+ }""")
+ return template.render(option_group=self)
+
+
+rds2_backends = {}
+for region in boto.rds2.regions():
+ rds2_backends[region.name] = RDS2Backend()
diff --git a/moto/rds2/responses.py b/moto/rds2/responses.py
new file mode 100644
index 000000000000..daa068aa6935
--- /dev/null
+++ b/moto/rds2/responses.py
@@ -0,0 +1,507 @@
+from __future__ import unicode_literals
+
+from moto.core.responses import BaseResponse
+from moto.ec2.models import ec2_backends
+from .models import rds2_backends
+import json
+import re
+
+
+class RDS2Response(BaseResponse):
+
+ @property
+ def backend(self):
+ return rds2_backends[self.region]
+
+ def _get_db_kwargs(self):
+ args = {
+ "auto_minor_version_upgrade": self._get_param('AutoMinorVersionUpgrade'),
+ "allocated_storage": self._get_int_param('AllocatedStorage'),
+ "availability_zone": self._get_param("AvailabilityZone"),
+ "backup_retention_period": self._get_param("BackupRetentionPeriod"),
+ "db_instance_class": self._get_param('DBInstanceClass'),
+ "db_instance_identifier": self._get_param('DBInstanceIdentifier'),
+ "db_name": self._get_param("DBName"),
+ # 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"),
+ "master_password": self._get_param('MasterUserPassword'),
+ "master_username": self._get_param('MasterUsername'),
+ "multi_az": self._get_bool_param("MultiAZ"),
+ # OptionGroupName
+ "port": self._get_param('Port'),
+ # PreferredBackupWindow
+ # PreferredMaintenanceWindow
+ "publicly_accessible": self._get_param("PubliclyAccessible"),
+ "region": self.region,
+ "security_groups": self._get_multi_param('DBSecurityGroups.member'),
+ "storage_type": self._get_param("StorageType"),
+ # VpcSecurityGroupIds.member.N
+ "tags": list()
+ }
+ args['tags'] = self.unpack_complex_list_params('Tags.member', ('Key', 'Value'))
+ return args
+
+ def _get_db_replica_kwargs(self):
+ return {
+ "auto_minor_version_upgrade": self._get_param('AutoMinorVersionUpgrade'),
+ "availability_zone": self._get_param("AvailabilityZone"),
+ "db_instance_class": self._get_param('DBInstanceClass'),
+ "db_instance_identifier": self._get_param('DBInstanceIdentifier'),
+ "db_subnet_group_name": self._get_param("DBSubnetGroupName"),
+ "iops": self._get_int_param("Iops"),
+ # OptionGroupName
+ "port": self._get_param('Port'),
+ "publicly_accessible": self._get_param("PubliclyAccessible"),
+ "source_db_identifier": self._get_param('SourceDBInstanceIdentifier'),
+ "storage_type": self._get_param("StorageType"),
+ }
+
+ def _get_option_group_kwargs(self):
+ return {
+ 'major_engine_version': self._get_param('MajorEngineVersion'),
+ 'description': self._get_param('OptionGroupDescription'),
+ 'engine_name': self._get_param('EngineName'),
+ 'name': self._get_param('OptionGroupName')
+ }
+
+ 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 unpack_list_params(self, label):
+ unpacked_list = list()
+ count = 1
+ while self._get_param('{0}.{1}'.format(label, count)):
+ unpacked_list.append(self._get_param('{0}.{1}'.format(label, count)))
+ count += 1
+ return unpacked_list
+
+ def create_dbinstance(self):
+ return self.create_db_instance()
+
+ def create_db_instance(self):
+ db_kwargs = self._get_db_kwargs()
+ database = self.backend.create_database(db_kwargs)
+ template = self.response_template(CREATE_DATABASE_TEMPLATE)
+ return template.render(database=database)
+
+ def create_dbinstance_read_replica(self):
+ return self.create_db_instance_read_replica()
+
+ def create_db_instance_read_replica(self):
+ db_kwargs = self._get_db_replica_kwargs()
+
+ database = self.backend.create_database_replica(db_kwargs)
+ template = self.response_template(CREATE_DATABASE_REPLICA_TEMPLATE)
+ return template.render(database=database)
+
+ def describe_dbinstances(self):
+ return self.describe_db_instances()
+
+ def describe_db_instances(self):
+ db_instance_identifier = self._get_param('DBInstanceIdentifier')
+ databases = self.backend.describe_databases(db_instance_identifier)
+ template = self.response_template(DESCRIBE_DATABASES_TEMPLATE)
+ return template.render(databases=databases)
+
+ def modify_dbinstance(self):
+ return self.modify_db_instance()
+
+ def modify_db_instance(self):
+ db_instance_identifier = self._get_param('DBInstanceIdentifier')
+ db_kwargs = self._get_db_kwargs()
+ database = self.backend.modify_database(db_instance_identifier, db_kwargs)
+ template = self.response_template(MODIFY_DATABASE_TEMPLATE)
+ return template.render(database=database)
+
+ def delete_dbinstance(self):
+ return self.delete_db_instance()
+
+ def delete_db_instance(self):
+ db_instance_identifier = self._get_param('DBInstanceIdentifier')
+ database = self.backend.delete_database(db_instance_identifier)
+ template = self.response_template(DELETE_DATABASE_TEMPLATE)
+ return template.render(database=database)
+
+ def reboot_dbinstance(self):
+ return self.reboot_db_instance()
+
+ def reboot_db_instance(self):
+ db_instance_identifier = self._get_param('DBInstanceIdentifier')
+ database = self.backend.reboot_db_instance(db_instance_identifier)
+ template = self.response_template(REBOOT_DATABASE_TEMPLATE)
+ return template.render(database=database)
+
+ def list_tags_for_resource(self):
+ arn = self._get_param('ResourceName')
+ template = self.response_template(LIST_TAGS_FOR_RESOURCE_TEMPLATE)
+ tags = self.backend.list_tags_for_resource(arn)
+ return template.render(tags=tags)
+
+ def add_tags_to_resource(self):
+ arn = self._get_param('ResourceName')
+ tags = self.unpack_complex_list_params('Tags.member', ('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)
+
+ def remove_tags_from_resource(self):
+ arn = self._get_param('ResourceName')
+ tag_keys = self.unpack_list_params('TagKeys.member')
+ self.backend.remove_tags_from_resource(arn, tag_keys)
+ template = self.response_template(REMOVE_TAGS_FROM_RESOURCE_TEMPLATE)
+ return template.render()
+
+ def create_dbsecurity_group(self):
+ return self.create_db_security_group()
+
+ 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)
+ template = self.response_template(CREATE_SECURITY_GROUP_TEMPLATE)
+ return template.render(security_group=security_group)
+
+ def describe_dbsecurity_groups(self):
+ return self.describe_db_security_groups()
+
+ def describe_db_security_groups(self):
+ security_group_name = self._get_param('DBSecurityGroupName')
+ security_groups = self.backend.describe_security_groups(security_group_name)
+ template = self.response_template(DESCRIBE_SECURITY_GROUPS_TEMPLATE)
+ return template.render(security_groups=security_groups)
+
+ def delete_dbsecurity_group(self):
+ return self.delete_db_security_group()
+
+ def delete_db_security_group(self):
+ security_group_name = self._get_param('DBSecurityGroupName')
+ security_group = self.backend.delete_security_group(security_group_name)
+ template = self.response_template(DELETE_SECURITY_GROUP_TEMPLATE)
+ return template.render(security_group=security_group)
+
+ def authorize_dbsecurity_group_ingress(self):
+ return self.authorize_db_security_group_ingress()
+
+ def authorize_db_security_group_ingress(self):
+ security_group_name = self._get_param('DBSecurityGroupName')
+ cidr_ip = self._get_param('CIDRIP')
+ security_group = self.backend.authorize_security_group(security_group_name, cidr_ip)
+ template = self.response_template(AUTHORIZE_SECURITY_GROUP_TEMPLATE)
+ return template.render(security_group=security_group)
+
+ def create_dbsubnet_group(self):
+ return self.create_db_subnet_group()
+
+ 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')
+ subnets = [ec2_backends[self.region].get_subnet(subnet_id) for subnet_id in subnet_ids]
+ subnet_group = self.backend.create_subnet_group(subnet_name, description, subnets)
+ template = self.response_template(CREATE_SUBNET_GROUP_TEMPLATE)
+ return template.render(subnet_group=subnet_group)
+
+ def describe_dbsubnet_groups(self):
+ return self.describe_db_subnet_groups()
+
+ def describe_db_subnet_groups(self):
+ subnet_name = self._get_param('DBSubnetGroupName')
+ subnet_groups = self.backend.describe_subnet_groups(subnet_name)
+ template = self.response_template(DESCRIBE_SUBNET_GROUPS_TEMPLATE)
+ return template.render(subnet_groups=subnet_groups)
+
+ def delete_dbsubnet_group(self):
+ return self.delete_db_subnet_group()
+
+ def delete_db_subnet_group(self):
+ subnet_name = self._get_param('DBSubnetGroupName')
+ subnet_group = self.backend.delete_subnet_group(subnet_name)
+ template = self.response_template(DELETE_SUBNET_GROUP_TEMPLATE)
+ return template.render(subnet_group=subnet_group)
+
+ def create_option_group(self):
+ kwargs = self._get_option_group_kwargs()
+ option_group = self.backend.create_option_group(kwargs)
+ template = self.response_template(CREATE_OPTION_GROUP_TEMPLATE)
+ return template.render(option_group=option_group)
+
+ def delete_option_group(self):
+ kwargs = self._get_option_group_kwargs()
+ option_group = self.backend.delete_option_group(kwargs['name'])
+ template = self.response_template(DELETE_OPTION_GROUP_TEMPLATE)
+ return template.render(option_group=option_group)
+
+ def describe_option_groups(self):
+ kwargs = self._get_option_group_kwargs()
+ kwargs['max_records'] = self._get_param('MaxRecords')
+ kwargs['marker'] = self._get_param('Marker')
+ option_groups = self.backend.describe_option_groups(kwargs)
+ template = self.response_template(DESCRIBE_OPTION_GROUP_TEMPLATE)
+ return template.render(option_groups=option_groups)
+
+ def describe_option_group_options(self):
+ engine_name = self._get_param('EngineName')
+ major_engine_version = self._get_param('MajorEngineVersion')
+ option_group_options = self.backend.describe_option_group_options(engine_name, major_engine_version)
+ return option_group_options
+
+ def modify_option_group(self):
+ option_group_name = self._get_param('OptionGroupName')
+ count = 1
+ options_to_include = []
+ while self._get_param('OptionsToInclude.member.{0}.OptionName'.format(count)):
+ options_to_include.append({
+ 'Port': self._get_param('OptionsToInclude.member.{0}.Port'.format(count)),
+ 'OptionName': self._get_param('OptionsToInclude.member.{0}.OptionName'.format(count)),
+ 'DBSecurityGroupMemberships': self._get_param('OptionsToInclude.member.{0}.DBSecurityGroupMemberships'.format(count)),
+ 'OptionSettings': self._get_param('OptionsToInclude.member.{0}.OptionSettings'.format(count)),
+ 'VpcSecurityGroupMemberships': self._get_param('OptionsToInclude.member.{0}.VpcSecurityGroupMemberships'.format(count))
+ })
+ count += 1
+
+ count = 1
+ options_to_remove = []
+ while self._get_param('OptionsToRemove.member.{0}'.format(count)):
+ options_to_remove.append(self._get_param('OptionsToRemove.member.{0}'.format(count)))
+ count += 1
+ apply_immediately = self._get_param('ApplyImmediately')
+ option_group = self.backend.modify_option_group(option_group_name,
+ options_to_include,
+ options_to_remove,
+ apply_immediately)
+ template = self.response_template(MODIFY_OPTION_GROUP_TEMPLATE)
+ return template.render(option_group=option_group)
+
+
+CREATE_DATABASE_TEMPLATE = """{
+ "CreateDBInstanceResponse": {
+ "CreateDBInstanceResult": {
+ "DBInstance": {{ database.to_json() }}
+ },
+ "ResponseMetadata": { "RequestId": "523e3218-afc7-11c3-90f5-f90431260ab4" }
+ }
+}"""
+
+CREATE_DATABASE_REPLICA_TEMPLATE = """{"CreateDBInstanceReadReplicaResponse": {
+ "ResponseMetadata": {
+ "RequestId": "5e60c46d-a844-11e4-bb68-17f36418e58f"
+ },
+ "CreateDBInstanceReadReplicaResult": {
+ "DBInstance": {{ database.to_json() }}
+ }
+}}"""
+
+DESCRIBE_DATABASES_TEMPLATE = """{
+ "DescribeDBInstancesResponse": {
+ "DescribeDBInstancesResult": {
+ "DBInstances": [
+ {%- for database in databases -%}
+ {%- if loop.index != 1 -%},{%- endif -%}
+ {{ database.to_json() }}
+ {%- endfor -%}
+ ]
+ },
+ "ResponseMetadata": { "RequestId": "523e3218-afc7-11c3-90f5-f90431260ab4" }
+ }
+}"""
+
+MODIFY_DATABASE_TEMPLATE = """{"ModifyDBInstanceResponse": {
+ "ModifyDBInstanceResult": {
+ "DBInstance": {{ database.to_json() }},
+ "ResponseMetadata": {
+ "RequestId": "bb58476c-a1a8-11e4-99cf-55e92d4bbada"
+ }
+ }
+ }
+}"""
+
+REBOOT_DATABASE_TEMPLATE = """{"RebootDBInstanceResponse": {
+ "RebootDBInstanceResult": {
+ "DBInstance": {{ database.to_json() }},
+ "ResponseMetadata": {
+ "RequestId": "d55711cb-a1ab-11e4-99cf-55e92d4bbada"
+ }
+ }
+ }
+}"""
+
+
+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"}}}
+ """
\ No newline at end of file
diff --git a/moto/rds2/urls.py b/moto/rds2/urls.py
new file mode 100644
index 000000000000..d21084766e77
--- /dev/null
+++ b/moto/rds2/urls.py
@@ -0,0 +1,11 @@
+from __future__ import unicode_literals
+from .responses import RDS2Response
+
+url_bases = [
+ "https?://rds.(.+).amazonaws.com",
+ "https?://rds.amazonaws.com",
+]
+
+url_paths = {
+ '{0}/$': RDS2Response().dispatch,
+}
diff --git a/tests/test_rds2/test_rds2.py b/tests/test_rds2/test_rds2.py
new file mode 100644
index 000000000000..7ca48f0aa0d0
--- /dev/null
+++ b/tests/test_rds2/test_rds2.py
@@ -0,0 +1,577 @@
+from __future__ import unicode_literals
+
+import boto.rds2
+import boto.vpc
+from boto.exception import BotoServerError
+import sure # noqa
+from moto import mock_ec2, 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')
+
+
+@disable_on_py3()
+@mock_rds2
+def test_get_databases():
+ conn = boto.rds2.connect_to_region("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"])
+ 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"])
+ instances = conn.describe_db_instances()
+ list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['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")
+
+
+@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)
+
+
+@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')
+
+
+@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)
+
+@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")
+
+
+@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)
+
+
+@disable_on_py3()
+@mock_rds2
+def test_delete_database():
+ conn = boto.rds2.connect_to_region("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"])
+ instances = conn.describe_db_instances()
+ list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances']).should.have.length_of(1)
+
+ conn.delete_db_instance("db-master-1")
+ instances = conn.describe_db_instances()
+ list(instances['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['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)
+
+
+@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')
+
+
+@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)
+
+
+@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)
+
+
+@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)
+
+
+@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)
+
+
+@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')
+
+
+@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)
+
+
+@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)
+
+
+@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)
+
+
+@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)
+
+
+@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')
+ # 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')
+
+
+@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)
+
+
+@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)
+
+
+@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)
+
+
+@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)
+
+
+@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'}])
+
+
+@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)
+
+
+@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)
+
+
+@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)
+
+
+@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)
+
+
+@disable_on_py3()
+@mock_rds2
+def test_create_database_security_group():
+ conn = boto.rds2.connect_to_region("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([])
+
+
+@disable_on_py3()
+@mock_rds2
+def test_get_security_groups():
+ conn = boto.rds2.connect_to_region("us-west-2")
+
+ result = conn.describe_db_security_groups()
+ result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['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')
+
+ result = conn.describe_db_security_groups()
+ result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['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")
+
+
+@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)
+
+
+@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')
+
+ result = conn.describe_db_security_groups()
+ result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['DBSecurityGroups'].should.have.length_of(1)
+
+ conn.delete_db_security_group("db_sg")
+ result = conn.describe_db_security_groups()
+ result['DescribeDBSecurityGroupsResponse']['DescribeDBSecurityGroupsResult']['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)
+
+
+@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.authorize_db_security_group_ingress(db_security_group_name='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'])
+
+ 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'])
+
+
+@disable_on_py3()
+@mock_rds2
+def test_add_security_group_to_database():
+ 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')
+ 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 = conn.describe_db_instances()
+ result['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['DBSecurityGroups'][0]['DBSecurityGroup']['DBSecurityGroupName'].should.equal('db_sg')
+
+
+@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")
+
+ 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']]
+ list(subnet_group_ids).should.equal(subnet_ids)
+
+
+@disable_on_py3()
+@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")
+
+ 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")
+
+
+@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")
+
+ 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])
+
+ resp = conn.describe_db_subnet_groups()
+ groups_resp = resp['DescribeDBSubnetGroupsResponse']
+
+ subnet_groups = groups_resp['DescribeDBSubnetGroupsResult']['DBSubnetGroups']
+ subnet_groups.should.have.length_of(2)
+
+ subnets = groups_resp['DescribeDBSubnetGroupsResult']['DBSubnetGroups'][0]['DBSubnetGroup']['Subnets']
+ subnets.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)
+
+
+@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")
+
+ conn = boto.rds2.connect_to_region("us-west-2")
+ result = conn.describe_db_subnet_groups()
+ result['DescribeDBSubnetGroupsResponse']['DescribeDBSubnetGroupsResult']['DBSubnetGroups'].should.have.length_of(0)
+
+ conn.create_db_subnet_group("db_subnet1", "my db subnet", [subnet.id])
+ result = conn.describe_db_subnet_groups()
+ result['DescribeDBSubnetGroupsResponse']['DescribeDBSubnetGroupsResult']['DBSubnetGroups'].should.have.length_of(1)
+
+ conn.delete_db_subnet_group("db_subnet1")
+ result = conn.describe_db_subnet_groups()
+ result['DescribeDBSubnetGroupsResponse']['DescribeDBSubnetGroupsResult']['DBSubnetGroups'].should.have.length_of(0)
+
+ conn.delete_db_subnet_group.when.called_with("db_subnet1").should.throw(BotoServerError)
+
+
+@disable_on_py3()
+@mock_rds2
+def test_create_database_replica():
+ 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"])
+
+ 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')
+
+ master = conn.describe_db_instances("db-master-1")
+ master['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['ReadReplicaDBInstanceIdentifiers'].should.equal(['db-replica-1'])
+
+ conn.delete_db_instance("db-replica-1")
+
+ master = conn.describe_db_instances("db-master-1")
+ master['DescribeDBInstancesResponse']['DescribeDBInstancesResult']['DBInstances'][0]['ReadReplicaDBInstanceIdentifiers'].should.equal([])
diff --git a/tests/test_rds2/test_server.py b/tests/test_rds2/test_server.py
new file mode 100644
index 000000000000..19c2b6e9fa71
--- /dev/null
+++ b/tests/test_rds2/test_server.py
@@ -0,0 +1,20 @@
+from __future__ import unicode_literals
+
+import sure # noqa
+
+import moto.server as server
+from moto import mock_rds2
+
+'''
+Test the different server responses
+'''
+
+
+#@mock_rds2
+#def test_list_databases():
+# backend = server.create_backend_app("rds2")
+# test_client = backend.test_client()
+#
+# res = test_client.get('/?Action=DescribeDBInstances')
+#
+# res.data.decode("utf-8").should.contain("")