diff --git a/lib/fog/rackspace/compute_v2.rb b/lib/fog/rackspace/compute_v2.rb index 445f22c6e..1c6891979 100644 --- a/lib/fog/rackspace/compute_v2.rb +++ b/lib/fog/rackspace/compute_v2.rb @@ -40,8 +40,10 @@ module Fog request :confirm_resize_server request :revert_resize_server + request :create_image request :list_images request :get_image + request :delete_image request :list_flavors request :get_flavor @@ -52,9 +54,15 @@ module Fog request :delete_attachment class Mock + + def initialize(options) + # prevents service initialization errors. This method should be implemented + end + def request(params) Fog::Mock.not_implemented end + end class Real diff --git a/lib/fog/rackspace/models/compute_v2/image.rb b/lib/fog/rackspace/models/compute_v2/image.rb index 1da944bc4..1e30727d7 100644 --- a/lib/fog/rackspace/models/compute_v2/image.rb +++ b/lib/fog/rackspace/models/compute_v2/image.rb @@ -24,6 +24,15 @@ module Fog attribute :metadata attribute :disk_config, :aliases => 'OS-DCF:diskConfig' attribute :links + + def ready? + state == ACTIVE + end + + def destroy + requires :identity + connection.delete_image(identity) + end end end end diff --git a/lib/fog/rackspace/models/compute_v2/server.rb b/lib/fog/rackspace/models/compute_v2/server.rb index b5283e51a..6a4f30b97 100644 --- a/lib/fog/rackspace/models/compute_v2/server.rb +++ b/lib/fog/rackspace/models/compute_v2/server.rb @@ -88,6 +88,12 @@ module Fog requires :image_id @image ||= connection.images.get(image_id) end + + def create_image(name, options = {}) + requires :identity + response = connection.create_image(identity, name, options) + response.headers["Location"].match(/\/([^\/]+$)/)[1] rescue nil + end def attachments @attachments ||= begin diff --git a/lib/fog/rackspace/requests/compute_v2/create_image.rb b/lib/fog/rackspace/requests/compute_v2/create_image.rb new file mode 100644 index 000000000..ad8b9b701 --- /dev/null +++ b/lib/fog/rackspace/requests/compute_v2/create_image.rb @@ -0,0 +1,41 @@ +module Fog + module Compute + class RackspaceV2 + class Real + + # Create an image from a running server + # + # ==== Parameters + # * server_id<~Integer> - Id of server to create image from + # * name - Name of image + # * options<~Hash> - Name + + def create_image(server_id, name, options = {}) + data = { + 'createImage' => { + 'name' => name + } + } + data['createImage'].merge!(options) + request( + :body => Fog::JSON.encode(data), + :expects => 202, + :method => 'POST', + :path => "servers/#{server_id}/action" + ) + end + end + + class Mock + + def create_image(server_id, name, options = {}) + response = Excon::Response.new + response.status = 202 + response.body = "" + response + end + + end + end + end +end diff --git a/lib/fog/rackspace/requests/compute_v2/delete_image.rb b/lib/fog/rackspace/requests/compute_v2/delete_image.rb new file mode 100644 index 000000000..2fe84c9dd --- /dev/null +++ b/lib/fog/rackspace/requests/compute_v2/delete_image.rb @@ -0,0 +1,31 @@ +module Fog + module Compute + class RackspaceV2 + class Real + + # Delete an image + # + # ==== Parameters + # * image_id<~Integer> - Id of image to delete + # + def delete_image(image_id) + request( + :expects => 204, + :method => 'DELETE', + :path => "images/#{image_id}" + ) + end + + end + + class Mock + def delete_image(image_id) + response = Excon::Response.new + response.status = 202 + response.body = "" + end + + end + end + end +end diff --git a/tests/rackspace/models/compute_v2/image_tests.rb b/tests/rackspace/models/compute_v2/image_tests.rb new file mode 100644 index 000000000..65b2b8744 --- /dev/null +++ b/tests/rackspace/models/compute_v2/image_tests.rb @@ -0,0 +1,28 @@ +Shindo.tests('Fog::Compute::RackspaceV2 | image', ['rackspace']) do + + pending if Fog.mocking? + + service = Fog::Compute::RackspaceV2.new + test_time = Time.now.to_i.to_s + options = { + :name => "fog_server_#{test_time}", + :flavor_id => 2, + :image_id => '3afe97b2-26dc-49c5-a2cc-a2fc8d80c001' + } + + + tests("success") do + begin + server = service.servers.create(options) + server.wait_for { ready? } + image_id = server.create_image("fog_image_#{test_time}") + image = service.images.get(image_id) + + tests("destroy").succeeds do + image.destroy + end + ensure + server.destroy if server + end + end +end diff --git a/tests/rackspace/models/compute_v2/server_tests.rb b/tests/rackspace/models/compute_v2/server_tests.rb index 57fc05c8c..22de7cffd 100644 --- a/tests/rackspace/models/compute_v2/server_tests.rb +++ b/tests/rackspace/models/compute_v2/server_tests.rb @@ -59,4 +59,19 @@ Shindo.tests('Fog::Compute::RackspaceV2 | server', ['rackspace']) do @instance.wait_for { ready? } end + + # When after testing resize/resize_confirm we get a 409 when we try to resize_revert so I am going to split it into two blocks + model_tests(service.servers, options, false) do + @instance.wait_for { ready? } + tests('#resize').succeeds do + @instance.resize(4) + returns('RESIZE') { @instance.state } + end + + @instance.wait_for { state == 'VERIFY_RESIZE' } + tests('#revert_resize').succeeds do + @instance.revert_resize + end + @instance.wait_for { ready? } + end end diff --git a/tests/rackspace/requests/compute_v2/image_tests.rb b/tests/rackspace/requests/compute_v2/image_tests.rb index c90c404fa..94ea8df72 100644 --- a/tests/rackspace/requests/compute_v2/image_tests.rb +++ b/tests/rackspace/requests/compute_v2/image_tests.rb @@ -30,18 +30,46 @@ Shindo.tests('Fog::Compute::RackspaceV2 | image_tests', ['rackspace']) do 'image' => IMAGE_FORMAT } - service = Fog::Compute.new(:provider => 'Rackspace', :version => 'V2') - image_id = nil + begin + service = Fog::Compute.new(:provider => 'Rackspace', :version => 'V2') + test_time = Time.now.to_i.to_s + @server = service.servers.create(:name => "fog-image-tests_#{test_time}", :flavor_id => 2, :image_id => "3afe97b2-26dc-49c5-a2cc-a2fc8d80c001") + @server.wait_for { ready? } + @image_id = nil - tests('success') do - tests('#list_images').formats(LIST_IMAGE_FORMAT) do - body = service.list_images.body - image_id = body['images'][0]['id'] - body - end + tests('success') do - tests('#get_image').formats(GET_IMAGE_FORMAT) do - service.get_image(image_id).body + tests("#create_image(#{@server.id}, 'fog-test-image')").succeeds do + response = service.create_image(@server.id, "fog-test-image_#{test_time}") + @image_id = response.headers["Location"].match(/\/([^\/]+$)/)[1] + end + + tests('#list_images').formats(LIST_IMAGE_FORMAT) do + service.list_images.body + end + + tests('#get_image').formats(GET_IMAGE_FORMAT, false) do + service.get_image(@image_id).body + end + + tests('#delete_image').succeeds do + service.delete_image(@image_id) + end end + + tests('failure') do + tests('#delete_image').raises(Excon::Errors::BadRequest) do + pending if Fog.mocking? + Fog::Compute[:rackspace].delete_image(0) + end + + tests('#get_image').raises(Fog::Compute::RackspaceV2::NotFound) do + pending if Fog.mocking? + service.get_image(0) + end + end + ensure + @image.destroy if @image + @server.destroy if @server end end