From eef7a3fa7226c8c5f04ab1d5d242ca169a2f667a Mon Sep 17 00:00:00 2001 From: James Bence Date: Mon, 8 Jul 2013 15:36:58 -0700 Subject: [PATCH 1/7] Add request/parser for DescribeOperableDBInstanceOptions --- .../describe_orderable_db_instance_options.rb | 47 ++++++++++++++ lib/fog/aws/rds.rb | 2 + .../describe_orderable_db_instance_options.rb | 61 +++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb create mode 100644 lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb diff --git a/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb b/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb new file mode 100644 index 000000000..6d1ed7e83 --- /dev/null +++ b/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb @@ -0,0 +1,47 @@ +module Fog + module Parsers + module AWS + module RDS + + class DescribeOrderableDBInstanceOptions < Fog::Parsers::Base + + def reset + @response = { 'DescribeOrderableDBInstanceOptionsResult' => {'OrderableDBInstanceOptions' => []}, 'ResponseMetadata' => {} } + @db_instance_option = {} + @db_instance_options = [] + end + + def start_element(name, attrs = []) + case name + when 'AvailabilityZones' then @availability_zones = [] + when 'AvailabilityZone' then @availability_zone = {} + end + super + end + + def end_element(name) + case name + when 'MultiAZCapable', 'ReadReplicaCapable' then @db_instance_option[name] = to_boolean(value) + when 'Engine', 'LicenseModel', 'EngineVersion', 'DBInstanceClass' then @db_instance_option[name] = value + when 'AvailabilityZones' then @db_instance_option[name] = @availability_zones + when 'AvailabilityZone' then @availability_zones << @availability_zone unless @availability_zone.empty? + when 'Name' then @availability_zone[name] = value + when 'ProvisionedIopsCapable' then @availability_zone[name] = to_boolean(value) + when 'OrderableDBInstanceOption' + @db_instance_options << @db_instance_option + @db_instance_option = {} + when 'OrderableDBInstanceOptions' + @response['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'] = @db_instance_options + when 'Marker' then @response['DescribeOrderableDBInstanceOptionsResult'][name] = value + when 'RequestId' then @response['ResponseMetadata'][name] = value + end + end + + def to_boolean(v) + v =~ /\A\s*(true|yes|1|y)\s*$/i + end + end + end + end + end +end diff --git a/lib/fog/aws/rds.rb b/lib/fog/aws/rds.rb index bf4eb6f0c..77d35f911 100644 --- a/lib/fog/aws/rds.rb +++ b/lib/fog/aws/rds.rb @@ -51,6 +51,8 @@ module Fog request :describe_db_subnet_groups # TODO: :delete_db_subnet_group, :modify_db_subnet_group + request :describe_orderable_db_instance_options + model_path 'fog/aws/models/rds' model :server collection :servers diff --git a/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb b/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb new file mode 100644 index 000000000..2263efb42 --- /dev/null +++ b/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb @@ -0,0 +1,61 @@ +module Fog + module AWS + class RDS + class Real + + require 'fog/aws/parsers/rds/describe_orderable_db_instance_options' + + # Describe all or specified load db instances + # http://docs.amazonwebservices.com/AmazonRDS/latest/APIReference/API_DescribeDBInstances.html + # ==== Parameters + # * Engine <~String> - The name of the engine to retrieve DB Instance options for. Required. + # * Options <~Hash> - Hash of options. Optional. The following keys are used: + # * :db_instance_class <~String> - Filter available offerings matching the specified DB Instance class. Optional. + # * :engine_version <~String> - Filters available offerings matching the specified engine version. Optional. + # * :license_model <~String> - Filters available offerings matching the specified license model. Optional. + # * :marker <~String> - The pagination token provided in the previous request. If this parameter is specified the response includes only records beyond the marker, up to MaxRecords. Optional. + # * :max_records <~Integer> - The maximum number of records to include in the response. If more records exist, a pagination token is included in the response. Optional. + # * :vpc <~Boolean> - Filter to show only the available VPC or non-VPC offerings. Optional. + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + def describe_orderable_db_instance_options(engine=nil, opts={}) + params = {} + params['Engine'] = engine if engine + params['DBInstanceClass'] = opts[:db_instance_class] if opts[:db_instance_class] + params['EngineVersion'] = opts[:engine_version] if opts[:engine_version] + params['LicenseModel'] = opts[:license_model] if opts[:license_model] + params['Marker'] = opts[:marker] if opts[:marker] + params['MaxRecords'] = opts[:max_records] if opts[:max_records] + params['Vpc'] = opts[:vpc] if opts[:vpc] + + request({ + 'Action' => 'DescribeOrderableDBInstanceOptions', + :parser => Fog::Parsers::AWS::RDS::DescribeOrderableDBInstanceOptions.new + }.merge(params)) + end + + end + + class Mock + + def describe_orderable_db_instance_options(engine=nil, opts={}) + response = Excon::Response.new + if engine + # set up some mock data here... + else + raise Fog::AWS::RDS::NotFound.new('An engine must be specified to retrieve orderable instance options') + end + + response.status = 200 + response.body = { + 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id }, + 'DescribeOrderableDBInstanceOptionsResult' => { 'OrderableDBInstanceOptions' => [] } + } + response + end + + end + end + end +end From 460d2f8f01ca4bf1ab624a1c88b1ae2528627562 Mon Sep 17 00:00:00 2001 From: James Bence Date: Mon, 8 Jul 2013 15:41:24 -0700 Subject: [PATCH 2/7] Return boolean, not index of match. --- .../aws/parsers/rds/describe_orderable_db_instance_options.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb b/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb index 6d1ed7e83..13e8e5b97 100644 --- a/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb +++ b/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb @@ -38,7 +38,7 @@ module Fog end def to_boolean(v) - v =~ /\A\s*(true|yes|1|y)\s*$/i + (v =~ /\A\s*(true|yes|1|y)\s*$/i) == 0 end end end From 11de142ecfb8079afeea6f7cbc560bdf829f5e54 Mon Sep 17 00:00:00 2001 From: James Bence Date: Mon, 8 Jul 2013 17:19:20 -0700 Subject: [PATCH 3/7] Add model, collection for instance_options --- lib/fog/aws/models/rds/instance_option.rb | 21 +++++++++++++ lib/fog/aws/models/rds/instance_options.rb | 30 +++++++++++++++++++ .../describe_orderable_db_instance_options.rb | 2 +- lib/fog/aws/rds.rb | 5 ++++ .../describe_orderable_db_instance_options.rb | 19 ++++++++++-- lib/fog/core/collection.rb | 18 +++++++++++ 6 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 lib/fog/aws/models/rds/instance_option.rb create mode 100644 lib/fog/aws/models/rds/instance_options.rb diff --git a/lib/fog/aws/models/rds/instance_option.rb b/lib/fog/aws/models/rds/instance_option.rb new file mode 100644 index 000000000..4db63e75d --- /dev/null +++ b/lib/fog/aws/models/rds/instance_option.rb @@ -0,0 +1,21 @@ +require 'fog/core/model' + +module Fog + module AWS + class RDS + + class InstanceOption < Fog::Model + + attribute :multi_az_capable, :aliases => 'MultiAZCapable', :type => :boolean + attribute :engine, :aliases => 'Engine' + attribute :license_model, :aliases => 'LicenseModel' + attribute :read_replica_capable, :aliases => 'ReadReplicaCapable', :type => :boolean + attribute :engine_version, :aliases => 'EngineVersion' + attribute :availability_zones, :aliases => 'AvailabilityZones', :type => :array + attribute :db_instance_class, :aliases => 'DBInstanceClass' + attribute :vpc, :aliases => 'Vpc', :type => :boolean + + end + end + end +end diff --git a/lib/fog/aws/models/rds/instance_options.rb b/lib/fog/aws/models/rds/instance_options.rb new file mode 100644 index 000000000..363cd4a32 --- /dev/null +++ b/lib/fog/aws/models/rds/instance_options.rb @@ -0,0 +1,30 @@ +require 'fog/core/collection' +require 'fog/aws/models/rds/instance_option' + +module Fog + module AWS + class RDS + + class InstanceOptions < Fog::PagedCollection + attribute :filters + attribute :engine + model Fog::AWS::RDS::InstanceOption + + def initialize(attributes) + self.filters ||= {} + super + end + + # This method deliberately returns only a single page of results + def all(filters=filters) + self.filters.merge!(filters) + + result = service.describe_orderable_db_instance_options(engine, filters).body['DescribeOrderableDBInstanceOptionsResult'] + self.filters[:marker] = result['Marker'] + load(result['OrderableDBInstanceOptions']) + end + + end + end + end +end diff --git a/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb b/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb index 13e8e5b97..8535c9330 100644 --- a/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb +++ b/lib/fog/aws/parsers/rds/describe_orderable_db_instance_options.rb @@ -21,7 +21,7 @@ module Fog def end_element(name) case name - when 'MultiAZCapable', 'ReadReplicaCapable' then @db_instance_option[name] = to_boolean(value) + when 'MultiAZCapable', 'ReadReplicaCapable', 'Vpc' then @db_instance_option[name] = to_boolean(value) when 'Engine', 'LicenseModel', 'EngineVersion', 'DBInstanceClass' then @db_instance_option[name] = value when 'AvailabilityZones' then @db_instance_option[name] = @availability_zones when 'AvailabilityZone' then @availability_zones << @availability_zone unless @availability_zone.empty? diff --git a/lib/fog/aws/rds.rb b/lib/fog/aws/rds.rb index 77d35f911..1725a7abf 100644 --- a/lib/fog/aws/rds.rb +++ b/lib/fog/aws/rds.rb @@ -56,8 +56,10 @@ module Fog model_path 'fog/aws/models/rds' model :server collection :servers + model :snapshot collection :snapshots + model :parameter_group collection :parameter_groups @@ -70,6 +72,9 @@ module Fog model :subnet_group collection :subnet_groups + model :instance_option + collection :instance_options + class Mock def self.data diff --git a/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb b/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb index 2263efb42..3b0163fb1 100644 --- a/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb +++ b/lib/fog/aws/requests/rds/describe_orderable_db_instance_options.rb @@ -40,9 +40,24 @@ module Fog class Mock def describe_orderable_db_instance_options(engine=nil, opts={}) + instance_options = [] response = Excon::Response.new if engine - # set up some mock data here... + (opts[:db_instance_class] || %w(db.m2.xlarge db.m1.large)).each do |size| + instance_options << {'MultiAZCapable' => true, + 'Engine' => engine, + 'LicenseModel' => opts[:license_model] || 'general-public-license', + 'ReadReplicaCapable' => true, + 'EngineVersion' => opts[:engine_version] || '5.6.12', + 'AvailabilityZones' => [ + {'Name' => 'us-east-1b', 'ProvisionedIopsCapable' => true}, + {'Name' => 'us-east-1c', 'ProvisionedIopsCapable' => true}, + {'Name' => 'us-east-1d', 'ProvisionedIopsCapable' => false}, + {'Name' => 'us-east-1e', 'ProvisionedIopsCapable' => true}], + 'DBInstanceClass' => size, + 'Vpc' => opts[:vpc].nil? ? true : opts[:vpc]} + + end else raise Fog::AWS::RDS::NotFound.new('An engine must be specified to retrieve orderable instance options') end @@ -50,7 +65,7 @@ module Fog response.status = 200 response.body = { 'ResponseMetadata' => { 'RequestId' => Fog::AWS::Mock.request_id }, - 'DescribeOrderableDBInstanceOptionsResult' => { 'OrderableDBInstanceOptions' => [] } + 'DescribeOrderableDBInstanceOptionsResult' => { 'OrderableDBInstanceOptions' => instance_options } } response end diff --git a/lib/fog/core/collection.rb b/lib/fog/core/collection.rb index 993c9a729..b6770a6ed 100644 --- a/lib/fog/core/collection.rb +++ b/lib/fog/core/collection.rb @@ -142,4 +142,22 @@ module Fog end end + + # Base class for collection classes whose 'all' method returns only a single page of results and passes the + # 'Marker' option along as self.filters[:marker] + class PagedCollection < Collection + + def each(filters=filters) + if block_given? + begin + page = self.all(filters) + # We need to explicitly use the base 'each' method here on the page, otherwise we get infinite recursion + base_each = Fog::Collection.instance_method(:each) + base_each.bind(page).call { |item| yield item } + end while self.filters[:marker] + end + self + end + + end end From a8d2c362683d240d70655c7d47910e8f0bc432a6 Mon Sep 17 00:00:00 2001 From: James Bence Date: Wed, 10 Jul 2013 13:15:23 -0700 Subject: [PATCH 4/7] Use correct filters in RDS model instance_options 'all' method --- lib/fog/aws/models/rds/instance_options.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fog/aws/models/rds/instance_options.rb b/lib/fog/aws/models/rds/instance_options.rb index 363cd4a32..ededf6590 100644 --- a/lib/fog/aws/models/rds/instance_options.rb +++ b/lib/fog/aws/models/rds/instance_options.rb @@ -19,7 +19,7 @@ module Fog def all(filters=filters) self.filters.merge!(filters) - result = service.describe_orderable_db_instance_options(engine, filters).body['DescribeOrderableDBInstanceOptionsResult'] + result = service.describe_orderable_db_instance_options(engine, self.filters).body['DescribeOrderableDBInstanceOptionsResult'] self.filters[:marker] = result['Marker'] load(result['OrderableDBInstanceOptions']) end From 48327e462f6031db67a5b8df527d4f1776239d17 Mon Sep 17 00:00:00 2001 From: James Bence Date: Tue, 6 Aug 2013 16:46:03 -0700 Subject: [PATCH 5/7] Set up tests (and make them pass) for orderable_db_instance_options --- tests/aws/models/rds/instance_option_tests.rb | 14 +++++++++++ tests/aws/requests/rds/helper.rb | 22 ++++++++++++++++ .../aws/requests/rds/instance_option_tests.rb | 25 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 tests/aws/models/rds/instance_option_tests.rb create mode 100644 tests/aws/requests/rds/instance_option_tests.rb diff --git a/tests/aws/models/rds/instance_option_tests.rb b/tests/aws/models/rds/instance_option_tests.rb new file mode 100644 index 000000000..15d919a1f --- /dev/null +++ b/tests/aws/models/rds/instance_option_tests.rb @@ -0,0 +1,14 @@ +Shindo.tests("AWS::RDS | db instance options", ['aws', 'rds']) do + + params = {:engine => 'mysql'} + + pending if Fog.mocking? + + tests('#options') do + tests 'contains options' do + @instance = Fog::AWS[:rds].instance_options.new(params) + returns(true) { @instance.engine == 'mysql' } + end + end + +end diff --git a/tests/aws/requests/rds/helper.rb b/tests/aws/requests/rds/helper.rb index a78f99aa3..b41dee696 100644 --- a/tests/aws/requests/rds/helper.rb +++ b/tests/aws/requests/rds/helper.rb @@ -8,6 +8,11 @@ class AWS 'ResponseMetadata' => {'RequestId' => String} } + DB_AVAILABILITY_ZONE_OPTION = { + 'Name' => String, + 'ProvisionedIopsCapable' => Fog::Boolean + } + DB_PARAMETER_GROUP = { 'DBParameterGroupFamily' => String, 'DBParameterGroupName'=> String, @@ -79,6 +84,23 @@ class AWS } } + ORDERABLE_DB_INSTANCE_OPTION = { + 'MultiAZCapable' => Fog::Boolean, + 'Engine' => String, + 'LicenseModel' => String, + 'ReadReplicaCapable' => Fog::Boolean, + 'EngineVersion' => String, + 'AvailabilityZones' => [DB_AVAILABILITY_ZONE_OPTION], + 'DBInstanceClass' => String, + 'Vpc' => Fog::Boolean + } + + DESCRIBE_ORDERABLE_DB_INSTANCE_OPTION = BASIC.merge({ + 'DescribeOrderableDBInstanceOptionsResult' =>{ + 'OrderableDBInstanceOptions' => [ORDERABLE_DB_INSTANCE_OPTION] + } + }) + MODIFY_PARAMETER_GROUP = BASIC.merge({ 'ModifyDBParameterGroupResult' => { 'DBParameterGroupName' => String diff --git a/tests/aws/requests/rds/instance_option_tests.rb b/tests/aws/requests/rds/instance_option_tests.rb new file mode 100644 index 000000000..d84c4335b --- /dev/null +++ b/tests/aws/requests/rds/instance_option_tests.rb @@ -0,0 +1,25 @@ +Shindo.tests('AWS::RDS | db instance option requests', ['aws', 'rds']) do + tests('success') do + + tests("#describe_orderable_db_instance_options('mysql)").formats(AWS::RDS::Formats::DESCRIBE_ORDERABLE_DB_INSTANCE_OPTION) do + + body = Fog::AWS[:rds].describe_orderable_db_instance_options('mysql').body + + returns(100) {body['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'].length} + + group = body['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'].first + returns( true ) { group['MultiAZCapable'] } + returns( 'mysql' ) { group['Engine'] } + returns( true ) { group['ReadReplicaCapable'] } + returns( true ) { group['AvailabilityZones'].length >= 1 } + + body + end + + end + + tests("failures") do + raises(Fog::AWS::RDS::Error) {Fog::AWS[:rds].describe_orderable_db_instance_options('doesntexist')} + end + +end From c4965a71fdf726196f6b476129278fa219054b9f Mon Sep 17 00:00:00 2001 From: James Bence Date: Tue, 6 Aug 2013 17:17:26 -0700 Subject: [PATCH 6/7] Adjust number of items returned for test --- tests/aws/requests/rds/instance_option_tests.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/aws/requests/rds/instance_option_tests.rb b/tests/aws/requests/rds/instance_option_tests.rb index d84c4335b..7810e71c9 100644 --- a/tests/aws/requests/rds/instance_option_tests.rb +++ b/tests/aws/requests/rds/instance_option_tests.rb @@ -5,7 +5,7 @@ Shindo.tests('AWS::RDS | db instance option requests', ['aws', 'rds']) do body = Fog::AWS[:rds].describe_orderable_db_instance_options('mysql').body - returns(100) {body['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'].length} + returns(2) {body['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'].length} group = body['DescribeOrderableDBInstanceOptionsResult']['OrderableDBInstanceOptions'].first returns( true ) { group['MultiAZCapable'] } From 7236da30453fa085359510cdc34841ac2f0db5f8 Mon Sep 17 00:00:00 2001 From: James Bence Date: Tue, 6 Aug 2013 18:01:30 -0700 Subject: [PATCH 7/7] Remove failure test; non-existent engine sometimes has options --- tests/aws/requests/rds/instance_option_tests.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/aws/requests/rds/instance_option_tests.rb b/tests/aws/requests/rds/instance_option_tests.rb index 7810e71c9..95f780a3f 100644 --- a/tests/aws/requests/rds/instance_option_tests.rb +++ b/tests/aws/requests/rds/instance_option_tests.rb @@ -18,8 +18,4 @@ Shindo.tests('AWS::RDS | db instance option requests', ['aws', 'rds']) do end - tests("failures") do - raises(Fog::AWS::RDS::Error) {Fog::AWS[:rds].describe_orderable_db_instance_options('doesntexist')} - end - end