diff --git a/lib/fog/openstack/compute.rb b/lib/fog/openstack/compute.rb index e77bcd666..a047f7828 100644 --- a/lib/fog/openstack/compute.rb +++ b/lib/fog/openstack/compute.rb @@ -27,6 +27,8 @@ module Fog collection :security_groups model :tenant collection :tenants + model :volume + collection :volumes request_path 'fog/openstack/requests/compute' @@ -88,6 +90,11 @@ module Fog request :list_tenants request :set_tenant + request :list_volumes + request :get_volume_details + request :create_volume + request :delete_volume + class Mock def self.data diff --git a/lib/fog/openstack/models/compute/volume.rb b/lib/fog/openstack/models/compute/volume.rb new file mode 100644 index 000000000..d6df92a9f --- /dev/null +++ b/lib/fog/openstack/models/compute/volume.rb @@ -0,0 +1,45 @@ +require 'fog/core/model' +require 'fog/openstack/models/compute/metadata' + +module Fog + module Compute + class OpenStack + + class Volume < Fog::Model + + identity :id + + attribute :name, :aliases => 'displayName' + attribute :description, :aliases => 'displayDescription' + attribute :status + attribute :size + attribute :type, :aliases => 'volumeType' + attribute :snapshot_id, :aliases => 'snapshotId' + attribute :availability_zone, :aliases => 'availabilityZone' + attribute :created_at, :aliases => 'createdAt' + attribute :attachments + + + def initialize(attributes) + @connection = attributes[:connection] + super + end + + def save + requires :name, :description, :size + data = connection.create_volume(name, description, size, attributes) + merge_attributes(data.body['volume']) + true + end + + def destroy + requires :id + connection.delete_volume(id) + true + end + end + + end + end + +end diff --git a/lib/fog/openstack/models/compute/volumes.rb b/lib/fog/openstack/models/compute/volumes.rb new file mode 100644 index 000000000..b84f383b2 --- /dev/null +++ b/lib/fog/openstack/models/compute/volumes.rb @@ -0,0 +1,26 @@ +require 'fog/core/collection' +require 'fog/openstack/models/compute/volume' + +module Fog + module Compute + class OpenStack + + class Volumes < Fog::Collection + model Fog::Compute::OpenStack::Volume + + def all(detailed=true) + load(connection.list_volumes(detailed).body['volumes']) + end + + def get(volume_id) + if volume = connection.get_volume_details(volume_id).body['volume'] + new(volume) + end + rescue Fog::Compute::OpenStack::NotFound + nil + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/compute/create_volume.rb b/lib/fog/openstack/requests/compute/create_volume.rb new file mode 100644 index 000000000..7b3ea12ff --- /dev/null +++ b/lib/fog/openstack/requests/compute/create_volume.rb @@ -0,0 +1,54 @@ +module Fog + module Compute + class OpenStack + class Real + + def create_volume(name, description, size, options={}) + data = { + 'volume' => { + 'display_name' => name, + 'display_description' => description, + 'size' => size + } + } + + vanilla_options = ['snapshot_id'] + vanilla_options.select{|o| options[o]}.each do |key| + data['volume'][key] = options[key] + end + request( + :body => MultiJson.encode(data), + :expects => [200, 202], + :method => 'POST', + :path => "os-volumes" + ) + end + + end + + class Mock + + def create_volume(name, description, size, options={}) + response = Excon::Response.new + response.status = 202 + response.body = { + 'volume' => { + 'id' => Fog::Mock.random_numbers(2), + 'displayName' => name, + 'displayDescription' => description, + 'size' => size, + 'status' => 'creating', + 'snapshotId' => '4', + 'volumeType' => nil, + 'availabilityZone' => 'nova', + 'createdAt' => Time.now, + 'attchments' => [] + } + } + response + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/compute/delete_volume.rb b/lib/fog/openstack/requests/compute/delete_volume.rb new file mode 100644 index 000000000..6ae1e6bfc --- /dev/null +++ b/lib/fog/openstack/requests/compute/delete_volume.rb @@ -0,0 +1,26 @@ +module Fog + module Compute + class OpenStack + class Real + + def delete_volume(volume_id) + request( + :expects => 204, + :method => 'DELETE', + :path => "os-volumes/#{volume_id}" + ) + end + + end + + class Mock + def delete_volume(volume_id) + response = Excon::Response.new + response.status = 204 + response + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/compute/get_volume_details.rb b/lib/fog/openstack/requests/compute/get_volume_details.rb new file mode 100644 index 000000000..5064adbbf --- /dev/null +++ b/lib/fog/openstack/requests/compute/get_volume_details.rb @@ -0,0 +1,42 @@ +module Fog + module Compute + class OpenStack + class Real + + def get_volume_details(volume_id) + + request( + :expects => 200, + :method => 'GET', + :path => "os-volumes/#{volume_id}" + ) + end + + end + + class Mock + + def get_volume_details(detailed=true) + response = Excon::Response.new + response.status = 200 + response.body = { + 'volume' => { + 'id' => '1', + 'displayName' => Fog::Mock.random_letters(rand(8) + 5), + 'displayDescription' => Fog::Mock.random_letters(rand(12) + 10), + 'size' => 3, + 'volumeType' => nil, + 'snapshotId' => '4', + 'status' => 'online', + 'availabilityZone' => 'nova', + 'createdAt' => Time.now, + 'attchments' => [] + } + } + response + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/compute/list_volumes.rb b/lib/fog/openstack/requests/compute/list_volumes.rb new file mode 100644 index 000000000..d28072a44 --- /dev/null +++ b/lib/fog/openstack/requests/compute/list_volumes.rb @@ -0,0 +1,43 @@ +module Fog + module Compute + class OpenStack + class Real + + def list_volumes(detailed=true) + + path = detailed ? 'os-volumes/detail' : 'os-volumes' + request( + :expects => 200, + :method => 'GET', + :path => path + ) + end + + end + + class Mock + + def list_volumes(detailed=true) + response = Excon::Response.new + response.status = 200 + response.body = { + 'volumes' => [ + { 'id' => '1', + 'displayName' => Fog::Mock.random_letters(rand(8) + 5), + 'displayDescription' => Fog::Mock.random_letters(rand(12) + 10), + 'size' => 3, + 'status' => 'online', + 'snapshotId' => '4', + 'volumeType' => nil, + 'availabilityZone' => 'nova', + 'createdAt' => Time.now, + 'attchments' => []} + ] + } + response + end + end + + end + end +end diff --git a/tests/openstack/requests/compute/volume_tests.rb b/tests/openstack/requests/compute/volume_tests.rb new file mode 100644 index 000000000..300f54266 --- /dev/null +++ b/tests/openstack/requests/compute/volume_tests.rb @@ -0,0 +1,39 @@ +require 'fog/openstack' + +Shindo.tests('Fog::Compute[:openstack] | volume requests', ['openstack']) do + + @volume_format = { + 'id' => String, + 'displayName' => String, + 'size' => Integer, + 'displayDescription' => String, + 'status' => String, + 'snapshotId' => String, + 'availabilityZone' => String, + 'attchments' => Array, + 'volumeType' => NilClass, + 'createdAt' => Time + } + + + tests('success') do + tests('#list_volumes').formats({'volumes' => [@volume_format]}) do + Fog::Compute[:openstack].list_volumes.body + end + + tests('#get_volume_detail').formats({'volume' => @volume_format}) do + pending unless Fog.mocking? + Fog::Compute[:openstack].get_volume_details(0).body + end + + tests('#create_volume').formats({'volume' => @volume_format}) do + pending unless Fog.mocking? + Fog::Compute[:openstack].create_volume('loud', 'this is a loud volume', 3).body + end + + tests('#delete_volume').succeeds do + pending unless Fog.mocking? + Fog::Compute[:openstack].delete_volume(1) + end + end +end