From 47cac2b71b9bd3da24a6272bd87452bf9356caf4 Mon Sep 17 00:00:00 2001 From: Rodrigo Estebanez Date: Tue, 29 Nov 2011 19:40:36 +0100 Subject: [PATCH 1/6] mock create_db_instance --- lib/fog/aws.rb | 4 ++ lib/fog/aws/rds.rb | 37 +++++++++++++- .../aws/requests/rds/create_db_instance.rb | 51 ++++++++++++++++++- 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/lib/fog/aws.rb b/lib/fog/aws.rb index 48b78de34..bd5afdbfe 100644 --- a/lib/fog/aws.rb +++ b/lib/fog/aws.rb @@ -218,6 +218,10 @@ module Fog def self.volume_id "vol-#{Fog::Mock.random_hex(8)}" end + + def self.rds_address(db_name,region) + "#{db_name}.#{Fog::Mock.random_letters(rand(12) + 4)}.#{region}.rds.amazonaws.com" + end end end end diff --git a/lib/fog/aws/rds.rb b/lib/fog/aws/rds.rb index a4fe2af0d..88e9a973b 100644 --- a/lib/fog/aws/rds.rb +++ b/lib/fog/aws/rds.rb @@ -57,9 +57,42 @@ module Fog class Mock - def initialize(options={}) - Fog::Mock.not_implemented + def self.data + @data ||= Hash.new do |hash, region| + owner_id = Fog::AWS::Mock.owner_id + hash[region] = Hash.new do |region_hash, key| + region_hash[key] = { + :servers => {} + } + end + end end + + def self.reset + @data = nil + end + + def initialize(options={}) + + @aws_access_key_id = options[:aws_access_key_id] + + @region = options[:region] || 'us-east-1' + + unless ['ap-northeast-1', 'ap-southeast-1', 'eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2'].include?(@region) + raise ArgumentError, "Unknown region: #{@region.inspect}" + end + + end + + def data + self.class.data[@region][@aws_access_key_id] + end + + def reset_data + self.class.data[@region].delete(@aws_access_key_id) + end + + end diff --git a/lib/fog/aws/requests/rds/create_db_instance.rb b/lib/fog/aws/requests/rds/create_db_instance.rb index 9332f30f0..13f027cff 100644 --- a/lib/fog/aws/requests/rds/create_db_instance.rb +++ b/lib/fog/aws/requests/rds/create_db_instance.rb @@ -47,7 +47,56 @@ module Fog class Mock def create_db_instance(db_name, options={}) - Fog::Mock.not_implemented + response = Excon::Response.new + # These are the required parameters according to the API + required_params = %w{AllocatedStorage DBInstanceClass Engine MasterUserPassword MasterUsername } + required_params.each do |key| + unless options.has_key?(key) and options[key] and !options[key].to_s.empty? + response.status = 400 + #response.body['Message'] = "The request must contain the parameter #{key}" + response.body = { + 'Code' => 'MissingParameter' + } + response.body['Message'] = "The request must contain the parameter #{key}" + return response + end + end + + data = + {"CreateDBInstanceResult"=> + {"DBInstance"=> + {#"created_at" => Time.now, + "AutoMinorVersionUpgrade"=>true, + "Endpoint"=>{}, + "ReadReplicaDBInstanceIdentifiers"=>[], + "PreferredMaintenanceWindow"=>"mon:04:30-mon:05:00", + "Engine"=> options["Engine"], + "EngineVersion"=> options["EngineVersion"] || "5.1.57", + "PendingModifiedValues"=>{"MasterUserPassword"=>"****"}, + "MultiAZ"=>false, + "MasterUsername"=> options["MasterUsername"], + "DBInstanceClass"=> options["DBInstanceClass"], + "DBInstanceStatus"=>"creating", + "BackupRetentionPeriod"=> options["BackupRetentionPeriod"] || 1, + "DBInstanceIdentifier"=> db_name, + "AllocatedStorage"=> options["AllocatedStorage"], + "DBParameterGroups"=> # I think groups shoul be in the self.data method + [{"DBParameterGroupName"=>"default.mysql5.1", + "ParameterApplyStatus"=>"in-sync"}], + "DBSecurityGroups"=> + [{"Status"=>"active", + "DBSecurityGroupName"=>"default"}], + "LicenseModel"=>"general-public-license", + "PreferredBackupWindow"=>"08:00-08:30"}} + } + + + self.data[:servers][db_name] = data + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id } + }.merge!(data) + response.status = 200 + response end end From 735f8ec66cc038ab91a3842f967666f2f116e78c Mon Sep 17 00:00:00 2001 From: Rodrigo Estebanez Date: Wed, 30 Nov 2011 15:06:49 +0100 Subject: [PATCH 2/6] mocking describe_db_instance. Fix hash structure in create_db_instance --- .../aws/requests/rds/create_db_instance.rb | 12 ++++---- .../aws/requests/rds/describe_db_instances.rb | 30 ++++++++++++++++++- .../rds/describe_db_reserved_instances.rb | 2 +- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/lib/fog/aws/requests/rds/create_db_instance.rb b/lib/fog/aws/requests/rds/create_db_instance.rb index 13f027cff..b705cae16 100644 --- a/lib/fog/aws/requests/rds/create_db_instance.rb +++ b/lib/fog/aws/requests/rds/create_db_instance.rb @@ -63,9 +63,8 @@ module Fog end data = - {"CreateDBInstanceResult"=> - {"DBInstance"=> - {#"created_at" => Time.now, + { + #"created_at" => Time.now, "AutoMinorVersionUpgrade"=>true, "Endpoint"=>{}, "ReadReplicaDBInstanceIdentifiers"=>[], @@ -87,14 +86,15 @@ module Fog [{"Status"=>"active", "DBSecurityGroupName"=>"default"}], "LicenseModel"=>"general-public-license", - "PreferredBackupWindow"=>"08:00-08:30"}} + "PreferredBackupWindow"=>"08:00-08:30" } self.data[:servers][db_name] = data response.body = { - "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id } - }.merge!(data) + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "CreateDBInstanceResult"=> {"DBInstance"=> data} + } response.status = 200 response end diff --git a/lib/fog/aws/requests/rds/describe_db_instances.rb b/lib/fog/aws/requests/rds/describe_db_instances.rb index ea7bd34a1..49e7cbd93 100644 --- a/lib/fog/aws/requests/rds/describe_db_instances.rb +++ b/lib/fog/aws/requests/rds/describe_db_instances.rb @@ -33,7 +33,35 @@ module Fog class Mock def describe_db_instances(identifier=nil, opts={}) - Fog::Mock.not_implemented + response = Excon::Response.new + if identifier + if self.data[:servers].has_key?(identifier) + servers_set = self.data[:servers][identifier] + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBInstancesResult" => { "DBInstances" => [servers_set] } + } + + + else + response.status = 404 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBInstancesResult" => { "DBInstances" => 'DBInstanceNotFound' } + } + raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") + end + + else + servers_set = self.data[:servers].values + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBInstancesResult" => { "DBInstances" => servers_set } + } + end + response end end diff --git a/lib/fog/aws/requests/rds/describe_db_reserved_instances.rb b/lib/fog/aws/requests/rds/describe_db_reserved_instances.rb index cafbb502e..ab089110e 100644 --- a/lib/fog/aws/requests/rds/describe_db_reserved_instances.rb +++ b/lib/fog/aws/requests/rds/describe_db_reserved_instances.rb @@ -32,7 +32,7 @@ module Fog class Mock - def describe_db_instances(identifier=nil, opts={}) + def describe_db_reserved_instances(identifier=nil, opts={}) Fog::Mock.not_implemented end From 077ddc41edc216cf4527af84c72699fcb5c5004f Mon Sep 17 00:00:00 2001 From: Rodrigo Estebanez Date: Wed, 30 Nov 2011 17:19:05 +0100 Subject: [PATCH 3/6] mocking delete_db_instance --- .../aws/requests/rds/delete_db_instance.rb | 22 ++++++++++++++++--- .../aws/requests/rds/describe_db_instances.rb | 12 ++-------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/fog/aws/requests/rds/delete_db_instance.rb b/lib/fog/aws/requests/rds/delete_db_instance.rb index 0c5979b21..170181f72 100644 --- a/lib/fog/aws/requests/rds/delete_db_instance.rb +++ b/lib/fog/aws/requests/rds/delete_db_instance.rb @@ -15,7 +15,7 @@ module Fog # ==== Returns # * response<~Excon::Response>: # * body<~Hash>: - def delete_db_instance(identifier, snapshot_identifier, skip_snapshot = false) + def delete_db_instance(identifier, snapshot_identifier, skip_snapshot = false) params = {} params['FinalDBSnapshotIdentifier'] = snapshot_identifier if snapshot_identifier request({ @@ -30,8 +30,24 @@ module Fog class Mock - def delete_db_snapshot(identifier, snapshot_identifier, skip_snapshot = false) - Fog::Mock.not_implemented + def delete_db_instance(identifier, snapshot_identifier, skip_snapshot = false) + response = Excon::Response.new + + unless skip_snapshot + # I don't know how to mock snapshot_identifier + Fog::Logger.warning("snapshot_identifier is not mocked [light_black](#{caller.first})[/]") + end + + if server_set = self.data[:servers].delete(identifier) + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DeleteDBInstanceResult" => { "DBInstance" => server_set } + } + response + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") + end end end diff --git a/lib/fog/aws/requests/rds/describe_db_instances.rb b/lib/fog/aws/requests/rds/describe_db_instances.rb index 49e7cbd93..a84c54535 100644 --- a/lib/fog/aws/requests/rds/describe_db_instances.rb +++ b/lib/fog/aws/requests/rds/describe_db_instances.rb @@ -35,21 +35,13 @@ module Fog def describe_db_instances(identifier=nil, opts={}) response = Excon::Response.new if identifier - if self.data[:servers].has_key?(identifier) - servers_set = self.data[:servers][identifier] + if server_set = self.data[:servers][identifier] response.status = 200 response.body = { "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, - "DescribeDBInstancesResult" => { "DBInstances" => [servers_set] } + "DescribeDBInstancesResult" => { "DBInstances" => [server_set] } } - - else - response.status = 404 - response.body = { - "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, - "DescribeDBInstancesResult" => { "DBInstances" => 'DBInstanceNotFound' } - } raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") end From 17885d5c82d7b97c618e0670ebf71a4f57ff4a53 Mon Sep 17 00:00:00 2001 From: Rodrigo Estebanez Date: Wed, 30 Nov 2011 20:38:10 +0100 Subject: [PATCH 4/6] mocking wait_for through describe_db_instances --- .../aws/requests/rds/create_db_instance.rb | 9 ++-- .../aws/requests/rds/describe_db_instances.rb | 43 ++++++++++++------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/lib/fog/aws/requests/rds/create_db_instance.rb b/lib/fog/aws/requests/rds/create_db_instance.rb index b705cae16..4fe21d287 100644 --- a/lib/fog/aws/requests/rds/create_db_instance.rb +++ b/lib/fog/aws/requests/rds/create_db_instance.rb @@ -64,20 +64,21 @@ module Fog data = { - #"created_at" => Time.now, + "DBInstanceIdentifier"=> db_name, + "DBName" => options["DBName"], + "created_at" => nil, "AutoMinorVersionUpgrade"=>true, "Endpoint"=>{}, "ReadReplicaDBInstanceIdentifiers"=>[], "PreferredMaintenanceWindow"=>"mon:04:30-mon:05:00", "Engine"=> options["Engine"], "EngineVersion"=> options["EngineVersion"] || "5.1.57", - "PendingModifiedValues"=>{"MasterUserPassword"=>"****"}, + "PendingModifiedValues"=>{}, "MultiAZ"=>false, "MasterUsername"=> options["MasterUsername"], "DBInstanceClass"=> options["DBInstanceClass"], "DBInstanceStatus"=>"creating", "BackupRetentionPeriod"=> options["BackupRetentionPeriod"] || 1, - "DBInstanceIdentifier"=> db_name, "AllocatedStorage"=> options["AllocatedStorage"], "DBParameterGroups"=> # I think groups shoul be in the self.data method [{"DBParameterGroupName"=>"default.mysql5.1", @@ -96,6 +97,8 @@ module Fog "CreateDBInstanceResult"=> {"DBInstance"=> data} } response.status = 200 + # This values aren't showed at creating time but at available time + self.data[:servers][db_name]["created_at"] = Time.now response end diff --git a/lib/fog/aws/requests/rds/describe_db_instances.rb b/lib/fog/aws/requests/rds/describe_db_instances.rb index a84c54535..4b55e8848 100644 --- a/lib/fog/aws/requests/rds/describe_db_instances.rb +++ b/lib/fog/aws/requests/rds/describe_db_instances.rb @@ -34,27 +34,38 @@ module Fog def describe_db_instances(identifier=nil, opts={}) response = Excon::Response.new - if identifier - if server_set = self.data[:servers][identifier] - response.status = 200 - response.body = { - "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, - "DescribeDBInstancesResult" => { "DBInstances" => [server_set] } - } + server_set = [] + if identifier + if server = self.data[:servers][identifier] + server_set << server else raise Fog::AWS::RDS::NotFound.new("DBInstance #{identifier} not found") - end - - else - servers_set = self.data[:servers].values - response.status = 200 - response.body = { - "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, - "DescribeDBInstancesResult" => { "DBInstances" => servers_set } - } + end end + server_set = self.data[:servers].values + + server_set.each do |server| + case server["DBInstanceStatus"] + when "creating" + if Time.now - server['created_at'] >= Fog::Mock.delay * 2 + region = "us-east-1" + server["DBInstanceStatus"] = "available" + server["availability_zone"] = region + 'a' + server["Endpoint"] = {"Port"=>3306, + "Address"=> Fog::AWS::Mock.rds_address(server["DBInstanceIdentifier"],region) } + server["PendingModifiedValues"] = {"MasterUserPassword"=>"****"} + end + end + end + + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "DescribeDBInstancesResult" => { "DBInstances" => server_set } + } response end + end end From d83ea87732dd2d11cb7ac816d3b95b2125af7157 Mon Sep 17 00:00:00 2001 From: Rodrigo Estebanez Date: Thu, 1 Dec 2011 01:08:28 +0100 Subject: [PATCH 5/6] mocking modify_db_instance and reboot_db_instance --- .../aws/requests/rds/create_db_instance.rb | 2 +- .../aws/requests/rds/describe_db_instances.rb | 9 ++++++- .../aws/requests/rds/modify_db_instance.rb | 25 ++++++++++++++++++- .../aws/requests/rds/reboot_db_instance.rb | 18 ++++++++++++- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/lib/fog/aws/requests/rds/create_db_instance.rb b/lib/fog/aws/requests/rds/create_db_instance.rb index 4fe21d287..3c6f64001 100644 --- a/lib/fog/aws/requests/rds/create_db_instance.rb +++ b/lib/fog/aws/requests/rds/create_db_instance.rb @@ -73,7 +73,7 @@ module Fog "PreferredMaintenanceWindow"=>"mon:04:30-mon:05:00", "Engine"=> options["Engine"], "EngineVersion"=> options["EngineVersion"] || "5.1.57", - "PendingModifiedValues"=>{}, + "PendingModifiedValues"=>{"MasterUserPassword"=>"****"}, # This clears when is available "MultiAZ"=>false, "MasterUsername"=> options["MasterUsername"], "DBInstanceClass"=> options["DBInstanceClass"], diff --git a/lib/fog/aws/requests/rds/describe_db_instances.rb b/lib/fog/aws/requests/rds/describe_db_instances.rb index 4b55e8848..7e1f0a63b 100644 --- a/lib/fog/aws/requests/rds/describe_db_instances.rb +++ b/lib/fog/aws/requests/rds/describe_db_instances.rb @@ -53,8 +53,15 @@ module Fog server["availability_zone"] = region + 'a' server["Endpoint"] = {"Port"=>3306, "Address"=> Fog::AWS::Mock.rds_address(server["DBInstanceIdentifier"],region) } - server["PendingModifiedValues"] = {"MasterUserPassword"=>"****"} + server["PendingModifiedValues"] = {} end + when "rebooting" + # it applies pending modified values + if server["PendingModifiedValues"] + server.merge!(server["PendingModifiedValues"]) + server["PendingModifiedValues"] = {} + server["DBInstanceStatus"] = 'available' + end end end diff --git a/lib/fog/aws/requests/rds/modify_db_instance.rb b/lib/fog/aws/requests/rds/modify_db_instance.rb index c6e51282e..abfe64467 100644 --- a/lib/fog/aws/requests/rds/modify_db_instance.rb +++ b/lib/fog/aws/requests/rds/modify_db_instance.rb @@ -45,7 +45,30 @@ module Fog class Mock def modify_db_instance(db_name, apply_immediately, options={}) - Fog::Mock.not_implemented + response = Excon::Response.new + if server = self.data[:servers][db_name] + if server["DBInstanceStatus"] != "available" + raise Fog::AWS::RDS::NotFound.new("DBInstance #{db_name} not available for modification") + else + # TODO verify the params options + # if apply_immediately is false, all the options go to pending_modified_values and then apply and clear after either + # a reboot or the maintainance window + if apply_immediately + modified_server = server.merge(options) + else + modified_server = server["PendingModifiedValues"].merge!(options) # it appends + end + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "ModifyDBInstanceResult" => { "DBInstance" => modified_server } + } + response + + end + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{db_name} not found") + end end end diff --git a/lib/fog/aws/requests/rds/reboot_db_instance.rb b/lib/fog/aws/requests/rds/reboot_db_instance.rb index 7d54b70a8..ef04120bd 100644 --- a/lib/fog/aws/requests/rds/reboot_db_instance.rb +++ b/lib/fog/aws/requests/rds/reboot_db_instance.rb @@ -25,7 +25,23 @@ module Fog class Mock def reboot_db_instance(instance_identifier) - Fog::Mock.not_implemented + response = Excon::Response.new + if server = self.data[:servers][instance_identifier] + if server["DBInstanceStatus"] != "available" + raise Fog::AWS::RDS::NotFound.new("DBInstance #{db_name} not available for rebooting") + else + server["DBInstanceStatus"] = 'rebooting' + response.status = 200 + response.body = { + "ResponseMetadata"=>{ "RequestId"=> Fog::AWS::Mock.request_id }, + "RebootDBInstanceResult" => { "DBInstance" => server } + } + response + + end + else + raise Fog::AWS::RDS::NotFound.new("DBInstance #{db_name} not found") + end end end From a8468de64c1d394a35b2c2a6c90602b3af1e63d0 Mon Sep 17 00:00:00 2001 From: Rodrigo Estebanez Date: Fri, 2 Dec 2011 10:36:10 +0100 Subject: [PATCH 6/6] raise exception instead of excon response --- .../aws/requests/rds/create_db_instance.rb | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/fog/aws/requests/rds/create_db_instance.rb b/lib/fog/aws/requests/rds/create_db_instance.rb index 3c6f64001..8879e2ec4 100644 --- a/lib/fog/aws/requests/rds/create_db_instance.rb +++ b/lib/fog/aws/requests/rds/create_db_instance.rb @@ -48,17 +48,28 @@ module Fog def create_db_instance(db_name, options={}) response = Excon::Response.new + if self.data[:servers] and self.data[:servers][db_name] + # I don't know how to raise an exception that contains the excon data + #response.status = 400 + #response.body = { + # 'Code' => 'DBInstanceAlreadyExists', + # 'Message' => "DB Instance already exists" + #} + #return response + raise Fog::AWS::RDS::IdentifierTaken.new("DBInstanceAlreadyExists #{response.body.to_s}") + end + # These are the required parameters according to the API required_params = %w{AllocatedStorage DBInstanceClass Engine MasterUserPassword MasterUsername } required_params.each do |key| unless options.has_key?(key) and options[key] and !options[key].to_s.empty? - response.status = 400 - #response.body['Message'] = "The request must contain the parameter #{key}" - response.body = { - 'Code' => 'MissingParameter' - } - response.body['Message'] = "The request must contain the parameter #{key}" - return response + #response.status = 400 + #response.body = { + # 'Code' => 'MissingParameter', + # 'Message' => "The request must contain the parameter #{key}" + #} + #return response + raise Fog::AWS::RDS::NotFound.new("The request must contain the parameter #{key}") end end