mirror of
https://github.com/fog/fog-aws.git
synced 2022-11-09 13:50:52 -05:00
commit
4c04799d24
8 changed files with 339 additions and 25 deletions
|
@ -120,6 +120,7 @@ module Fog
|
|||
request :describe_subnets
|
||||
request :describe_tags
|
||||
request :describe_volumes
|
||||
request :describe_volumes_modifications
|
||||
request :describe_volume_status
|
||||
request :describe_vpcs
|
||||
request :describe_vpc_attribute
|
||||
|
@ -140,6 +141,7 @@ module Fog
|
|||
request :modify_network_interface_attribute
|
||||
request :modify_snapshot_attribute
|
||||
request :modify_subnet_attribute
|
||||
request :modify_volume
|
||||
request :modify_volume_attribute
|
||||
request :modify_vpc_attribute
|
||||
request :move_address_to_vpc
|
||||
|
@ -290,6 +292,7 @@ module Fog
|
|||
}
|
||||
],
|
||||
:spot_requests => {},
|
||||
:volume_modifications => {}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,31 +36,50 @@ module Fog
|
|||
state == 'available'
|
||||
end
|
||||
|
||||
def modification_in_progress?
|
||||
modifications.any? { |m| m['modificationState'] != 'completed' }
|
||||
end
|
||||
|
||||
def modifications
|
||||
requires :identity
|
||||
service.describe_volumes_modifications('volume-id' => self.identity).body['volumeModificationSet']
|
||||
end
|
||||
|
||||
def save
|
||||
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted?
|
||||
requires :availability_zone
|
||||
requires_one :size, :snapshot_id
|
||||
if identity
|
||||
update_params = {
|
||||
'Size' => self.size,
|
||||
'Iops' => self.iops,
|
||||
'VolumeType' => self.type
|
||||
}
|
||||
|
||||
if type == 'io1'
|
||||
requires :iops
|
||||
service.modify_volume(self.identity, update_params)
|
||||
true
|
||||
else
|
||||
requires :availability_zone
|
||||
requires_one :size, :snapshot_id
|
||||
|
||||
if type == 'io1'
|
||||
requires :iops
|
||||
end
|
||||
|
||||
data = service.create_volume(availability_zone, size, create_params).body
|
||||
merge_attributes(data)
|
||||
|
||||
if tags = self.tags
|
||||
# expect eventual consistency
|
||||
Fog.wait_for { self.reload rescue nil }
|
||||
service.create_tags(
|
||||
self.identity,
|
||||
tags
|
||||
)
|
||||
end
|
||||
|
||||
if @server
|
||||
self.server = @server
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
data = service.create_volume(availability_zone, size, create_params).body
|
||||
merge_attributes(data)
|
||||
|
||||
if tags = self.tags
|
||||
# expect eventual consistency
|
||||
Fog.wait_for { self.reload rescue nil }
|
||||
service.create_tags(
|
||||
self.identity,
|
||||
tags
|
||||
)
|
||||
end
|
||||
|
||||
if @server
|
||||
self.server = @server
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def server
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
module Fog
|
||||
module Parsers
|
||||
module Compute
|
||||
module AWS
|
||||
class DescribeVolumesModifications < Fog::Parsers::Base
|
||||
def reset
|
||||
@response = { 'volumeModificationSet' => [] }
|
||||
@modification = {}
|
||||
end
|
||||
|
||||
def end_element(name)
|
||||
case name
|
||||
when 'modificationState', 'originalVolumeType', 'statusMessage', 'targetVolumeType', 'volumeId'
|
||||
@modification[name] = value
|
||||
when 'startTime', 'endTime'
|
||||
@modification[name] = Time.parse(value)
|
||||
when 'originalIops', 'originalSize', 'progress', 'targetIops', 'targetSize'
|
||||
@modification[name] = value.to_i
|
||||
when 'requestId'
|
||||
@response[name] = value
|
||||
when 'item'
|
||||
@response['volumeModificationSet'] << @modification.dup
|
||||
@modification = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
26
lib/fog/aws/parsers/compute/modify_volume.rb
Normal file
26
lib/fog/aws/parsers/compute/modify_volume.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
module Fog
|
||||
module Parsers
|
||||
module Compute
|
||||
module AWS
|
||||
class ModifyVolume < Fog::Parsers::Base
|
||||
def reset
|
||||
@response = {'volumeModification' => {}}
|
||||
end
|
||||
|
||||
def end_element(name)
|
||||
case name
|
||||
when 'modificationState', 'originalVolumeType', 'statusMessage', 'targetVolumeType', 'volumeId'
|
||||
@response['volumeModification'][name] = value
|
||||
when 'startTime', 'endTime'
|
||||
@response['volumeModification'][name] = Time.parse(value)
|
||||
when 'originalIops', 'originalSize', 'progress', 'targetIops', 'targetSize'
|
||||
@response['volumeModification'][name] = value.to_i
|
||||
when 'requestId'
|
||||
@response[name] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,93 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class AWS
|
||||
class Real
|
||||
require 'fog/aws/parsers/compute/describe_volumes_modifications'
|
||||
|
||||
# Reports the current modification status of EBS volumes.
|
||||
#
|
||||
# ==== Parameters
|
||||
# * filters<~Hash> - List of filters to limit results with
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * body<~Hash>
|
||||
# * 'volumeModificationSet'<~Array>:
|
||||
# * 'targetIops'<~Integer> - Target IOPS rate of the volume being modified.
|
||||
# * 'originalIops'<~Integer> - Original IOPS rate of the volume being modified.
|
||||
# * 'modificationState'<~String> - Current state of modification. Modification state is null for unmodified volumes.
|
||||
# * 'targetSize'<~Integer> - Target size of the volume being modified.
|
||||
# * 'targetVolumeType'<~String> - Target EBS volume type of the volume being modified.
|
||||
# * 'volumeId'<~String> - ID of the volume being modified.
|
||||
# * 'progress'<~Integer> - Modification progress from 0 to 100%.
|
||||
# * 'startTime'<~Time> - Modification start time
|
||||
# * 'endTime'<~Time> - Modification end time
|
||||
# * 'originalSize'<~Integer> - Original size of the volume being modified.
|
||||
# * 'originalVolumeType'<~String> - Original EBS volume type of the volume being modified.
|
||||
|
||||
def describe_volumes_modifications(filters = {})
|
||||
params = {}
|
||||
if volume_id = filters.delete('volume-id')
|
||||
params.merge!(Fog::AWS.indexed_param('VolumeId.%d', [*volume_id]))
|
||||
end
|
||||
params.merge!(Fog::AWS.indexed_filters(filters))
|
||||
request({
|
||||
'Action' => 'DescribeVolumesModifications',
|
||||
:idempotent => true,
|
||||
:parser => Fog::Parsers::Compute::AWS::DescribeVolumesModifications.new
|
||||
}.merge(params))
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def describe_volumes_modifications(filters = {})
|
||||
response = Excon::Response.new
|
||||
|
||||
modification_set = self.data[:volume_modifications].values
|
||||
|
||||
aliases = {
|
||||
'volume-id' => 'volumeId',
|
||||
'modification-state' => 'modificationState',
|
||||
'target-size' => 'targetSize',
|
||||
'target-iops' => 'targetIops',
|
||||
'target-volume-type' => 'targetVolumeType',
|
||||
'original-size' => 'originalSize',
|
||||
'original-iops' => 'originalIops',
|
||||
'original-volume-type' => 'originalVolumeType',
|
||||
'start-time' => 'startTime'
|
||||
}
|
||||
|
||||
attribute_aliases = {
|
||||
'targetSize' => 'size',
|
||||
'targetVolumeType' => 'volumeType',
|
||||
'targetIops' => 'iops'
|
||||
}
|
||||
|
||||
for filter_key, filter_value in filters
|
||||
aliased_key = aliases[filter_key]
|
||||
modification_set = modification_set.reject { |m| ![*filter_value].include?(m[aliased_key]) }
|
||||
end
|
||||
|
||||
modification_set.each do |modification|
|
||||
case modification['modificationState']
|
||||
when 'modifying'
|
||||
volume = self.data[:volumes][modification['volumeId']]
|
||||
modification['modificationState'] = 'optimizing'
|
||||
%w(targetSize targetIops targetVolumeType).each do |attribute|
|
||||
aliased_attribute = attribute_aliases[attribute]
|
||||
volume[aliased_attribute] = modification[attribute] if modification[attribute]
|
||||
end
|
||||
self.data[:volumes][modification['volumeId']] = volume
|
||||
when 'optimizing'
|
||||
modification['modificationState'] = 'completed'
|
||||
modification['endTime'] = Time.now
|
||||
end
|
||||
end
|
||||
|
||||
response.body = {'requestId' => Fog::AWS::Mock.request_id, 'volumeModificationSet' => modification_set}
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
88
lib/fog/aws/requests/compute/modify_volume.rb
Normal file
88
lib/fog/aws/requests/compute/modify_volume.rb
Normal file
|
@ -0,0 +1,88 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class AWS
|
||||
class Real
|
||||
require 'fog/aws/parsers/compute/modify_volume'
|
||||
|
||||
# Modifies a volume
|
||||
#
|
||||
# ==== Parameters
|
||||
# * volume_id<~String> - The ID of the volume
|
||||
# * options<~Hash>:
|
||||
# * 'VolumeType'<~String> - Type of volume
|
||||
# * 'Size'<~Integer> - Size in GiBs fo the volume
|
||||
# * 'Iops'<~Integer> - Number of IOPS the volume supports
|
||||
#
|
||||
# ==== Response
|
||||
# * response<~Excon::Response>:
|
||||
# * body<~Hash>:
|
||||
# * 'targetIops'<~Integer> - Target IOPS rate of the volume being modified.
|
||||
# * 'originalIops'<~Integer> - Original IOPS rate of the volume being modified.
|
||||
# * 'modificationState'<~String> - Current state of modification. Modification state is null for unmodified volumes.
|
||||
# * 'targetSize'<~Integer> - Target size of the volume being modified.
|
||||
# * 'targetVolumeType'<~String> - Target EBS volume type of the volume being modified.
|
||||
# * 'volumeId'<~String> - ID of the volume being modified.
|
||||
# * 'progress'<~Integer> - Modification progress from 0 to 100%.
|
||||
# * 'startTime'<~Time> - Modification start time
|
||||
# * 'endTime'<~Time> - Modification end time
|
||||
# * 'originalSize'<~Integer> - Original size of the volume being modified.
|
||||
# * 'originalVolumeType'<~String> - Original EBS volume type of the volume being modified.
|
||||
|
||||
def modify_volume(volume_id, options={})
|
||||
request({
|
||||
'Action' => "ModifyVolume",
|
||||
'VolumeId' => volume_id,
|
||||
:parser => Fog::Parsers::Compute::AWS::ModifyVolume.new
|
||||
}.merge(options))
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def modify_volume(volume_id, options={})
|
||||
response = Excon::Response.new
|
||||
volume = self.data[:volumes][volume_id]
|
||||
|
||||
if volume["volumeType"] == 'standard' && options['VolumeType']
|
||||
raise Fog::Compute::AWS::Error.new("InvalidParameterValue => Volume type EBS Magnetic is not supported.")
|
||||
end
|
||||
|
||||
volume_modification = {
|
||||
'modificationState' => 'modifying',
|
||||
'progress' => 0,
|
||||
'startTime' => Time.now,
|
||||
'volumeId' => volume_id
|
||||
}
|
||||
|
||||
if options['Size']
|
||||
volume_modification.merge!(
|
||||
'originalSize' => volume['size'],
|
||||
'targetSize' => options['Size']
|
||||
)
|
||||
end
|
||||
|
||||
if options['Iops']
|
||||
volume_modification.merge!(
|
||||
'originalIops' => volume['iops'],
|
||||
'targetIops' => options['Iops']
|
||||
)
|
||||
end
|
||||
|
||||
if options['VolumeType']
|
||||
if options["VolumeType"] == 'standard'
|
||||
raise Fog::Compute::AWS::Error.new("InvalidParameterValue => Volume type EBS Magnetic is not supported.")
|
||||
end
|
||||
volume_modification.merge!(
|
||||
'originalVolumeType' => volume['volumeType'],
|
||||
'targetVolumeType' => options['VolumeType']
|
||||
)
|
||||
end
|
||||
|
||||
self.data[:volume_modifications][volume_id] = volume_modification
|
||||
|
||||
response.body = {'volumeModification' => volume_modification, 'requestId' => Fog::AWS::Mock.request_id}
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,7 +3,7 @@ Shindo.tests("Fog::Compute[:aws] | volume", ['aws']) do
|
|||
@server = Fog::Compute[:aws].servers.create
|
||||
@server.wait_for { ready? }
|
||||
|
||||
model_tests(Fog::Compute[:aws].volumes, {:availability_zone => @server.availability_zone, :size => 1, :device => '/dev/sdz1', :tags => {"key" => "value"}}, true) do
|
||||
model_tests(Fog::Compute[:aws].volumes, {:availability_zone => @server.availability_zone, :size => 1, :device => '/dev/sdz1', :tags => {"key" => "value"}, :type => 'gp2'}, true) do
|
||||
|
||||
@instance.wait_for { ready? }
|
||||
|
||||
|
@ -32,6 +32,21 @@ Shindo.tests("Fog::Compute[:aws] | volume", ['aws']) do
|
|||
|
||||
@instance.wait_for { ready? }
|
||||
|
||||
@instance.type = 'io1'
|
||||
@instance.iops = 5000
|
||||
@instance.size = 100
|
||||
@instance.save
|
||||
|
||||
returns(true) { @instance.modification_in_progress? }
|
||||
@instance.wait_for { !modification_in_progress? }
|
||||
|
||||
# avoid weirdness with merge_attributes
|
||||
@instance = Fog::Compute[:aws].volumes.get(@instance.identity)
|
||||
|
||||
returns('io1') { @instance.type }
|
||||
returns(5000) { @instance.iops }
|
||||
returns(100) { @instance.size }
|
||||
|
||||
tests('@instance.reload.tags').returns({'key' => 'value'}) do
|
||||
@instance.reload.tags
|
||||
end
|
||||
|
|
|
@ -68,6 +68,29 @@ Shindo.tests('Fog::Compute[:aws] | volume requests', ['aws']) do
|
|||
'requestId' => String
|
||||
}
|
||||
|
||||
@volume_modification_format = {
|
||||
'endTime' => Fog::Nullable::Time,
|
||||
'modificationState' => String,
|
||||
'originalIops' => Fog::Nullable::Integer,
|
||||
'originalSize' => Fog::Nullable::Integer,
|
||||
'originalVolumeType' => Fog::Nullable::String,
|
||||
'startTime' => Time,
|
||||
'targetIops' => Fog::Nullable::Integer,
|
||||
'targetSize' => Fog::Nullable::Integer,
|
||||
'targetVolumeType' => Fog::Nullable::String,
|
||||
'volumeId' => String,
|
||||
}
|
||||
|
||||
@modify_volume_format = {
|
||||
'requestId' => String,
|
||||
'volumeModification' => @volume_modification_format
|
||||
}
|
||||
|
||||
@describe_volume_modifications_format = {
|
||||
'requestId' => String,
|
||||
'volumeModificationSet' => [@volume_modification_format]
|
||||
}
|
||||
|
||||
@server = Fog::Compute[:aws].servers.create
|
||||
@server.wait_for { ready? }
|
||||
|
||||
|
@ -113,13 +136,13 @@ Shindo.tests('Fog::Compute[:aws] | volume requests', ['aws']) do
|
|||
Fog::Compute[:aws].delete_volume(@volume_id)
|
||||
|
||||
tests('#create_volume from snapshot with size').formats(@volume_format) do
|
||||
volume = Fog::Compute[:aws].volumes.create(:availability_zone => 'us-east-1d', :size => 1)
|
||||
volume = Fog::Compute[:aws].volumes.create(:availability_zone => 'us-east-1d', :size => 1, :type => 'gp2')
|
||||
volume.wait_for { ready? }
|
||||
|
||||
snapshot = Fog::Compute[:aws].create_snapshot(volume.identity).body
|
||||
Fog::Compute[:aws].snapshots.new(snapshot).wait_for { ready? }
|
||||
|
||||
data = Fog::Compute[:aws].create_volume(@server.availability_zone, 1, 'SnapshotId' => snapshot['snapshotId']).body
|
||||
data = Fog::Compute[:aws].create_volume(@server.availability_zone, 1, 'SnapshotId' => snapshot['snapshotId'], 'VolumeType' => 'gp2').body
|
||||
@volume_id = data['volumeId']
|
||||
data
|
||||
end
|
||||
|
@ -155,6 +178,23 @@ Shindo.tests('Fog::Compute[:aws] | volume requests', ['aws']) do
|
|||
|
||||
Fog::Compute[:aws].volumes.get(@volume_id).wait_for { ready? }
|
||||
|
||||
tests("#modify_volume('#{@volume_id}', 'Size' => 100, 'VolumeType' => 'io1', 'Iops' => 5000").formats(@modify_volume_format) do
|
||||
Fog::Compute[:aws].modify_volume(@volume_id, 'Size' => 100, 'VolumeType' => 'io1', 'Iops' => 5000).body
|
||||
end
|
||||
|
||||
tests("#describe_volumes_modifications('volume-id' => '#{@volume_id}')").formats(@describe_volume_modifications_format) do
|
||||
Fog.wait_for do
|
||||
Fog::Compute[:aws].describe_volumes_modifications('volume-id' => @volume_id).body['volumeModificationSet'].first['modificationState'] == 'completed'
|
||||
end
|
||||
|
||||
volume = Fog::Compute[:aws].describe_volumes('volume-id' => @volume_id).body['volumeSet'].first
|
||||
returns(100) { volume['size'] }
|
||||
returns('io1') { volume['volumeType'] }
|
||||
returns(5000) { volume['iops'] }
|
||||
|
||||
Fog::Compute[:aws].describe_volumes_modifications('volume-id' => @volume_id).body
|
||||
end
|
||||
|
||||
tests("#modify_volume_attribute('#{@volume_id}', true)").formats(AWS::Compute::Formats::BASIC) do
|
||||
Fog::Compute[:aws].modify_volume_attribute(@volume_id, true).body
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue