From c216917285fb5bc0e82f68bff4fb06f807216b56 Mon Sep 17 00:00:00 2001 From: Rupak Ganguly Date: Wed, 22 May 2013 10:50:39 -0400 Subject: [PATCH] [hp|block_storage_v2] Add volume model, fix some mocks, and add volume tests. --- lib/fog/hp/block_storage_v2.rb | 6 +- lib/fog/hp/models/block_storage_v2/volume.rb | 132 ++++++++++++++ lib/fog/hp/models/block_storage_v2/volumes.rb | 36 ++++ .../hp/requests/compute_v2/attach_volume.rb | 16 +- .../compute_v2/get_server_volume_details.rb | 2 +- .../models/block_storage_v2/volume_tests.rb | 22 +++ .../compute_v2/volume_attachment_tests.rb | 84 ++++----- .../compute_v2/volume_attachments_tests.rb | 34 ++-- .../compute_v2/server_volume_tests.rb | 172 +++++++++--------- 9 files changed, 345 insertions(+), 159 deletions(-) create mode 100644 lib/fog/hp/models/block_storage_v2/volume.rb create mode 100644 lib/fog/hp/models/block_storage_v2/volumes.rb create mode 100644 tests/hp/models/block_storage_v2/volume_tests.rb diff --git a/lib/fog/hp/block_storage_v2.rb b/lib/fog/hp/block_storage_v2.rb index 334974164..9b91244c4 100644 --- a/lib/fog/hp/block_storage_v2.rb +++ b/lib/fog/hp/block_storage_v2.rb @@ -11,9 +11,9 @@ module Fog secrets :hp_secret_key - #model_path 'fog/hp/models/block_storage_v2' - #model :volume - #collection :volumes + model_path 'fog/hp/models/block_storage_v2' + model :volume + collection :volumes #collection :bootable_volumes #model :snapshot #collection :snapshots diff --git a/lib/fog/hp/models/block_storage_v2/volume.rb b/lib/fog/hp/models/block_storage_v2/volume.rb new file mode 100644 index 000000000..9b59a5483 --- /dev/null +++ b/lib/fog/hp/models/block_storage_v2/volume.rb @@ -0,0 +1,132 @@ +require 'fog/core/model' + +module Fog + module HP + class BlockStorageV2 + + class Volume < Fog::Model + + identity :id + + attribute :name, :aliases => 'display_name' + attribute :description, :aliases => 'display_description' + attribute :size + attribute :status + attribute :type, :aliases => 'volume_type' + attribute :created_at + attribute :availability_zone + attribute :snapshot_id + attribute :source_volid + attribute :attachments + attribute :metadata + attribute :bootable + attribute :image_metadata, :aliases => 'volume_image_metadata' + + #attr_reader :server_id + #attr_reader :device + + def initialize(attributes = {}) + # assign these attributes first to prevent race condition with new_record? + self.image_id = attributes.delete(:image_id) + super + end + + def device + attachments[0]['device'] if has_attachments? + end + + def server_id + attachments[0]['serverId'] if has_attachments? + end + + # used for creating bootable volumes + def image_id=(new_image_id) + @image_id = new_image_id + end + + def image_id + @image_id = image_metadata['image_id'] if image_metadata + end + + # a volume can be attached to only one server at a time + def has_attachments? + !(attachments.nil? || attachments.empty? || attachments[0].empty?) + end + + def in_use? + self.status == 'in-use' + end + alias :attached? :in_use? + + def ready? + self.status == 'available' + end + + # volume can be attached to only one server at a time + def attach(new_server_id, device) + requires :id + unless in_use? + data = service.compute.attach_volume(new_server_id, id, device) + merge_attributes(:attachments => attachments << data.body['volumeAttachment']) + true + else + false + end + end + + def detach + requires :id + if has_attachments? + service.compute.detach_volume(self.server_id, id) + end + true + end + + def destroy + requires :id + service.delete_volume(id) + true + end + + def save + identity ? update : create + end + + private + + def create + options = { + 'display_name' => name, + 'display_description' => description, + 'size' => size, + 'metadata' => metadata, + 'snapshot_id' => snapshot_id, + 'imageRef' => @image_id, + 'availability_zone' => availability_zone, + 'source_volid' => source_volid, + 'volume_type' => type # this parameter is currently ignored + } + options = options.reject {|_, value| value.nil?} + data = service.create_volume(options) + merge_attributes(data.body['volume']) + true + end + + def update + requires :id + options = { + 'display_name' => name, + 'display_description' => description, + 'metadata' => metadata + } + options = options.reject {|_, value| value.nil?} + data = service.update_volume(id, options) + merge_attributes(data.body['volume']) + true + end + + end + + end + end +end diff --git a/lib/fog/hp/models/block_storage_v2/volumes.rb b/lib/fog/hp/models/block_storage_v2/volumes.rb new file mode 100644 index 000000000..02dc80a89 --- /dev/null +++ b/lib/fog/hp/models/block_storage_v2/volumes.rb @@ -0,0 +1,36 @@ +require 'fog/core/collection' +require 'fog/hp/models/block_storage_v2/volume' + +module Fog + module HP + class BlockStorageV2 + + class Volumes < Fog::Collection + + attribute :filters + + model Fog::HP::BlockStorageV2::Volume + + def initialize(attributes) + self.filters ||= {} + super + end + + def all(filters = filters) + self.filters = filters + data = service.list_volumes(filters).body['volumes'] + load(data) + end + + def get(volume_id) + volume = service.get_volume_details(volume_id).body['volume'] + new(volume) + rescue Fog::HP::BlockStorageV2::NotFound + nil + end + + end + + end + end +end diff --git a/lib/fog/hp/requests/compute_v2/attach_volume.rb b/lib/fog/hp/requests/compute_v2/attach_volume.rb index 070ee332a..a83eaf269 100644 --- a/lib/fog/hp/requests/compute_v2/attach_volume.rb +++ b/lib/fog/hp/requests/compute_v2/attach_volume.rb @@ -45,20 +45,22 @@ module Fog response.body = '{"badRequest": {"message": "Volume status must be available", "code": 400}}' raise(Excon::Errors.status_error({:expects => 200}, response)) else - resp_data = { "volumeAttachment" => + resp_data = { 'volumeAttachment' => { - "volumeId" => volume_id, - "id" => volume_id + 'device' => device, + 'serverId' => server_id, + 'id' => volume_id, + 'volumeId' => volume_id, } } response.body = resp_data response.status = 200 data = { - "device" => device, - "serverId" => server_id, - "id" => volume_id, - "volumeId" => volume_id, + 'device' => device, + 'serverId' => server_id, + 'id' => volume_id, + 'volumeId' => volume_id, } if server['volumeAttachments'] server['volumeAttachments'] << data diff --git a/lib/fog/hp/requests/compute_v2/get_server_volume_details.rb b/lib/fog/hp/requests/compute_v2/get_server_volume_details.rb index c51cbe84f..41ce08367 100644 --- a/lib/fog/hp/requests/compute_v2/get_server_volume_details.rb +++ b/lib/fog/hp/requests/compute_v2/get_server_volume_details.rb @@ -30,7 +30,7 @@ module Fog if server = self.data[:servers][server_id] if server['volumeAttachments'] && server['volumeAttachments'].select {|v| v['volumeId'] == volume_id} data = server['volumeAttachments'].select {|v| v['volumeId'] == volume_id} - response.body = { 'volumeAttachment' => data } + response.body = { 'volumeAttachment' => data[0] } response.status = 200 else raise Fog::Compute::HPV2::NotFound diff --git a/tests/hp/models/block_storage_v2/volume_tests.rb b/tests/hp/models/block_storage_v2/volume_tests.rb new file mode 100644 index 000000000..960ad2792 --- /dev/null +++ b/tests/hp/models/block_storage_v2/volume_tests.rb @@ -0,0 +1,22 @@ +Shindo.tests("HP::BlockStorage | volume model", ['hp', 'v2', 'block_storage', 'volumes']) do + + model_tests(HP[:block_storage_v2].volumes, {:name => 'fogvol2tests', :description => 'fogvol2tests-desc', :size => 1}, true) do + + test("get(#{@instance.id})") do + HP[:block_storage_v2].volumes.get(@instance.id) != nil? + end + + test("update(#{@instance.id})") do + @instance.name = 'fogvol2tests Updated' + @instance.save + @instance.reload + @instance.name == 'fogvol2tests Updated' + end + + test("has_attachments?") do + @instance.has_attachments? == false + end + + end + +end diff --git a/tests/hp/models/compute_v2/volume_attachment_tests.rb b/tests/hp/models/compute_v2/volume_attachment_tests.rb index 47f261bee..2e9709d00 100644 --- a/tests/hp/models/compute_v2/volume_attachment_tests.rb +++ b/tests/hp/models/compute_v2/volume_attachment_tests.rb @@ -1,44 +1,40 @@ -#Shindo.tests("Fog::Compute::HPV2 | volume_attachment model", ['hp', 'v2', 'compute']) do -# -# service = Fog::Compute.new(:provider => 'HP', :version => :v2) -# -# @base_image_id = ENV['BASE_IMAGE_ID'] || '7f60b54c-cd15-433f-8bed-00acbcd25a17' -# -# @server = service.servers.create(:name => 'fogserattachtests', :flavor_id => 100, :image_id => @base_image_id) -# @server.wait_for { ready? } -# @volume = HP[:block_storage_v2].volumes.create(:display_name => 'fogvolumetest', :size => 1) -# @volume.wait_for { ready? } -# -# tests('success') do -# -# tests('#create').succeeds do -# volume_attachment = @server.volume_attachments.create(:server_id => @server.id, :volume_id => @volume.id, :device => '/dev/sdf') -# test('volume attached to server') do -# volume_attachment.server_id == @server.id -# end -# end -# -# tests('#all').succeeds do -# volume_attachment = @server.volume_attachments.all -# test('list server in volume attachment') do -# volume_attachment.server_id == @server.id -# end -# end -# -# tests('#get').succeeds do -# volume_attachment = @server.volume_attachments.get(@volume.id) -# test('get server in volume attachment') do -# volume_attachment.id == @volume.id -# end -# end -# -# tests('#detach').succeeds do -# volume = @server.volume_attachments.get(@volume.id) -# volume.detach -# end -# -# end -# -# @volume.destroy -# @server.destroy -#end +Shindo.tests("Fog::Compute::HPV2 | volume_attachment model", ['hp', 'v2', 'compute']) do + + service = Fog::Compute.new(:provider => 'HP', :version => :v2) + + @base_image_id = ENV['BASE_IMAGE_ID'] || '7f60b54c-cd15-433f-8bed-00acbcd25a17' + + @server = service.servers.create(:name => 'fogserattachtests', :flavor_id => 100, :image_id => @base_image_id) + @server.wait_for { ready? } + @volume = HP[:block_storage_v2].volumes.create(:name => 'fogvolumetest', :size => 1) + @volume.wait_for { ready? } + + tests('success') do + + tests('#create').succeeds do + volume_attachment = @server.volume_attachments.create(:server_id => @server.id, :volume_id => @volume.id, :device => '/dev/sdf') + test('volume attached to server') do + volume_attachment.server_id == @server.id + end + end + + tests('#get').succeeds do + volume_attachment = @server.volume_attachments.get(@volume.id) + test('get server in volume attachment') do + volume_attachment.server_id == @server.id + end + test('get volume in volume attachment') do + volume_attachment.id == @volume.id + end + end + + tests('#detach').succeeds do + volume_attachment = @server.volume_attachments.get(@volume.id) + volume_attachment.detach + end + + end + + @volume.destroy + @server.destroy +end diff --git a/tests/hp/models/compute_v2/volume_attachments_tests.rb b/tests/hp/models/compute_v2/volume_attachments_tests.rb index 880c74168..34b00f441 100644 --- a/tests/hp/models/compute_v2/volume_attachments_tests.rb +++ b/tests/hp/models/compute_v2/volume_attachments_tests.rb @@ -1,17 +1,17 @@ -#Shindo.tests("Fog::Compute::HPV2 | volume attachments collection", ['hp', 'v2', 'compute']) do -# -# service = Fog::Compute.new(:provider => 'HP', :version => :v2) -# -# @base_image_id = ENV['BASE_IMAGE_ID'] || '7f60b54c-cd15-433f-8bed-00acbcd25a17' -# -# @server = service.servers.create(:name => 'fogserverattachtest', :flavor_id => 100, :image_id => @base_image_id) -# @server.wait_for { ready? } -# @volume = HP[:block_storage_v2].volumes.create(:display_name => 'fogvolumetest', :size => 1) -# @volume.wait_for { ready? } -# -# collection_tests(service.volume_attachments, {:server_id => @server.id, :volume_id => @volume.id, :device => '/dev/sdf'}, true) -# -# @volume.destroy -# @server.destroy -# -#end \ No newline at end of file +Shindo.tests("Fog::Compute::HPV2 | volume attachments collection", ['hp', 'v2', 'compute']) do + + service = Fog::Compute.new(:provider => 'HP', :version => :v2) + + @base_image_id = ENV['BASE_IMAGE_ID'] || '7f60b54c-cd15-433f-8bed-00acbcd25a17' + + @server = service.servers.create(:name => 'fogserverattachtest', :flavor_id => 100, :image_id => @base_image_id) + @server.wait_for { ready? } + @volume = HP[:block_storage_v2].volumes.create(:name => 'fogvolumetest', :size => 1) + @volume.wait_for { ready? } + + collection_tests(@server.volume_attachments, {:server_id => @server.id, :volume_id => @volume.id, :device => '/dev/sdf'}, true) + + @volume.destroy + @server.destroy + +end \ No newline at end of file diff --git a/tests/hp/requests/compute_v2/server_volume_tests.rb b/tests/hp/requests/compute_v2/server_volume_tests.rb index 09fe92a10..3abe360b2 100644 --- a/tests/hp/requests/compute_v2/server_volume_tests.rb +++ b/tests/hp/requests/compute_v2/server_volume_tests.rb @@ -1,87 +1,85 @@ -#Shindo.tests("Fog::Compute::HPV2 | volume requests", ['hp', 'v2', 'compute', 'volumes']) do -# -# service = Fog::Compute.new(:provider => 'HP', :version => :v2) -# -# @list_volume_attachments_format = { -# 'volumeAttachments' => [{ -# 'device' => String, -# 'serverId' => String, -# 'id' => String, -# 'volumeId' => String -# }] -# } -# -# @volume_attachment_format = { -# 'volumeAttachment' => { -# "volumeId" => String, -# "id" => String -# } -# } -# -# @base_image_id = ENV['BASE_IMAGE_ID'] || '7f60b54c-cd15-433f-8bed-00acbcd25a17' -# -# @server = service.servers.create(:name => 'fogservoltests', :flavor_id => 100, :image_id => @base_image_id) -# @server.wait_for { ready? } -# -# tests('success') do -# response = HP[:block_storage].create_volume('fogvoltest', 'fogvoltest desc', 1) -# @volume_id = response.body['volume']['id'] -# @device = "\/dev\/sdf" -# -# HP[:block_storage].volumes.get(@volume_id).wait_for { ready? } -# tests("#attach_volume(#{@server.id}, #{@volume_id}, #{@device}").formats(@volume_attachment_format) do -# service.attach_volume(@server.id, @volume_id, @device).body -# end -# -# HP[:block_storage].volumes.get(@volume_id).wait_for { ready? } -# tests("#list_server_volumes(#{@server.id})").formats(@list_volume_attachments_format) do -# service.list_server_volumes(@server.id).body -# end -# -# HP[:block_storage].volumes.get(@volume_id).wait_for { ready? } -# tests("#get_server_volume_details(#{@server.id}, #{@volume_id})").formats(@list_volume_attachments_format) do -# service.get_server_volume_details(@server.id, @volume_id).body -# end -# -# HP[:block_storage].volumes.get(@volume_id).wait_for { in_use? } unless Fog.mocking? -# tests("#detach_volume(#{@server.id}, #{@volume_id}").succeeds do -# service.detach_volume(@server.id, @volume_id) -# end -# -# end -# -# -# tests('failure') do -# -# tests('#list_server_volumes(0)').raises(Fog::Compute::HPV2::NotFound) do -# service.list_server_volumes(0) -# end -# -# tests('#get_server_volume_details(0, 0)').raises(Fog::Compute::HPV2::NotFound) do -# service.get_server_volume_details(0, 0) -# end -# -# tests("#attach_volume(#{@server.id}, 0, #{@device})").raises(Fog::Compute::HPV2::NotFound) do -# pending if Fog.mocking? -# service.attach_volume(@server.id, 0, @device) -# end -# -# tests("#attach_volume(0, #{@volume_id}, #{@device})").raises(Fog::Compute::HPV2::NotFound) do -# service.attach_volume(0, @volume_id, @device) -# end -# -# tests("#detach_volume(#{@server.id}, 0)").raises(Fog::Compute::HPV2::NotFound) do -# pending if Fog.mocking? -# service.detach_volume(@server.id, 0) -# end -# -# tests("#detach_volume(0, #{@volume_id})").raises(Fog::Compute::HP::NotFound) do -# service.detach_volume(0, @volume_id) -# end -# -# end -# -# HP[:block_storage].delete_volume(@volume_id) -# service.delete_server(@server.id) -# -#end +Shindo.tests("Fog::Compute::HPV2 | volume requests", ['hp', 'v2', 'compute', 'volumes']) do + + service = Fog::Compute.new(:provider => 'HP', :version => :v2) + + @list_volume_attachments_format = { + 'volumeAttachments' => [{ + 'device' => String, + 'serverId' => String, + 'id' => String, + 'volumeId' => String + }] + } + + @volume_attachment_format = { + 'volumeAttachment' => { + 'device' => String, + 'serverId' => String, + 'id' => String, + 'volumeId' => String + } + } + + @base_image_id = ENV['BASE_IMAGE_ID'] || '7f60b54c-cd15-433f-8bed-00acbcd25a17' + + @server = service.servers.create(:name => 'fogservoltests', :flavor_id => 100, :image_id => @base_image_id) + @server.wait_for { ready? } + + tests('success') do + response = HP[:block_storage_v2].create_volume('display_name' => 'fogvoltest', 'display_description' => 'fogvoltest desc', 'size' => 1) + @volume_id = response.body['volume']['id'] + @device = "\/dev\/sdf" + + tests("#attach_volume(#{@server.id}, #{@volume_id}, #{@device}").formats(@volume_attachment_format) do + service.attach_volume(@server.id, @volume_id, @device).body + end + + tests("#list_server_volumes(#{@server.id})").formats(@list_volume_attachments_format) do + service.list_server_volumes(@server.id).body + end + + tests("#get_server_volume_details(#{@server.id}, #{@volume_id})").formats(@volume_attachment_format) do + service.get_server_volume_details(@server.id, @volume_id).body + end + + tests("#detach_volume(#{@server.id}, #{@volume_id}").succeeds do + service.detach_volume(@server.id, @volume_id) + end + + end + + + tests('failure') do + + tests('#list_server_volumes(0)').raises(Fog::Compute::HPV2::NotFound) do + service.list_server_volumes(0) + end + + tests('#get_server_volume_details(0, 0)').raises(Fog::Compute::HPV2::NotFound) do + service.get_server_volume_details(0, 0) + end + + tests("#attach_volume(#{@server.id}, 0, #{@device})").raises(Fog::Compute::HPV2::NotFound) do + pending if Fog.mocking? + service.attach_volume(@server.id, 0, @device) + end + + tests("#attach_volume(0, #{@volume_id}, #{@device})").raises(Fog::Compute::HPV2::NotFound) do + service.attach_volume(0, @volume_id, @device) + end + + tests("#detach_volume(#{@server.id}, 0)").raises(Fog::Compute::HPV2::NotFound) do + pending if Fog.mocking? + service.detach_volume(@server.id, 0) + end + + tests("#detach_volume(0, #{@volume_id})").raises(Fog::Compute::HPV2::NotFound) do + service.detach_volume(0, @volume_id) + end + + end + + HP[:block_storage_v2].delete_volume(@volume_id) + service.delete_server(@server.id) + +end