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("")