mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
Merge pull request #3189 from smashwilson/boot-from-volume
[rackspace] Boot from volume
This commit is contained in:
commit
1bc78346c0
7 changed files with 130 additions and 8 deletions
|
@ -48,6 +48,10 @@ module Fog
|
|||
# @return [String] region of the volume
|
||||
attribute :availability_zone
|
||||
|
||||
# @!attribute [rw] image_id
|
||||
# @return [String] The ID of an image used to create a bootable volume.
|
||||
attribute :image_id, :aliases => ['image', 'imageRef'], :squash => 'id'
|
||||
|
||||
# Returns true if the volume is in a ready state
|
||||
# @return [Boolean] returns true if volume is in a ready state
|
||||
def ready?
|
||||
|
@ -104,7 +108,8 @@ module Fog
|
|||
:display_description => display_description,
|
||||
:volume_type => volume_type,
|
||||
:availability_zone => availability_zone,
|
||||
:snapshot_id => attributes[:snapshot_id]
|
||||
:snapshot_id => attributes[:snapshot_id],
|
||||
:image_id => attributes[:image_id]
|
||||
})
|
||||
merge_attributes(data.body['volume'])
|
||||
true
|
||||
|
|
|
@ -148,6 +148,16 @@ module Fog
|
|||
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/List_Images-d1e4435.html
|
||||
attribute :image_id, :aliases => 'image', :squash => 'id'
|
||||
|
||||
# @!attribute [w] boot_volume_id
|
||||
# @return [String] The ID of a bootable volume from the BlockStorage service.
|
||||
# @see http://developer.openstack.org/api-ref-compute-v2-ext.html#ext-os-block-device-mapping-v2-boot
|
||||
attribute :boot_volume_id
|
||||
|
||||
# @!attribute [w] boot_image_id
|
||||
# @return [String] The ID of an image to create a bootable volume from.
|
||||
# @see http://developer.openstack.org/api-ref-compute-v2-ext.html#ext-os-block-device-mapping-v2-boot
|
||||
attribute :boot_image_id
|
||||
|
||||
# @!attribute [rw] password
|
||||
# @return [String] Password for system adminstrator account.
|
||||
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Passwords-d1e2510.html
|
||||
|
@ -221,7 +231,8 @@ module Fog
|
|||
|
||||
# Creates server
|
||||
# * requires attributes: service:, :name, :image_id, and :flavor_id
|
||||
# * optional attributes :disk_config, :metadata, :personality, :config_drive
|
||||
# * optional attributes :disk_config, :metadata, :personality, :config_drive, :boot_volume_id, :boot_image_id
|
||||
# * :image_id should be "" if :boot_volume_id or :boot_image_id are provided.
|
||||
# @return [Boolean] returns true if server is being created
|
||||
# @raise [Fog::Compute::RackspaceV2::NotFound] - HTTP 404
|
||||
# @raise [Fog::Compute::RackspaceV2::BadRequest] - HTTP 400
|
||||
|
@ -251,10 +262,13 @@ module Fog
|
|||
modified_options[:config_drive] = config_drive unless config_drive.nil?
|
||||
modified_options[:user_data] = user_data_encoded unless user_data_encoded.nil?
|
||||
modified_options[:key_name] ||= attributes[:key_name]
|
||||
modified_options[:boot_volume_id] ||= attributes[:boot_volume_id]
|
||||
modified_options[:boot_image_id] ||= attributes[:boot_image_id]
|
||||
|
||||
if modified_options[:networks]
|
||||
modified_options[:networks].map! { |id| { :uuid => id } }
|
||||
end
|
||||
|
||||
data = service.create_server(name, image_id, flavor_id, 1, 1, modified_options)
|
||||
merge_attributes(data.body['server'])
|
||||
true
|
||||
|
|
|
@ -10,6 +10,8 @@ module Fog
|
|||
# @option options [String] :display_description display description for volume
|
||||
# @option options [String] :volume_type type of volume
|
||||
# @option options [String] :snapshot_id The optional snapshot from which to create a volume.
|
||||
# @option options [String] :image_id The ID of an image from the compute service. If provided, a bootable volume will be
|
||||
# created.
|
||||
# @return [Excon::Response] response:
|
||||
# * body [Hash]:
|
||||
# * 'volume' [Hash]:
|
||||
|
@ -41,6 +43,7 @@ module Fog
|
|||
data['volume']['volume_type'] = options[:volume_type] unless options[:volume_type].nil?
|
||||
data['volume']['availability_zone'] = options[:availability_zone] unless options[:availability_zone].nil?
|
||||
data['volume']['snapshot_id'] = options[:snapshot_id] unless options[:snapshot_id].nil?
|
||||
data['volume']['imageRef'] = options[:image_id] unless options[:image_id].nil?
|
||||
|
||||
request(
|
||||
:body => Fog::JSON.encode(data),
|
||||
|
@ -80,6 +83,7 @@ module Fog
|
|||
snapshot = self.data[:snapshots][snapshot_id]
|
||||
volume.merge!("size" => snapshot["size"])
|
||||
end
|
||||
volume["image_id"] = options[:image_id] if options[:image_id]
|
||||
|
||||
self.data[:volumes][volume_id] = volume
|
||||
|
||||
|
|
|
@ -14,6 +14,12 @@ module Fog
|
|||
# @option options [Hash] personality Hash containing data to inject into the file system of the cloud server instance during server creation.
|
||||
# @option options [Boolean] config_drive whether to attach a read-only configuration drive
|
||||
# @option options [String] keypair Name of the kay-pair to associate with this server.
|
||||
# @option options [Array<Hash>] block_device_mapping A manually specified block device mapping to fully control the creation and
|
||||
# attachment of volumes to this server. Mutually exclusive with :volume_id or :volume_image_id. If provided, leave image_id
|
||||
# as "". See http://developer.openstack.org/api-ref-compute-v2-ext.html#ext-os-block-device-mapping-v2-boot for details.
|
||||
# @option options [String] boot_volume_id Id of a pre-created bootable volume to use for this server. If provided, leave image_id as "".
|
||||
# @option options [String] boot_image_id Id of an image to create a bootable volume from and attach to this server. If provided,
|
||||
# leave image_id as "".
|
||||
# @return [Excon::Response] response:
|
||||
# * body [Hash]:
|
||||
# * server [Hash]:
|
||||
|
@ -40,6 +46,7 @@ module Fog
|
|||
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Metadata-d1e2529.html
|
||||
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Personality-d1e2543.html
|
||||
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ch_extensions.html#diskconfig_attribute
|
||||
# @see http://developer.openstack.org/api-ref-compute-v2-ext.html#ext-os-block-device-mapping-v2-boot
|
||||
#
|
||||
# * State Transitions
|
||||
# * BUILD -> ACTIVE
|
||||
|
@ -73,6 +80,42 @@ module Fog
|
|||
|
||||
data['server']['key_name'] = options[:key_name] unless options[:key_name].nil?
|
||||
|
||||
if options[:block_device_mapping]
|
||||
if options[:boot_volume_id]
|
||||
Fog::Logger.warning("Manual :block_device_mapping overrides :boot_volume_id in #create_server!")
|
||||
end
|
||||
|
||||
if options[:boot_image_id]
|
||||
Fog::Logger.warning("Manual :block_device_mapping overrides :boot_image_id in #create_server!")
|
||||
end
|
||||
|
||||
data['server']['block_device_mapping_v2'] = options[:block_device_mapping]
|
||||
else
|
||||
if options[:boot_volume_id]
|
||||
if options[:boot_image_id]
|
||||
Fog::Logger.warning(":boot_volume_id overrides :boot_image_id!")
|
||||
end
|
||||
|
||||
data['server']['block_device_mapping_v2'] = [{
|
||||
'boot_index' => '0',
|
||||
'uuid' => options[:boot_volume_id],
|
||||
'source_type' => 'volume',
|
||||
'destination_type' => 'volume',
|
||||
'volume_size' => 100
|
||||
}]
|
||||
end
|
||||
|
||||
if options[:boot_image_id]
|
||||
data['server']['block_device_mapping_v2'] = [{
|
||||
'boot_index' => '0',
|
||||
'uuid' => options[:boot_image_id],
|
||||
'source_type' => 'image',
|
||||
'destination_type' => 'volume',
|
||||
'volume_size' => 100
|
||||
}]
|
||||
end
|
||||
end
|
||||
|
||||
request(
|
||||
:body => Fog::JSON.encode(data),
|
||||
:expects => [202],
|
||||
|
|
|
@ -60,6 +60,19 @@ module Shindo
|
|||
sleep 30 unless Fog.mocking?
|
||||
end
|
||||
|
||||
def wait_for_volume_state(service, volume_id, state)
|
||||
current_state = nil
|
||||
until current_state == state
|
||||
current_state = service.get_volume(volume_id).body['volume']['status']
|
||||
if current_state == 'error'
|
||||
Fog::Logger.warning caller
|
||||
Fog::Logger.warning "Volume is in an error state!"
|
||||
return
|
||||
end
|
||||
sleep 10 unless Fog.mocking?
|
||||
end
|
||||
end
|
||||
|
||||
def rackspace_test_image_id(service)
|
||||
image_id = Fog.credentials[:rackspace_image_id]
|
||||
# I chose to use the first Ubuntu because it will work with the smallest flavor and it doesn't require a license
|
||||
|
|
|
@ -10,6 +10,7 @@ Shindo.tests('Fog::Rackspace::BlockStorage | volume_tests', ['rackspace']) do
|
|||
'volume_type' => String,
|
||||
'availability_zone' => String,
|
||||
'snapshot_id' => Fog::Nullable::String,
|
||||
'image_id' => Fog::Nullable::String,
|
||||
'attachments' => Array,
|
||||
'metadata' => Hash
|
||||
}
|
||||
|
@ -25,12 +26,23 @@ Shindo.tests('Fog::Rackspace::BlockStorage | volume_tests', ['rackspace']) do
|
|||
service = Fog::Rackspace::BlockStorage.new
|
||||
|
||||
tests('success') do
|
||||
id = nil
|
||||
ids = []
|
||||
size = 100
|
||||
|
||||
tests("#create_volume(#{size})").formats(get_volume_format) do
|
||||
data = service.create_volume(size).body
|
||||
id = data['volume']['id']
|
||||
ids << data['volume']['id']
|
||||
data
|
||||
end
|
||||
|
||||
tests("#create_volume for a bootable volume").formats(get_volume_format) do
|
||||
# Find a suitable image.
|
||||
image_id = rackspace_test_image_id(Fog::Compute.new(:provider => 'rackspace'))
|
||||
data = service.create_volume(size, :image_id => image_id).body
|
||||
tests("assigned an image id").returns(image_id) do
|
||||
data['volume']['image_id']
|
||||
end
|
||||
ids << data['volume']['id']
|
||||
data
|
||||
end
|
||||
|
||||
|
@ -38,12 +50,16 @@ Shindo.tests('Fog::Rackspace::BlockStorage | volume_tests', ['rackspace']) do
|
|||
service.list_volumes.body
|
||||
end
|
||||
|
||||
tests("#get_volume(#{id})").formats(get_volume_format) do
|
||||
service.get_volume(id).body
|
||||
tests("#get_volume(#{ids.first})").formats(get_volume_format) do
|
||||
service.get_volume(ids.first).body
|
||||
end
|
||||
|
||||
tests("#delete_volume(#{id})").succeeds do
|
||||
service.delete_volume(id)
|
||||
ids.each do |id|
|
||||
tests("#delete_volume(#{id})").succeeds do
|
||||
wait_for_volume_state(service, id, 'available')
|
||||
|
||||
service.delete_volume(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -61,6 +61,11 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server_tests', ['rackspace']) do
|
|||
server_name = "fog#{Time.now.to_i.to_s}"
|
||||
image_id = rackspace_test_image_id(service)
|
||||
flavor_id = rackspace_test_flavor_id(service)
|
||||
bootable_flavor_id = if Fog.mocking?
|
||||
flavor_id
|
||||
else
|
||||
service.flavors.find { |f| f.name =~ /Performance/ }.id
|
||||
end
|
||||
|
||||
tests("#create_server(#{server_name}, #{image_id}, #{flavor_id}, 1, 1)").formats(create_server_format) do
|
||||
body = service.create_server(server_name, image_id, flavor_id, 1, 1).body
|
||||
|
@ -69,6 +74,28 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server_tests', ['rackspace']) do
|
|||
end
|
||||
wait_for_server_state(service, server_id, 'ACTIVE', 'ERROR')
|
||||
|
||||
tests("#create_server(#{server_name}_bfv_1, '', #{flavor_id}, 1, 1, :boot_volume_id => bootable_volume_id)").succeeds do
|
||||
# First, create a bootable volume.
|
||||
volume_service = Fog::Rackspace::BlockStorage.new
|
||||
bootable_volume_id = volume_service.create_volume(100, :image_id => image_id).body['volume']['id']
|
||||
wait_for_volume_state(volume_service, bootable_volume_id, 'available')
|
||||
|
||||
body = service.create_server(server_name + "_bfv_1", '', bootable_flavor_id, 1, 1, :boot_volume_id => bootable_volume_id).body
|
||||
bfv_server_id = body['server']['id']
|
||||
wait_for_server_state(service, bfv_server_id, 'ACTIVE', 'ERROR')
|
||||
service.delete_server(bfv_server_id)
|
||||
|
||||
wait_for_volume_state(volume_service, bootable_volume_id, 'available')
|
||||
volume_service.delete_volume(bootable_volume_id)
|
||||
end
|
||||
|
||||
tests("#create_server(#{server_name}_bfv_2, '', #{flavor_id}, 1, 1, :boot_image_id => #{image_id})").succeeds do
|
||||
body = service.create_server(server_name + "_bfv_2", '', bootable_flavor_id, 1, 1, :boot_image_id => image_id).body
|
||||
bfv_server_id = body['server']['id']
|
||||
wait_for_server_state(service, bfv_server_id, 'ACTIVE', 'ERROR')
|
||||
service.delete_server(bfv_server_id)
|
||||
end
|
||||
|
||||
tests('#list_servers').formats(list_servers_format, false) do
|
||||
service.list_servers.body
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue