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_subnets
|
||||||
request :describe_tags
|
request :describe_tags
|
||||||
request :describe_volumes
|
request :describe_volumes
|
||||||
|
request :describe_volumes_modifications
|
||||||
request :describe_volume_status
|
request :describe_volume_status
|
||||||
request :describe_vpcs
|
request :describe_vpcs
|
||||||
request :describe_vpc_attribute
|
request :describe_vpc_attribute
|
||||||
|
@ -140,6 +141,7 @@ module Fog
|
||||||
request :modify_network_interface_attribute
|
request :modify_network_interface_attribute
|
||||||
request :modify_snapshot_attribute
|
request :modify_snapshot_attribute
|
||||||
request :modify_subnet_attribute
|
request :modify_subnet_attribute
|
||||||
|
request :modify_volume
|
||||||
request :modify_volume_attribute
|
request :modify_volume_attribute
|
||||||
request :modify_vpc_attribute
|
request :modify_vpc_attribute
|
||||||
request :move_address_to_vpc
|
request :move_address_to_vpc
|
||||||
|
@ -290,6 +292,7 @@ module Fog
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
:spot_requests => {},
|
:spot_requests => {},
|
||||||
|
:volume_modifications => {}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,31 +36,50 @@ module Fog
|
||||||
state == 'available'
|
state == 'available'
|
||||||
end
|
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
|
def save
|
||||||
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted?
|
if identity
|
||||||
requires :availability_zone
|
update_params = {
|
||||||
requires_one :size, :snapshot_id
|
'Size' => self.size,
|
||||||
|
'Iops' => self.iops,
|
||||||
|
'VolumeType' => self.type
|
||||||
|
}
|
||||||
|
|
||||||
if type == 'io1'
|
service.modify_volume(self.identity, update_params)
|
||||||
requires :iops
|
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
|
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
|
end
|
||||||
|
|
||||||
def server
|
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 = Fog::Compute[:aws].servers.create
|
||||||
@server.wait_for { ready? }
|
@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? }
|
@instance.wait_for { ready? }
|
||||||
|
|
||||||
|
@ -32,6 +32,21 @@ Shindo.tests("Fog::Compute[:aws] | volume", ['aws']) do
|
||||||
|
|
||||||
@instance.wait_for { ready? }
|
@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
|
tests('@instance.reload.tags').returns({'key' => 'value'}) do
|
||||||
@instance.reload.tags
|
@instance.reload.tags
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,6 +68,29 @@ Shindo.tests('Fog::Compute[:aws] | volume requests', ['aws']) do
|
||||||
'requestId' => String
|
'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 = Fog::Compute[:aws].servers.create
|
||||||
@server.wait_for { ready? }
|
@server.wait_for { ready? }
|
||||||
|
|
||||||
|
@ -113,13 +136,13 @@ Shindo.tests('Fog::Compute[:aws] | volume requests', ['aws']) do
|
||||||
Fog::Compute[:aws].delete_volume(@volume_id)
|
Fog::Compute[:aws].delete_volume(@volume_id)
|
||||||
|
|
||||||
tests('#create_volume from snapshot with size').formats(@volume_format) do
|
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? }
|
volume.wait_for { ready? }
|
||||||
|
|
||||||
snapshot = Fog::Compute[:aws].create_snapshot(volume.identity).body
|
snapshot = Fog::Compute[:aws].create_snapshot(volume.identity).body
|
||||||
Fog::Compute[:aws].snapshots.new(snapshot).wait_for { ready? }
|
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']
|
@volume_id = data['volumeId']
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
|
@ -155,6 +178,23 @@ Shindo.tests('Fog::Compute[:aws] | volume requests', ['aws']) do
|
||||||
|
|
||||||
Fog::Compute[:aws].volumes.get(@volume_id).wait_for { ready? }
|
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
|
tests("#modify_volume_attribute('#{@volume_id}', true)").formats(AWS::Compute::Formats::BASIC) do
|
||||||
Fog::Compute[:aws].modify_volume_attribute(@volume_id, true).body
|
Fog::Compute[:aws].modify_volume_attribute(@volume_id, true).body
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue