1
0
Fork 0
mirror of https://github.com/fog/fog-aws.git synced 2022-11-09 13:50:52 -05:00

restore db instance fom db snapshot

* add mock
* add restore method on servers collection
* modify save method on server model
* raise error when multi_az and az are set
* cannot specify multi_az to be true and pick an az together
* take allocated_storage from snapshot on restore
* restore from snapshot endpoint does not take
* allocated_storage parameter
* save storage type on rds snapshot
This commit is contained in:
Michelle Noorali 2015-07-10 18:25:26 -07:00 committed by Eugene Howe
parent b823dbf522
commit 646492d153
12 changed files with 181 additions and 71 deletions

View file

@ -38,7 +38,7 @@ module Fog
attribute :tde_credential_arn, :aliases => 'TdeCredentialArn'
attribute :vpc_security_groups, :aliases => 'VpcSecurityGroups', :type => :array
attr_accessor :password, :parameter_group_name, :security_group_names, :port
attr_accessor :password, :parameter_group_name, :security_group_names, :port, :source_snapshot_id
def create_read_replica(replica_id, options={})
options[:security_group_names] ||= options['DBSecurityGroups']
@ -104,16 +104,22 @@ module Fog
end
def save
requires :engine
requires :allocated_storage
requires :master_username
requires :password
if source_snapshot_id
requires :id
data = service.restore_db_instance_from_db_snapshot(source_snapshot_id, id, attributes_to_params)
merge_attributes(data.body['RestoreDBInstanceFromDBSnapshotResult']['DBInstance'])
else
requires :engine
requires :allocated_storage
requires :master_username
requires :password
self.flavor_id ||= 'db.m1.small'
self.flavor_id ||= 'db.m1.small'
data = service.create_db_instance(id, attributes_to_params)
merge_attributes(data.body['CreateDBInstanceResult']['DBInstance'])
true
data = service.create_db_instance(id, attributes_to_params)
merge_attributes(data.body['CreateDBInstanceResult']['DBInstance'])
true
end
end
# Converts attributes to a parameter hash suitable for requests

View file

@ -17,6 +17,10 @@ module Fog
rescue Fog::AWS::RDS::NotFound
nil
end
def restore(options)
create(options)
end
end
end
end

View file

@ -12,6 +12,7 @@ module Fog
attribute :state, :aliases => 'Status'
attribute :port, :aliases => 'Port', :type => :integer
attribute :allocated_storage, :aliases => 'AllocatedStorage', :type => :integer
attribute :storage_type, :aliases => 'StorageType', :type => :string
attribute :iops, :aliases => 'Iops', :type => :integer
attribute :availability_zone, :aliases => 'AvailabilityZone'
attribute :type, :aliases => 'SnapshotType'

View file

@ -6,7 +6,7 @@ module Fog
class RestoreDBInstanceFromDBSnapshot < Fog::Parsers::AWS::RDS::DbParser
def reset
@response = { 'RestoreDBInstanceFromDBSnapshot' => {}, 'ResponseMetadata' => {} }
@response = { 'RestoreDBInstanceFromDBSnapshotResult' => {}, 'ResponseMetadata' => {} }
super
end
@ -17,7 +17,7 @@ module Fog
def end_element(name)
case name
when 'DBInstance'
@response['RestoreDBInstanceFromDBSnapshot']['DBInstance'] = @db_instance
@response['RestoreDBInstanceFromDBSnapshotResult']['DBInstance'] = @db_instance
@db_instance = fresh_instance
when 'RequestId'
@response['ResponseMetadata'][name] = value

View file

@ -65,7 +65,7 @@ module Fog
end
# These are the required parameters according to the API
required_params = %w{AllocatedStorage DBInstanceClass Engine MasterUserPassword MasterUsername }
required_params = %w{AllocatedStorage DBInstanceClass Engine MasterUsername }
required_params.each do |key|
unless options.key?(key) and options[key] and !options[key].to_s.empty?
#response.status = 400

View file

@ -45,7 +45,7 @@ module Fog
'InstanceCreateTime' => Time.now
}
# Copy attributes from server
%w(Engine EngineVersion AvailabilityZone AllocatedStorage Iops MasterUsername InstanceCreateTime).each do |key|
%w(Engine EngineVersion AvailabilityZone AllocatedStorage StorageType Iops MasterUsername InstanceCreateTime).each do |key|
snapshot_data[key] = server_data[key]
end
snapshot_data['Port'] = server_data['Endpoint']['Port']

View file

@ -47,60 +47,62 @@ module Fog
class Mock
def modify_db_instance(db_name, apply_immediately, _options={})
options = _options.dup
options = _options
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
self.data[:modify_time] = Time.now
# 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
if options["NewDBInstanceIdentifier"]
options["DBInstanceIdentifier"] = options.delete("NewDBInstanceIdentifier")
end
server = self.data[:servers][db_name]
rds_security_groups = self.data[:security_groups].values
ec2_security_groups = Fog::Compute::AWS::Mock.data[@region][@aws_access_key_id][:security_groups].values
if server.nil?
db_security_group_names = Array(options.delete("DBSecurityGroups"))
db_security_groups = db_security_group_names.inject([]) do |r, group_name|
unless rds_security_groups.find { |sg| sg["DBSecurityGroupName"] == group_name }
raise Fog::AWS::RDS::Error.new("InvalidParameterValue => Invalid security group , groupId= , groupName=#{group_name}")
end
r << {"Status" => "active", "DBSecurityGroupName" => group_name }
end
vpc_security_groups = Array(options.delete("VpcSecurityGroups")).inject([]) do |r, group_id|
unless ec2_security_groups.find { |sg| sg["groupId"] == group_id }
raise Fog::AWS::RDS::Error.new("InvalidParameterValue => Invalid security group , groupId=#{group_id} , groupName=")
end
r << {"Status" => "active", "VpcSecurityGroupId" => group_id }
end
options.merge!(
"DBSecurityGroups" => db_security_groups,
"VpcSecurityGroups" => vpc_security_groups
)
self.data[:servers][db_name]["PendingModifiedValues"].merge!(options) # it appends
self.data[:servers][db_name]["DBInstanceStatus"] = "modifying"
response.status = 200
response.body = {
"ResponseMetadata" => { "RequestId" => Fog::AWS::Mock.request_id },
"ModifyDBInstanceResult" => { "DBInstance" => self.data[:servers][db_name] }
}
response
end
else
raise Fog::AWS::RDS::NotFound.new("DBInstance #{db_name} not found")
end
if server["DBInstanceStatus"] != "available"
raise Fog::AWS::RDS::NotFound.new("DBInstance #{db_name} not available for modification")
end
db_security_group_names = Array(options.delete("DBSecurityGroups"))
rds_security_groups = self.data[:security_groups].values
db_security_groups = db_security_group_names.map do |r, group_name|
unless rds_security_groups.find { |sg| sg["DBSecurityGroupName"] == group_name }
raise Fog::AWS::RDS::Error.new("InvalidParameterValue => Invalid security group , groupId= , groupName=#{group_name}")
end
r << {"Status" => "active", "DBSecurityGroupName" => group_name }
end
ec2_security_groups = Fog::Compute::AWS::Mock.data[@region][@aws_access_key_id][:security_groups].values
vpc_security_groups = Array(options.delete("VpcSecurityGroups")).map do |group_id|
unless ec2_security_groups.find { |sg| sg["groupId"] == group_id }
raise Fog::AWS::RDS::Error.new("InvalidParameterValue => Invalid security group , groupId=#{group_id} , groupName=")
end
{"Status" => "active", "VpcSecurityGroupId" => group_id }
end
options.merge!(
"DBSecurityGroups" => db_security_groups,
"VpcSecurityGroups" => vpc_security_groups
)
if options["NewDBInstanceIdentifier"]
options["DBInstanceIdentifier"] = options.delete("NewDBInstanceIdentifier")
end
self.data[:modify_time] = Time.now
server["PendingModifiedValues"].merge!(options)
server["DBInstanceStatus"] = "modifying"
response.status = 200
response.body = {
"ResponseMetadata" => { "RequestId" => Fog::AWS::Mock.request_id },
"ModifyDBInstanceResult" => { "DBInstance" => server }
}
response
end
end
end

View file

@ -20,8 +20,69 @@ module Fog
end
class Mock
def restore_db_instance_from_db_snapshot(snapshot_id, db_id, options={})
Fog::Mock.not_implemented
def restore_db_instance_from_db_snapshot(snapshot_id, db_name, options={})
if self.data[:servers] and self.data[:servers][db_name]
raise Fog::AWS::RDS::IdentifierTaken.new("DBInstanceAlreadyExists #{response.body.to_s}")
end
unless self.data[:snapshots] and snapshot = self.data[:snapshots][snapshot_id]
raise Fog::AWS::RDS::NotFound.new("DBSnapshotNotFound #{response.body.to_s}")
end
if !!options["MultiAZ"] && !!options["AvailabilityZone"]
raise Fog::AWS::RDS::InvalidParameterCombination.new('Requesting a specific availability zone is not valid for Multi-AZ instances.')
end
option_group_membership =
if option_group_name = options['OptionGroupName']
[{ 'OptionGroupMembership' =>
[{ 'OptionGroupName' => option_group_name, 'Status' => "pending-apply"}] }]
else
[{ 'OptionGroupMembership' =>
[{ 'OptionGroupName' => 'default: mysql-5.6', 'Status' => "pending-apply"}] }]
end
data = {
"AllocatedStorage" => snapshot['AllocatedStorage'],
"AutoMinorVersionUpgrade" => options['AutoMinorVersionUpgrade'].nil? ? true : options['AutoMinorVersionUpgrade'],
"AvailabilityZone" => options['AvailabilityZone'],
"BackupRetentionPeriod" => options['BackupRetentionPeriod'] || 1,
"CACertificateIdentifier" => 'rds-ca-2015',
"DBInstanceClass" => options['DBInstanceClass'] || 'db.m3.medium',
"DBInstanceIdentifier" => db_name,
"DBInstanceStatus" => 'creating',
"DBName" => options['DBName'],
"DBParameterGroups" => [{'DBParameterGroupName'=>'default.mysql5.5', 'ParameterApplyStatus'=>'in-sync'}],
"DBSecurityGroups" => [{'Status'=>'active', 'DBSecurityGroupName'=>'default'}],
"Endpoint" => {},
"Engine" => options['Engine'] || snapshot['Engine'],
"EngineVersion" => options['EngineVersion'] || snapshot['EngineVersion'],
"InstanceCreateTime" => nil,
"Iops" => options['Iops'],
"LicenseModel" => options['LicenseModel'] || snapshot['LicenseModel'] || 'general-public-license',
"MasterUsername" => options['MasterUsername'] || snapshot['MasterUsername'],
"MultiAZ" => options['MultiAZ'],
"OptiongroupMemberships" => option_group_membership,
"PendingModifiedValues" => { 'MasterUserPassword' => '****' }, # This clears when is available
"PreferredBackupWindow" => '08:00-08:30',
"PreferredMaintenanceWindow" => 'mon:04:30-mon:05:00',
"PubliclyAccessible" => true,
"ReadReplicaDBInstanceIdentifiers" => [],
"StorageType" => options['StorageType'] || (options['Iops'] ? 'io1' : 'standard'),
"VpcSecurityGroups" => nil,
"StorageEncrypted" => false,
}
self.data[:servers][db_name] = data
response = Excon::Response.new
response.body =
{ "ResponseMetadata" => { "RequestId" => Fog::AWS::Mock.request_id },
"RestoreDBInstanceFromDBSnapshotResult" => { "DBInstance" => data }
}
response.status = 200
self.data[:servers][db_name]["InstanceCreateTime"] = Time.now
response
end
end
end

View file

@ -6,6 +6,7 @@ Shindo.tests("AWS::RDS | server", ['aws', 'rds']) do
@instance.wait_for(20*60) { ready? }
@instance_with_encrypted_storage.wait_for(20*60) { ready? }
@final_snapshot_id = uniq_id('fog-test-snapshot')
tests("#storage_encrypted") do
returns(true) { @instance_with_encrypted_storage.storage_encrypted }
@ -114,12 +115,11 @@ Shindo.tests("AWS::RDS | server", ['aws', 'rds']) do
replica && replica.destroy
test("Destroying with a final snapshot") do
final_snapshot_id = uniq_id('fog-test-snapshot')
@instance_with_final_snapshot.wait_for { ready? }
@instance_with_final_snapshot.destroy(final_snapshot_id)
@instance_with_final_snapshot.destroy(@final_snapshot_id)
returns(true, "Final snapshot created") do
@final_snapshot = Fog::AWS[:rds].snapshots.get(final_snapshot_id)
@final_snapshot = Fog::AWS[:rds].snapshots.get(@final_snapshot_id)
!@final_snapshot.nil?
end

View file

@ -3,4 +3,22 @@ Shindo.tests("AWS::RDS | servers", ['aws', 'rds']) do
collection_tests(Fog::AWS[:rds].servers, rds_default_server_params) do
@instance.wait_for { ready? }
end
tests("#restore").succeeds do
instance = Fog::AWS[:rds].servers.create(rds_default_server_params.merge(:id => uniq_id("fog-snapshot-test")))
snapshot_id = uniq_id('fog-snapshot-test')
@snapshot = instance.snapshots.create(:id => snapshot_id )
instance.destroy
db_name = uniq_id('fog-db-name')
@restore_instance = Fog::AWS[:rds].servers.restore(snapshot_id, db_name, {'master_username' => instance.master_username, 'flavor_id' => 'db.m3.medium'})
end
if Fog.mocking? && @restore_instance.respond_to?(:ready?)
@restore_instance.wait_for { ready? }
end
@snapshot.destroy
@restore_instance.destroy
end

View file

@ -311,6 +311,12 @@ class AWS
'DBEngineVersions' => [DB_ENGINE_VERSION]
}
)
RESTORE_DB_INSTANCE_FROM_DB_SNAPSHOT = BASIC.merge({
'RestoreDBInstanceFromDBSnapshotResult' => {
'DBInstance' => INSTANCE
}
})
end
end
end

View file

@ -5,10 +5,11 @@ Shindo.tests('AWS::RDS | instance requests', ['aws', 'rds']) do
# serveral minutes for deleted servers to disappear
suffix = rand(65536).to_s(16)
@db_instance_id = "fog-test-#{suffix}"
@db_replica_id = "fog-replica-#{suffix}"
@db_snapshot_id = "fog-snapshot-#{suffix}"
@db_final_snapshot_id = "fog-final-snapshot-#{suffix}"
@db_instance_id = "fog-test-#{suffix}"
@db_replica_id = "fog-replica-#{suffix}"
@db_snapshot_id = "fog-snapshot-#{suffix}"
@db_final_snapshot_id = "fog-final-snapshot-#{suffix}"
@db_instance_restore_id = "fog-test-#{suffix}"
tests('success') do
@ -109,6 +110,17 @@ Shindo.tests('AWS::RDS | instance requests', ['aws', 'rds']) do
body
end
tests("#restore_db_instance_from_db_snapshot").formats(AWS::RDS::Formats::RESTORE_DB_INSTANCE_FROM_DB_SNAPSHOT) do
snapshot = Fog::AWS[:rds].snapshots.get(@db_final_snapshot_id)
snapshot.wait_for { state == 'available' }
result = Fog::AWS[:rds].restore_db_instance_from_db_snapshot(@db_final_snapshot_id, @db_instance_restore_id).body
instance = result['RestoreDBInstanceFromDBSnapshotResult']['DBInstance']
returns('creating') { instance['DBInstanceStatus'] }
result
end
restore_server = Fog::AWS[:rds].servers.get(@db_instance_restore_id)
restore_server.wait_for { state == 'available' }
tests("#delete_db_snapshot").formats(AWS::RDS::Formats::DELETE_DB_SNAPSHOT) do
Fog::AWS[:rds].snapshots.get(@db_snapshot_id).wait_for { ready? }
Fog::AWS[:rds].delete_db_snapshot(@db_snapshot_id).body