diff --git a/lib/fog/bin.rb b/lib/fog/bin.rb index 62cdf63b7..daade1317 100644 --- a/lib/fog/bin.rb +++ b/lib/fog/bin.rb @@ -68,6 +68,7 @@ require 'fog/bin/local' require 'fog/bin/new_servers' require 'fog/bin/ninefold' require 'fog/bin/rackspace' +require 'fog/bin/openstack' require 'fog/bin/slicehost' require 'fog/bin/stormondemand' require 'fog/bin/terremark' diff --git a/lib/fog/bin/openstack.rb b/lib/fog/bin/openstack.rb new file mode 100644 index 000000000..70a648eb5 --- /dev/null +++ b/lib/fog/bin/openstack.rb @@ -0,0 +1,31 @@ +class OpenStack < Fog::Bin + class << self + + def class_for(key) + case key + when :compute + Fog::Compute::OpenStack + else + raise ArgumentError, "Unrecognized service: #{key}" + end + end + + def [](service) + @@connections ||= Hash.new do |hash, key| + hash[key] = case key + when :compute + Fog::Logger.warning("OpenStack[:compute] is deprecated, use Compute[:rackspace] instead") + Fog::Compute.new(:provider => 'OpenStack') + else + raise ArgumentError, "Unrecognized service: #{key.inspect}" + end + end + @@connections[service] + end + + def services + Fog::OpenStack.services + end + + end +end diff --git a/lib/fog/openstack/compute.rb b/lib/fog/openstack/compute.rb index dd3dd7b3a..08bb8d24b 100644 --- a/lib/fog/openstack/compute.rb +++ b/lib/fog/openstack/compute.rb @@ -1,12 +1,13 @@ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'openstack')) require 'fog/compute' +require 'fog/openstack' module Fog module Compute class OpenStack < Fog::Service - requires :openstack_api_key, :openstack_username, :openstack_auth_url - recognizes :openstack_auth_token, :openstack_management_url, :persistent, :openstack_tenant, :openstack_compute_service_name + requires :openstack_api_key, :openstack_username, :openstack_auth_url, :openstack_tenant + recognizes :openstack_auth_token, :openstack_management_url, :persistent, :openstack_compute_service_name model_path 'fog/openstack/models/compute' model :flavor @@ -63,7 +64,19 @@ module Fog :images => {}, :servers => {} }, - :images => {}, + :images => { + "1" => { + 'id' => "1", + 'name' => "img1", + 'progress' => 100, + 'status' => "ACTIVE", + 'updated' => "", + 'minRam' => 0, + 'minDisk' => 0, + 'metadata' => {}, + 'links' => [] + } + }, :servers => {} } end diff --git a/lib/fog/openstack/models/compute/server.rb b/lib/fog/openstack/models/compute/server.rb index bb1ac518a..9f2b0a9c3 100644 --- a/lib/fog/openstack/models/compute/server.rb +++ b/lib/fog/openstack/models/compute/server.rb @@ -108,9 +108,9 @@ module Fog true end - def rebuild + def rebuild(image_ref, name, admin_pass=nil, metadata=nil, personality=nil) requires :id - connection.rebuild_server(id, name, metadata, personality) + connection.rebuild_server(id, image_ref, name, admin_pass, metadata, personality) true end @@ -141,7 +141,6 @@ module Fog def create_image(name, metadata={}) requires :id connection.create_image(id, name, metadata) - true end def save diff --git a/lib/fog/openstack/requests/compute/create_image.rb b/lib/fog/openstack/requests/compute/create_image.rb index 6bff6b49e..7efc4238a 100644 --- a/lib/fog/openstack/requests/compute/create_image.rb +++ b/lib/fog/openstack/requests/compute/create_image.rb @@ -8,7 +8,9 @@ module Fog 'name' => name, 'metadata' => metadata }} - server_action(server_id, body) + data = server_action(server_id, body) + image_id = data.headers["Location"].scan(/.*\/(.*)/).flatten + get_image_details(image_id) end end @@ -18,7 +20,27 @@ module Fog def create_image(server_id, name, metadata={}) response = Excon::Response.new response.status = 202 + + img_id=Fog::Mock.random_numbers(6).to_s + + data = { + 'id' => img_id, + 'server' => {"id"=>"3", "links"=>[{"href"=>"http://nova1:8774/admin/servers/#{server_id}", "rel"=>"bookmark"}]}, + 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/images/#{img_id}", "rel"=>"self"}, {"href"=>"http://nova1:8774/admin/images/#{img_id}", "rel"=>"bookmark"}], + 'metadata' => metadata || {}, + 'name' => name || "server_#{rand(999)}", + 'progress' => 0, + 'status' => 'SAVING', + 'minDisk' => 0, + 'minRam' => 0, + 'updated' => "", + 'created' => "" + } + self.data[:last_modified][:images][data['id']] = Time.now + self.data[:images][data['id']] = data + response.body = { 'image' => data } response + end end diff --git a/lib/fog/openstack/requests/compute/get_image_details.rb b/lib/fog/openstack/requests/compute/get_image_details.rb index 292faa9e8..630a070d7 100644 --- a/lib/fog/openstack/requests/compute/get_image_details.rb +++ b/lib/fog/openstack/requests/compute/get_image_details.rb @@ -12,6 +12,22 @@ module Fog end end + + class Mock + + def get_image_details(image_id) + response = Excon::Response.new + if image = list_images_detail.body['images'].detect {|_| _['id'] == image_id} + response.status = [200, 203][rand(1)] + response.body = { 'image' => image } + response + else + raise Fog::Compute::OpenStack::NotFound + end + end + + end + end end end diff --git a/lib/fog/openstack/requests/compute/list_flavors.rb b/lib/fog/openstack/requests/compute/list_flavors.rb index 4089c1dc4..4e491cc8a 100644 --- a/lib/fog/openstack/requests/compute/list_flavors.rb +++ b/lib/fog/openstack/requests/compute/list_flavors.rb @@ -20,13 +20,13 @@ module Fog response.status = 200 response.body = { 'flavors' => [ - { 'name' => '256 server', 'id' => '1' }, - { 'name' => '512 server', 'id' => '2' }, - { 'name' => '1GB server', 'id' => '3' }, - { 'name' => '2GB server', 'id' => '4' }, - { 'name' => '4GB server', 'id' => '5' }, - { 'name' => '8GB server', 'id' => '6' }, - { 'name' => '15.5GB server', 'id' => '7' } + { 'name' => '256 server', 'id' => '1', 'links' => [] }, + { 'name' => '512 server', 'id' => '2', 'links' => [] }, + { 'name' => '1GB server', 'id' => '3', 'links' => [] }, + { 'name' => '2GB server', 'id' => '4', 'links' => [] }, + { 'name' => '4GB server', 'id' => '5', 'links' => [] }, + { 'name' => '8GB server', 'id' => '6', 'links' => [] }, + { 'name' => '15.5GB server', 'id' => '7', 'links' => [] } ] } response diff --git a/lib/fog/openstack/requests/compute/list_images.rb b/lib/fog/openstack/requests/compute/list_images.rb index 27d6358c1..8ad0405c9 100644 --- a/lib/fog/openstack/requests/compute/list_images.rb +++ b/lib/fog/openstack/requests/compute/list_images.rb @@ -20,7 +20,7 @@ module Fog data = list_images_detail.body['images'] images = [] for image in data - images << image.reject { |key, value| !['id', 'name'].include?(key) } + images << image.reject { |key, value| !['id', 'name', 'links'].include?(key) } end response.status = [200, 203][rand(1)] response.body = { 'images' => images } diff --git a/lib/fog/openstack/requests/compute/list_images_detail.rb b/lib/fog/openstack/requests/compute/list_images_detail.rb index 7e982bf00..86c840233 100644 --- a/lib/fog/openstack/requests/compute/list_images_detail.rb +++ b/lib/fog/openstack/requests/compute/list_images_detail.rb @@ -29,7 +29,7 @@ module Fog end response.status = [200, 203][rand(1)] - response.body = { 'images' => images.map {|image| image.reject {|key, value| !['id', 'name', 'status', 'updated'].include?(key)}} } + response.body = { 'images' => images.map {|image| image.reject {|key, value| !['id', 'name', 'links', 'minRam', 'minDisk', 'metadata', 'status', 'updated'].include?(key)}} } response end diff --git a/lib/fog/openstack/requests/compute/list_servers.rb b/lib/fog/openstack/requests/compute/list_servers.rb index 19a0040a7..a83b892f6 100644 --- a/lib/fog/openstack/requests/compute/list_servers.rb +++ b/lib/fog/openstack/requests/compute/list_servers.rb @@ -20,7 +20,7 @@ module Fog data = list_servers_detail.body['servers'] servers = [] for server in data - servers << server.reject { |key, value| !['id', 'name'].include?(key) } + servers << server.reject { |key, value| !['id', 'name', 'links'].include?(key) } end response.status = [200, 203][rand(1)] response.body = { 'servers' => servers } diff --git a/lib/fog/openstack/requests/compute/rebuild_server.rb b/lib/fog/openstack/requests/compute/rebuild_server.rb index 7d3e5d4e7..c4f23e6b1 100644 --- a/lib/fog/openstack/requests/compute/rebuild_server.rb +++ b/lib/fog/openstack/requests/compute/rebuild_server.rb @@ -3,24 +3,25 @@ module Fog class OpenStack class Real - def rebuild_server(server_id, name, metadata=nil, personality=nil) + def rebuild_server(server_id, image_ref, name, admin_pass=nil, metadata=nil, personality=nil) body = { 'rebuild' => { + 'imageRef' => image_ref, 'name' => name }} + body['rebuild']['adminPass'] = admin_pass if admin_pass body['rebuild']['metadata'] = metadata if metadata body['rebuild']['personality'] = personality if personality - #NOTE: the implementation returns 200 on rebuild - server_action(server_id, body, 200) + server_action(server_id, body, 202) end end class Mock - def rebuild_server(server_id, name, metadata, personality) - response = Excon::Response.new - response.status = 202 + def rebuild_server(server_id, image_ref, name, admin_pass=nil, metadata=nil, personality=nil) + response = get_server_details(server_id) + response.body['server']['status'] = "REBUILD" response end diff --git a/lib/fog/openstack/requests/compute/resize_server.rb b/lib/fog/openstack/requests/compute/resize_server.rb index 0e4ac4219..bb14b6dab 100644 --- a/lib/fog/openstack/requests/compute/resize_server.rb +++ b/lib/fog/openstack/requests/compute/resize_server.rb @@ -4,7 +4,7 @@ module Fog class Real def resize_server(server_id, flavor_ref) - body = { 'resize' => { 'flavor' => { 'id' => flavor_ref }}} + body = { 'resize' => { 'flavorRef' => flavor_ref }} server_action(server_id, body) end diff --git a/lib/fog/providers.rb b/lib/fog/providers.rb index 8e11427cd..212e450a0 100644 --- a/lib/fog/providers.rb +++ b/lib/fog/providers.rb @@ -14,6 +14,7 @@ require 'fog/local' require 'fog/new_servers' require 'fog/ninefold' require 'fog/rackspace' +require 'fog/openstack' require 'fog/slicehost' require 'fog/storm_on_demand' require 'fog/vcloud' diff --git a/tests/helper.rb b/tests/helper.rb index 3e9d2e48f..9a19c4728 100644 --- a/tests/helper.rb +++ b/tests/helper.rb @@ -8,7 +8,7 @@ def lorem_file end # check to see which credentials are available and add others to the skipped tags list -all_providers = ['aws', 'bluebox', 'brightbox', 'dnsimple', 'dnsmadeeasy', 'dynect', 'ecloud', 'glesys', 'gogrid', 'google', 'linode', 'local', 'ninefold', 'newservers', 'rackspace', 'slicehost', 'stormondemand', 'voxel', 'zerigo'] +all_providers = ['aws', 'bluebox', 'brightbox', 'dnsimple', 'dnsmadeeasy', 'dynect', 'ecloud', 'glesys', 'gogrid', 'google', 'linode', 'local', 'ninefold', 'newservers', 'openstack', 'rackspace', 'slicehost', 'stormondemand', 'voxel', 'zerigo'] available_providers = Fog.available_providers.map {|provider| provider.downcase} for provider in (all_providers - available_providers) Formatador.display_line("[yellow]Skipping tests for [bold]#{provider}[/] [yellow]due to lacking credentials (add some to '~/.fog' to run them)[/]") diff --git a/tests/openstack/requests/compute/flavor_tests.rb b/tests/openstack/requests/compute/flavor_tests.rb index 888c4a151..f67ca54e4 100644 --- a/tests/openstack/requests/compute/flavor_tests.rb +++ b/tests/openstack/requests/compute/flavor_tests.rb @@ -1,16 +1,16 @@ Shindo.tests('Fog::Compute[:openstack] | flavor requests', ['openstack']) do @flavor_format = { - 'disk' => Integer, 'id' => String, 'name' => String, + 'disk' => Integer, 'ram' => Integer, 'links' => Array } tests('success') do - tests('#get_flavor_details(1)').formats(@flavor_format) do + tests('#get_flavor_details(1)').formats(@flavor_format, false) do Fog::Compute[:openstack].get_flavor_details("1").body['flavor'] end @@ -18,7 +18,7 @@ Shindo.tests('Fog::Compute[:openstack] | flavor requests', ['openstack']) do Fog::Compute[:openstack].list_flavors.body end - tests('#list_flavors_detail').formats({'flavors' => [@flavor_format]}) do + tests('#list_flavors_detail').formats({'flavors' => [@flavor_format]}, false) do Fog::Compute[:openstack].list_flavors_detail.body end diff --git a/tests/openstack/requests/compute/helper.rb b/tests/openstack/requests/compute/helper.rb index 6c34705bf..8d8e166c2 100644 --- a/tests/openstack/requests/compute/helper.rb +++ b/tests/openstack/requests/compute/helper.rb @@ -6,7 +6,8 @@ class OpenStack SUMMARY = { 'id' => String, - 'name' => String + 'name' => String, + 'links' => Array } end diff --git a/tests/openstack/requests/compute/image_tests.rb b/tests/openstack/requests/compute/image_tests.rb index 78be51702..12c62e310 100644 --- a/tests/openstack/requests/compute/image_tests.rb +++ b/tests/openstack/requests/compute/image_tests.rb @@ -1,3 +1,5 @@ +require 'fog/openstack' + Shindo.tests('Fog::Compute[:openstack] | image requests', ['openstack']) do @image_format = { @@ -7,21 +9,20 @@ Shindo.tests('Fog::Compute[:openstack] | image requests', ['openstack']) do 'progress' => Fog::Nullable::Integer, 'status' => String, 'updated' => String, - 'minRam' => String, - 'minDisk' => String, - #'server' => Hash, + 'minRam' => Integer, + 'minDisk' => Integer, + 'server' => Fog::Nullable::Hash, 'metadata' => Hash, 'links' => Array } tests('success') do - @image_id = 1 + @image_id = Fog::Compute[:openstack].images[0].id unless Fog.mocking? Fog::Compute[:openstack].images.get(@image_id).wait_for { ready? } end - tests("#get_image_details(#{@image_id})").formats(@image_format) do pending if Fog.mocking? Fog::Compute[:openstack].get_image_details(@image_id).body['image'] @@ -39,18 +40,12 @@ Shindo.tests('Fog::Compute[:openstack] | image requests', ['openstack']) do Fog::Compute[:openstack].images.get(@image_id).wait_for { ready? } end - if Fog.mocking? - tests("#delete_image(#{@image_id})").succeeds do - pending if Fog.mocking? # because it will fail without the wait just above here, which won't work - Fog::Compute[:openstack].delete_image(@image_id) - end - end - end tests('failure') do - tests('#delete_image(0)').raises(Excon::Errors::BadRequest) do + tests('#delete_image(0)').raises(Fog::Compute::OpenStack::NotFound) do + pending if Fog.mocking? Fog::Compute[:openstack].delete_image(0) end diff --git a/tests/openstack/requests/compute/server_tests.rb b/tests/openstack/requests/compute/server_tests.rb index 9887fd28c..a4ff1dab4 100644 --- a/tests/openstack/requests/compute/server_tests.rb +++ b/tests/openstack/requests/compute/server_tests.rb @@ -1,64 +1,117 @@ Shindo.tests('Fog::Compute[:openstack] | server requests', ['openstack']) do @server_format = { - 'addresses' => Hash, - 'flavor' => Hash, - 'hostId' => String, - 'id' => String, - 'image' => Hash, - 'metadata' => Hash, - 'name' => String, - 'progress' => Integer, - 'status' => String, + 'id' => String, + 'addresses' => Hash, + 'flavor' => Hash, + 'hostId' => String, + 'image' => Hash, + 'metadata' => Hash, + 'name' => String, + 'progress' => Integer, + 'status' => String, 'accessIPv4' => Fog::Nullable::String, 'accessIPv6' => Fog::Nullable::String, 'links' => Array } + @image_format = { + 'created' => Fog::Nullable::String, + 'id' => String, + 'name' => String, + 'progress' => Fog::Nullable::Integer, + 'status' => String, + 'updated' => String, + 'minRam' => Integer, + 'minDisk' => Integer, + 'server' => Hash, + 'metadata' => Hash, + 'links' => Array + } + tests('success') do - @server_id = nil + @image_id = Fog::Compute[:openstack].images[0].id + @snapshot_id = nil + @flavor_id = 2 - tests('#create_server("test", 1, 19)').formats(@server_format.merge('adminPass' => String)) do - data = Fog::Compute[:openstack].create_server("test", 3, 1).body['server'] + tests('#create_server("test", #{@image_id} , 19)').formats(@server_format.merge('adminPass' => String), false) do + data = Fog::Compute[:openstack].create_server("test", @image_id, @flavor_id).body['server'] @server_id = data['id'] data end Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } - tests("#get_server_details(#{@server_id})").formats(@server_format) do + #CREATE + tests("#get_server_details(#{@server_id})").formats(@server_format, false) do Fog::Compute[:openstack].get_server_details(@server_id).body['server'] end - tests('#list_servers').formats({'servers' => [OpenStack::Compute::Formats::SUMMARY]}) do + #LIST + #NOTE: we can remove strict=false if we remove uuid from GET /servers + tests('#list_servers').formats({'servers' => [OpenStack::Compute::Formats::SUMMARY]}, false) do Fog::Compute[:openstack].list_servers.body end - tests('#list_servers_detail').formats({'servers' => [@server_format]}) do + #DETAILS + tests('#list_servers_detail').formats({'servers' => [@server_format]}, false) do Fog::Compute[:openstack].list_servers_detail.body end + #CHANGE PASSWORD + tests("#change_password_server(#{@server_id}, 'fogupdatedserver')").succeeds do + Fog::Compute[:openstack].change_password_server(@server_id, 'foggy') + end Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } + #UPDATE SERVER NAME tests("#update_server(#{@server_id}, :name => 'fogupdatedserver')").succeeds do Fog::Compute[:openstack].update_server(@server_id, :name => 'fogupdatedserver') end - Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } + #CREATE IMAGE WITH METADATA + tests("#create_image(#{@server_id}, 'fog')").formats('image' => @image_format) do + data = Fog::Compute[:openstack].create_image(@server_id, 'fog', {"foo" => "bar"}).body + @snapshot_id = data['image']['id'] + data + end + Fog::Compute[:openstack].images.get(@snapshot_id).wait_for { ready? } + + #REBUILD + tests("#rebuild_server(#{@server_id}, #{@snapshot_id}, 'fog')").formats({'server' => @server_format}, false) do + Fog::Compute[:openstack].rebuild_server(@server_id, @snapshot_id, 'fog', 'newpass', {"foo" => "bar"}).body + end + Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } if not Fog.mocking? + + #RESIZE + tests("#resize_server(#{@server_id}, '3')").succeeds do + Fog::Compute[:openstack].resize_server(@server_id, 3) + end + Fog::Compute[:openstack].servers.get(@server_id).wait_for { self.state == 'VERIFY_RESIZE' } if not Fog.mocking? + + #RESIZE CONFIRM + tests("#resize_confirm(#{@server_id}, '3')").succeeds do + Fog::Compute[:openstack].confirm_resized_server(@server_id) + end + Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } if not Fog.mocking? + + #REBOOT - HARD tests("#reboot_server(#{@server_id}, 'HARD')").succeeds do Fog::Compute[:openstack].reboot_server(@server_id, 'HARD') end - Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } + Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } if not Fog.mocking? + #REBOOT - SOFT tests("#reboot_server(#{@server_id}, 'SOFT')").succeeds do Fog::Compute[:openstack].reboot_server(@server_id, 'SOFT') end - Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } + Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? } if not Fog.mocking? + #DELETE tests("#delete_server(#{@server_id})").succeeds do Fog::Compute[:openstack].delete_server(@server_id) end