mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
Implement fog support for the Openstack Compute API v1.1. Includes
support for legacy v1.0 style auth and v2.0 keystone auth.
This commit is contained in:
parent
f812565897
commit
41f09986f4
48 changed files with 2016 additions and 0 deletions
|
@ -38,6 +38,9 @@ module Fog
|
|||
when :ninefold
|
||||
require 'fog/ninefold/compute'
|
||||
Fog::Compute::Ninefold.new(attributes)
|
||||
when :openstack
|
||||
require 'fog/openstack/compute'
|
||||
Fog::Compute::OpenStack.new(attributes)
|
||||
when :rackspace
|
||||
require 'fog/rackspace/compute'
|
||||
Fog::Compute::Rackspace.new(attributes)
|
||||
|
|
|
@ -48,6 +48,10 @@ An alternate file may be used by placing its path in the FOG_RC environment vari
|
|||
:new_servers_username:
|
||||
:public_key_path:
|
||||
:private_key_path:
|
||||
:openstack_api_key:
|
||||
:openstack_username:
|
||||
:openstack_auth_url:
|
||||
:openstack_tenant:
|
||||
:rackspace_api_key:
|
||||
:rackspace_username:
|
||||
:rackspace_servicenet:
|
||||
|
|
112
lib/fog/openstack.rb
Normal file
112
lib/fog/openstack.rb
Normal file
|
@ -0,0 +1,112 @@
|
|||
require(File.expand_path(File.join(File.dirname(__FILE__), 'core')))
|
||||
|
||||
module Fog
|
||||
module OpenStack
|
||||
extend Fog::Provider
|
||||
|
||||
module Errors
|
||||
class ServiceError < Fog::Errors::Error
|
||||
attr_reader :response_data
|
||||
|
||||
def self.slurp(error)
|
||||
if error.response.body.empty?
|
||||
data = nil
|
||||
message = nil
|
||||
else
|
||||
data = MultiJson.decode(error.response.body)
|
||||
message = data['message']
|
||||
end
|
||||
|
||||
new_error = super(error, message)
|
||||
new_error.instance_variable_set(:@response_data, data)
|
||||
new_error
|
||||
end
|
||||
end
|
||||
|
||||
class InternalServerError < ServiceError; end
|
||||
class Conflict < ServiceError; end
|
||||
class NotFound < ServiceError; end
|
||||
class ServiceUnavailable < ServiceError; end
|
||||
|
||||
class BadRequest < ServiceError
|
||||
attr_reader :validation_errors
|
||||
|
||||
def self.slurp(error)
|
||||
new_error = super(error)
|
||||
unless new_error.response_data.nil?
|
||||
new_error.instance_variable_set(:@validation_errors, new_error.response_data['validationErrors'])
|
||||
end
|
||||
new_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
service(:compute, 'openstack/compute', 'Compute')
|
||||
|
||||
# legacy v1.0 style auth
|
||||
def self.authenticate_v1(options, connection_options = {})
|
||||
openstack_auth_url = options[:openstack_auth_url]
|
||||
uri = URI.parse(openstack_auth_url)
|
||||
connection = Fog::Connection.new(openstack_auth_url, false, connection_options)
|
||||
@openstack_api_key = options[:openstack_api_key]
|
||||
@openstack_username = options[:openstack_username]
|
||||
response = connection.request({
|
||||
:expects => [200, 204],
|
||||
:headers => {
|
||||
'X-Auth-Key' => @openstack_api_key,
|
||||
'X-Auth-User' => @openstack_username
|
||||
},
|
||||
:host => uri.host,
|
||||
:method => 'GET',
|
||||
:path => (uri.path and not uri.path.empty?) ? uri.path : 'v1.0'
|
||||
})
|
||||
|
||||
return {
|
||||
:token => response.headers['X-Auth-Token'],
|
||||
:server_management_url => response.headers['X-Server-Management-Url']
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
# keystone style auth
|
||||
def self.authenticate_v2(options, connection_options = {})
|
||||
openstack_auth_url = options[:openstack_auth_url]
|
||||
uri = URI.parse(openstack_auth_url)
|
||||
connection = Fog::Connection.new(openstack_auth_url, false, connection_options)
|
||||
@openstack_api_key = options[:openstack_api_key]
|
||||
@openstack_username = options[:openstack_username]
|
||||
@openstack_tenant = options[:openstack_tenant]
|
||||
@compute_service_name = options[:openstack_compute_service_name]
|
||||
|
||||
req_body= {
|
||||
'passwordCredentials' => {
|
||||
'username' => @openstack_username,
|
||||
'password' => @openstack_api_key
|
||||
}
|
||||
}
|
||||
req_body['tenantId'] = @openstack_tenant if @openstack_tenant
|
||||
|
||||
response = connection.request({
|
||||
:expects => [200, 204],
|
||||
:body => req_body,
|
||||
:host => uri.host,
|
||||
:method => 'GET',
|
||||
:path => (uri.path and not uri.path.empty?) ? uri.path : 'v2.0'
|
||||
})
|
||||
body=response.body
|
||||
|
||||
if body['auth']['serviceCatalog'] and body['auth']['serviceCatalog'][@compute_service_name] and body['auth']['serviceCatalog'][@compute_service_name][0] then
|
||||
mgmt_url = body['auth']['serviceCatalog'][@compute_service_name][0]['publicURL']
|
||||
token = body['auth']['token']['id']
|
||||
return {
|
||||
:token => token,
|
||||
:server_management_url => mgmt_url
|
||||
}
|
||||
else
|
||||
raise "Unable to parse service catalog."
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
182
lib/fog/openstack/compute.rb
Normal file
182
lib/fog/openstack/compute.rb
Normal file
|
@ -0,0 +1,182 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'openstack'))
|
||||
require 'fog/compute'
|
||||
|
||||
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
|
||||
|
||||
model_path 'fog/openstack/models/compute'
|
||||
model :flavor
|
||||
collection :flavors
|
||||
model :image
|
||||
collection :images
|
||||
model :server
|
||||
collection :servers
|
||||
model :meta
|
||||
collection :metadata
|
||||
|
||||
request_path 'fog/openstack/requests/compute'
|
||||
request :create_server
|
||||
request :delete_image
|
||||
request :delete_server
|
||||
request :get_flavor_details
|
||||
request :get_image_details
|
||||
request :get_server_details
|
||||
request :list_addresses
|
||||
request :list_private_addresses
|
||||
request :list_public_addresses
|
||||
request :list_flavors
|
||||
request :list_flavors_detail
|
||||
request :list_images
|
||||
request :list_images_detail
|
||||
request :list_servers
|
||||
request :list_servers_detail
|
||||
|
||||
request :server_action
|
||||
request :change_password_server
|
||||
request :reboot_server
|
||||
request :rebuild_server
|
||||
request :resize_server
|
||||
request :confirm_resized_server
|
||||
request :revert_resized_server
|
||||
request :create_image
|
||||
|
||||
request :update_server
|
||||
|
||||
request :set_metadata
|
||||
request :update_metadata
|
||||
request :list_metadata
|
||||
|
||||
request :get_meta
|
||||
request :update_meta
|
||||
request :delete_meta
|
||||
|
||||
class Mock
|
||||
|
||||
def self.data
|
||||
@data ||= Hash.new do |hash, key|
|
||||
hash[key] = {
|
||||
:last_modified => {
|
||||
:images => {},
|
||||
:servers => {}
|
||||
},
|
||||
:images => {},
|
||||
:servers => {}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.reset
|
||||
@data = nil
|
||||
end
|
||||
|
||||
def initialize(options={})
|
||||
require 'multi_json'
|
||||
@openstack_username = options[:openstack_username]
|
||||
end
|
||||
|
||||
def data
|
||||
self.class.data[@openstack_username]
|
||||
end
|
||||
|
||||
def reset_data
|
||||
self.class.data.delete(@openstack_username)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Real
|
||||
|
||||
def initialize(options={})
|
||||
require 'multi_json'
|
||||
@openstack_api_key = options[:openstack_api_key]
|
||||
@openstack_username = options[:openstack_username]
|
||||
@openstack_tenant = options[:openstack_tenant]
|
||||
@openstack_compute_service_name = options[:openstack_compute_service_name] || 'nova'
|
||||
@openstack_auth_url = options[:openstack_auth_url]
|
||||
@openstack_auth_token = options[:openstack_auth_token]
|
||||
@openstack_management_url = options[:openstack_management_url]
|
||||
@openstack_must_reauthenticate = false
|
||||
@connection_options = options[:connection_options] || {}
|
||||
authenticate
|
||||
@persistent = options[:persistent] || false
|
||||
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
|
||||
end
|
||||
|
||||
def reload
|
||||
@connection.reset
|
||||
end
|
||||
|
||||
def request(params)
|
||||
begin
|
||||
response = @connection.request(params.merge({
|
||||
:headers => {
|
||||
'Content-Type' => 'application/json',
|
||||
'X-Auth-Token' => @auth_token
|
||||
}.merge!(params[:headers] || {}),
|
||||
:host => @host,
|
||||
:path => "#{@path}/#{params[:path]}",
|
||||
:query => ('ignore_awful_caching' << Time.now.to_i.to_s)
|
||||
}))
|
||||
rescue Excon::Errors::Unauthorized => error
|
||||
if error.response.body != 'Bad username or password' # token expiration
|
||||
@openstack_must_reauthenticate = true
|
||||
authenticate
|
||||
retry
|
||||
else # bad credentials
|
||||
raise error
|
||||
end
|
||||
rescue Excon::Errors::HTTPStatusError => error
|
||||
raise case error
|
||||
when Excon::Errors::NotFound
|
||||
Fog::Compute::OpenStack::NotFound.slurp(error)
|
||||
else
|
||||
error
|
||||
end
|
||||
end
|
||||
unless response.body.empty?
|
||||
response.body = MultiJson.decode(response.body)
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticate
|
||||
if @openstack_must_reauthenticate || @openstack_auth_token.nil?
|
||||
options = {
|
||||
:openstack_api_key => @openstack_api_key,
|
||||
:openstack_username => @openstack_username,
|
||||
:openstack_auth_url => @openstack_auth_url,
|
||||
:openstack_tenant => @openstack_tenant,
|
||||
:openstack_compute_service_name => @openstack_compute_service_name
|
||||
}
|
||||
if @openstack_auth_url =~ /.*v2.0\/?$/
|
||||
credentials = Fog::OpenStack.authenticate_v2(options, @connection_options)
|
||||
else
|
||||
credentials = Fog::OpenStack.authenticate_v1(options, @connection_options)
|
||||
end
|
||||
@auth_token = credentials[:token]
|
||||
url = credentials[:server_management_url]
|
||||
uri = URI.parse(url)
|
||||
else
|
||||
@auth_token = @openstack_auth_token
|
||||
uri = URI.parse(@openstack_management_url)
|
||||
end
|
||||
@host = uri.host
|
||||
@path = uri.path
|
||||
# Force URL into v1.1 namespace (what this binding supports)
|
||||
@path.sub!(/\/.*\/?/, '/v1.1/')
|
||||
# Add tenant
|
||||
@path += @openstack_tenant if @openstack_tenant
|
||||
@port = uri.port
|
||||
@scheme = uri.scheme
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
20
lib/fog/openstack/models/compute/flavor.rb
Normal file
20
lib/fog/openstack/models/compute/flavor.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Flavor < Fog::Model
|
||||
|
||||
identity :id
|
||||
|
||||
attribute :disk
|
||||
attribute :name
|
||||
attribute :ram
|
||||
attribute :links
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
28
lib/fog/openstack/models/compute/flavors.rb
Normal file
28
lib/fog/openstack/models/compute/flavors.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/openstack/models/compute/flavor'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Flavors < Fog::Collection
|
||||
|
||||
model Fog::Compute::OpenStack::Flavor
|
||||
|
||||
def all
|
||||
data = connection.list_flavors_detail.body['flavors']
|
||||
load(data)
|
||||
end
|
||||
|
||||
def get(flavor_id)
|
||||
data = connection.get_flavor_details(flavor_id).body['flavor']
|
||||
new(data)
|
||||
rescue Fog::Compute::OpenStack::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
57
lib/fog/openstack/models/compute/image.rb
Normal file
57
lib/fog/openstack/models/compute/image.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
require 'fog/core/model'
|
||||
require 'fog/openstack/models/compute/metadata'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Image < Fog::Model
|
||||
|
||||
identity :id
|
||||
|
||||
attribute :name
|
||||
attribute :created_at, :aliases => 'created'
|
||||
attribute :updated_at, :aliases => 'updated'
|
||||
attribute :progress
|
||||
attribute :status
|
||||
attribute :minDisk
|
||||
attribute :minRam
|
||||
attribute :server, :aliases => 'server'
|
||||
attribute :metadata
|
||||
attribute :links
|
||||
|
||||
def initialize(attributes)
|
||||
@connection = attributes[:connection]
|
||||
super
|
||||
end
|
||||
|
||||
def metadata
|
||||
@metadata ||= begin
|
||||
Fog::Compute::OpenStack::Metadata.new({
|
||||
:connection => connection,
|
||||
:parent => self
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def metadata=(new_metadata={})
|
||||
metas = []
|
||||
new_metadata.each_pair {|k,v| metas << {"key" => k, "value" => v} }
|
||||
metadata.load(metas)
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :id
|
||||
connection.delete_image(id)
|
||||
true
|
||||
end
|
||||
|
||||
def ready?
|
||||
status == 'ACTIVE'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
33
lib/fog/openstack/models/compute/images.rb
Normal file
33
lib/fog/openstack/models/compute/images.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/openstack/models/compute/image'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Images < Fog::Collection
|
||||
|
||||
model Fog::Compute::OpenStack::Image
|
||||
|
||||
attribute :server
|
||||
|
||||
def all
|
||||
data = connection.list_images_detail.body['images']
|
||||
load(data)
|
||||
if server
|
||||
self.replace(self.select {|image| image.server_id == server.id})
|
||||
end
|
||||
end
|
||||
|
||||
def get(image_id)
|
||||
data = connection.get_image_details(image_id).body['image']
|
||||
new(data)
|
||||
rescue Fog::Compute::OpenStack::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
29
lib/fog/openstack/models/compute/meta.rb
Normal file
29
lib/fog/openstack/models/compute/meta.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require 'fog/core/model'
|
||||
require 'fog/openstack/models/meta_parent'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Meta < Fog::Model
|
||||
|
||||
include Fog::Compute::OpenStack::MetaParent
|
||||
|
||||
identity :key
|
||||
attribute :value
|
||||
|
||||
def destroy
|
||||
requires :identity
|
||||
connection.delete_meta(collection_name, @parent.id, key)
|
||||
true
|
||||
end
|
||||
|
||||
def save
|
||||
requires :identity, :value
|
||||
connection.update_meta(collection_name, @parent.id, key, value)
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
69
lib/fog/openstack/models/compute/metadata.rb
Normal file
69
lib/fog/openstack/models/compute/metadata.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/openstack/models/meta_parent'
|
||||
require 'fog/openstack/models/compute/meta'
|
||||
require 'fog/openstack/models/compute/image'
|
||||
require 'fog/openstack/models/compute/server'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Metadata < Fog::Collection
|
||||
|
||||
model Fog::Compute::OpenStack::Meta
|
||||
|
||||
include Fog::Compute::OpenStack::MetaParent
|
||||
|
||||
def all
|
||||
requires :parent
|
||||
metadata = connection.list_metadata(collection_name, @parent.id).body['metadata']
|
||||
metas = []
|
||||
metadata.each_pair {|k,v| metas << {"key" => k, "value" => v} }
|
||||
load(metas)
|
||||
end
|
||||
|
||||
def get(key)
|
||||
requires :parent
|
||||
data = connection.get_meta(collection_name, @parent.id, key).body["meta"]
|
||||
metas = []
|
||||
data.each_pair {|k,v| metas << {"key" => k, "value" => v} }
|
||||
new(metas[0])
|
||||
rescue Fog::Compute::OpenStack::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
def update(data=nil)
|
||||
requires :parent
|
||||
connection.update_metadata(collection_name, @parent.id, meta_hash(data))
|
||||
end
|
||||
|
||||
def set(data=nil)
|
||||
requires :parent
|
||||
connection.set_metadata(collection_name, @parent.id, meta_hash(data))
|
||||
end
|
||||
|
||||
def new(attributes = {})
|
||||
requires :parent
|
||||
super({ :parent => @parent }.merge!(attributes))
|
||||
end
|
||||
|
||||
private
|
||||
def meta_hash(data=nil)
|
||||
if data.nil?
|
||||
data={}
|
||||
self.each do |meta|
|
||||
if meta.is_a?(Fog::Compute::OpenStack::Meta) then
|
||||
data.store(meta.key, meta.value)
|
||||
else
|
||||
data.store(meta["key"], meta["value"])
|
||||
end
|
||||
end
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
187
lib/fog/openstack/models/compute/server.rb
Normal file
187
lib/fog/openstack/models/compute/server.rb
Normal file
|
@ -0,0 +1,187 @@
|
|||
require 'fog/compute/models/server'
|
||||
require 'fog/openstack/models/compute/metadata'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Server < Fog::Compute::Server
|
||||
|
||||
identity :id
|
||||
|
||||
attribute :addresses
|
||||
attribute :flavor
|
||||
attribute :host_id, :aliases => 'hostId'
|
||||
attribute :image
|
||||
attribute :metadata
|
||||
attribute :links
|
||||
attribute :name
|
||||
attribute :personality
|
||||
attribute :progress
|
||||
attribute :accessIPv4
|
||||
attribute :accessIPv6
|
||||
attribute :state, :aliases => 'status'
|
||||
|
||||
attr_reader :password
|
||||
attr_writer :private_key, :private_key_path, :public_key, :public_key_path, :username, :image_ref, :flavor_ref
|
||||
|
||||
def initialize(attributes={})
|
||||
@connection = attributes[:connection]
|
||||
super
|
||||
end
|
||||
|
||||
def metadata
|
||||
@metadata ||= begin
|
||||
Fog::Compute::OpenStack::Metadata.new({
|
||||
:connection => connection,
|
||||
:parent => self
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def metadata=(new_metadata={})
|
||||
metas = []
|
||||
new_metadata.each_pair {|k,v| metas << {"key" => k, "value" => v} }
|
||||
metadata.load(metas)
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :id
|
||||
connection.delete_server(id)
|
||||
true
|
||||
end
|
||||
|
||||
def images
|
||||
requires :id
|
||||
connection.images(:server => self)
|
||||
end
|
||||
|
||||
def private_ip_address
|
||||
nil
|
||||
end
|
||||
|
||||
def private_key_path
|
||||
@private_key_path ||= Fog.credentials[:private_key_path]
|
||||
@private_key_path &&= File.expand_path(@private_key_path)
|
||||
end
|
||||
|
||||
def private_key
|
||||
@private_key ||= private_key_path && File.read(private_key_path)
|
||||
end
|
||||
|
||||
def public_ip_address
|
||||
addresses['public'].first
|
||||
end
|
||||
|
||||
def public_key_path
|
||||
@public_key_path ||= Fog.credentials[:public_key_path]
|
||||
@public_key_path &&= File.expand_path(@public_key_path)
|
||||
end
|
||||
|
||||
def public_key
|
||||
@public_key ||= public_key_path && File.read(public_key_path)
|
||||
end
|
||||
|
||||
def image_ref
|
||||
@image_ref
|
||||
end
|
||||
|
||||
def image_ref=(new_image_ref)
|
||||
@image_ref = new_image_ref
|
||||
end
|
||||
|
||||
def flavor_ref
|
||||
@flavor_ref
|
||||
end
|
||||
|
||||
def flavor_ref=(new_flavor_ref)
|
||||
@flavor_ref = new_flavor_ref
|
||||
end
|
||||
|
||||
def ready?
|
||||
self.state == 'ACTIVE'
|
||||
end
|
||||
|
||||
def change_password(admin_password)
|
||||
requires :id
|
||||
connection.change_password_server(id, admin_password)
|
||||
true
|
||||
end
|
||||
|
||||
def rebuild
|
||||
requires :id
|
||||
connection.rebuild_server(id, name, metadata, personality)
|
||||
true
|
||||
end
|
||||
|
||||
def resize(flavor_ref)
|
||||
requires :id
|
||||
connection.resize_server(id, flavor_ref)
|
||||
true
|
||||
end
|
||||
|
||||
def revert_resize
|
||||
requires :id
|
||||
connection.revert_resize_server(id)
|
||||
true
|
||||
end
|
||||
|
||||
def confirm_resize
|
||||
requires :id
|
||||
connection.confirm_resize_server(id)
|
||||
true
|
||||
end
|
||||
|
||||
def reboot(type = 'SOFT')
|
||||
requires :id
|
||||
connection.reboot_server(id, type)
|
||||
true
|
||||
end
|
||||
|
||||
def save
|
||||
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if identity
|
||||
requires :flavor_ref, :image_ref, :name
|
||||
meta_hash = {}
|
||||
metadata.each { |meta| meta_hash.store(meta.key, meta.value) }
|
||||
options = {
|
||||
'metadata' => meta_hash,
|
||||
'personality' => personality,
|
||||
'accessIPv4' => accessIPv4,
|
||||
'accessIPv6' => accessIPv6
|
||||
}
|
||||
options = options.reject {|key, value| value.nil?}
|
||||
data = connection.create_server(name, image_ref, flavor_ref, options)
|
||||
merge_attributes(data.body['server'])
|
||||
true
|
||||
end
|
||||
|
||||
def setup(credentials = {})
|
||||
requires :public_ip_address, :identity, :public_key, :username
|
||||
Fog::SSH.new(public_ip_address, username, credentials).run([
|
||||
%{mkdir .ssh},
|
||||
%{echo "#{public_key}" >> ~/.ssh/authorized_keys},
|
||||
%{passwd -l #{username}},
|
||||
%{echo "#{MultiJson.encode(attributes)}" >> ~/attributes.json},
|
||||
%{echo "#{MultiJson.encode(metadata)}" >> ~/metadata.json}
|
||||
])
|
||||
rescue Errno::ECONNREFUSED
|
||||
sleep(1)
|
||||
retry
|
||||
end
|
||||
|
||||
def username
|
||||
@username ||= 'root'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def adminPass=(new_admin_pass)
|
||||
@password = new_admin_pass
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
36
lib/fog/openstack/models/compute/servers.rb
Normal file
36
lib/fog/openstack/models/compute/servers.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/openstack/models/compute/server'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Servers < Fog::Collection
|
||||
|
||||
model Fog::Compute::OpenStack::Server
|
||||
|
||||
def all
|
||||
data = connection.list_servers_detail.body['servers']
|
||||
load(data)
|
||||
end
|
||||
|
||||
def bootstrap(new_attributes = {})
|
||||
server = create(new_attributes)
|
||||
server.wait_for { ready? }
|
||||
server.setup(:password => server.password)
|
||||
server
|
||||
end
|
||||
|
||||
def get(server_id)
|
||||
if server = connection.get_server_details(server_id).body['server']
|
||||
new(server)
|
||||
end
|
||||
rescue Fog::Compute::OpenStack::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
33
lib/fog/openstack/models/meta_parent.rb
Normal file
33
lib/fog/openstack/models/meta_parent.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
module MetaParent
|
||||
|
||||
def parent
|
||||
@parent
|
||||
end
|
||||
|
||||
def parent=(new_parent)
|
||||
@parent = new_parent
|
||||
end
|
||||
|
||||
def collection_name
|
||||
if @parent.class == Fog::Compute::OpenStack::Image
|
||||
return "images"
|
||||
elsif @parent.class == Fog::Compute::OpenStack::Server
|
||||
return "servers"
|
||||
else
|
||||
raise "Metadata is not supported for this model type."
|
||||
end
|
||||
end
|
||||
|
||||
def metas_to_hash(metas)
|
||||
hash = {}
|
||||
metas.each { |meta| hash.store(meta.key, meta.value) }
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
lib/fog/openstack/requests/compute/change_password_server.rb
Normal file
24
lib/fog/openstack/requests/compute/change_password_server.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def change_password_server(server_id, admin_password)
|
||||
body = { 'changePassword' => { 'adminPass' => admin_password }}
|
||||
server_action(server_id, body)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def change_password_server(server_id, admin_password)
|
||||
response = Excon::Response.new
|
||||
response.status = 202
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
lib/fog/openstack/requests/compute/confirm_resized_server.rb
Normal file
24
lib/fog/openstack/requests/compute/confirm_resized_server.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def confirm_resized_server(server_id)
|
||||
body = { 'confirmResize' => nil }
|
||||
server_action(server_id, body, 204)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def confirm_resized_server(server_id)
|
||||
response = Excon::Response.new
|
||||
response.status = 204
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
27
lib/fog/openstack/requests/compute/create_image.rb
Normal file
27
lib/fog/openstack/requests/compute/create_image.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def create_image(server_id, name, metadata={})
|
||||
body = { 'createImage' => {
|
||||
'name' => name,
|
||||
'metadata' => metadata
|
||||
}}
|
||||
server_action(server_id, body)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def create_image(server_id, name, metadata={})
|
||||
response = Excon::Response.new
|
||||
response.status = 202
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
72
lib/fog/openstack/requests/compute/create_server.rb
Normal file
72
lib/fog/openstack/requests/compute/create_server.rb
Normal file
|
@ -0,0 +1,72 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def create_server(name, image_ref, flavor_ref, options = {})
|
||||
data = {
|
||||
'server' => {
|
||||
'flavorRef' => flavor_ref,
|
||||
'imageRef' => image_ref,
|
||||
'name' => name
|
||||
}
|
||||
}
|
||||
|
||||
if options['metadata']
|
||||
data['server']['metadata'] = options['metadata']
|
||||
end
|
||||
if options['accessIPv4']
|
||||
data['server']['accessIPv4'] = options['accessIPv4']
|
||||
end
|
||||
if options['accessIPv6']
|
||||
data['server']['accessIPv6'] = options['accessIPv6']
|
||||
end
|
||||
if options['personality']
|
||||
data['server']['personality'] = []
|
||||
for file in options['personality']
|
||||
data['server']['personality'] << {
|
||||
'contents' => Base64.encode64(file['contents']),
|
||||
'path' => file['path']
|
||||
}
|
||||
end
|
||||
end
|
||||
request(
|
||||
:body => MultiJson.encode(data),
|
||||
:expects => [200, 202],
|
||||
:method => 'POST',
|
||||
:path => 'servers.json'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def create_server(name, image_ref, flavor_ref, options = {})
|
||||
response = Excon::Response.new
|
||||
response.status = 202
|
||||
|
||||
data = {
|
||||
'addresses' => {},
|
||||
'flavor' => {"id"=>"1", "links"=>[{"href"=>"http://nova1:8774/admin/flavors/1", "rel"=>"bookmark"}]},
|
||||
'id' => Fog::Mock.random_numbers(6).to_s,
|
||||
'image' => {"id"=>"3", "links"=>[{"href"=>"http://nova1:8774/admin/images/3", "rel"=>"bookmark"}]},
|
||||
'links' => [{"href"=>"http://nova1:8774/v1.1/admin/servers/5", "rel"=>"self"}, {"href"=>"http://nova1:8774/admin/servers/5", "rel"=>"bookmark"}],
|
||||
'hostId' => "123456789ABCDEF01234567890ABCDEF",
|
||||
'metadata' => options['metadata'] || {},
|
||||
'name' => options['name'] || "server_#{rand(999)}",
|
||||
'accessIPv4' => options['accessIPv4'] || "",
|
||||
'accessIPv6' => options['accessIPv6'] || "",
|
||||
'progress' => 0,
|
||||
'status' => 'BUILD'
|
||||
}
|
||||
self.data[:last_modified][:servers][data['id']] = Time.now
|
||||
self.data[:servers][data['id']] = data
|
||||
response.body = { 'server' => data.merge({'adminPass' => 'password'}) }
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
40
lib/fog/openstack/requests/compute/delete_image.rb
Normal file
40
lib/fog/openstack/requests/compute/delete_image.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
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
|
||||
if image = list_images_detail.body['images'].detect {|_| _['id'] == image_id}
|
||||
if image['status'] == 'SAVING'
|
||||
response.status = 409
|
||||
raise(Excon::Errors.status_error({:expects => 202}, response))
|
||||
else
|
||||
self.data[:last_modified][:images].delete(image_id)
|
||||
self.data[:images].delete(image_id)
|
||||
response.status = 202
|
||||
end
|
||||
response
|
||||
else
|
||||
response.status = 400
|
||||
raise(Excon::Errors.status_error({:expects => 202}, response))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
28
lib/fog/openstack/requests/compute/delete_meta.rb
Normal file
28
lib/fog/openstack/requests/compute/delete_meta.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def delete_meta(collection_name, parent_id, key)
|
||||
request(
|
||||
:expects => 204,
|
||||
:method => 'DELETE',
|
||||
:path => "#{collection_name}/#{parent_id}/metadata/#{key}"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def delete_meta(collection_name, parent_id, key)
|
||||
response = Excon::Response.new
|
||||
response.status = 204
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
38
lib/fog/openstack/requests/compute/delete_server.rb
Normal file
38
lib/fog/openstack/requests/compute/delete_server.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def delete_server(server_id)
|
||||
request(
|
||||
:expects => 204,
|
||||
:method => 'DELETE',
|
||||
:path => "servers/#{server_id}"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def delete_server(server_id)
|
||||
response = Excon::Response.new
|
||||
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
|
||||
if server['status'] == 'BUILD'
|
||||
response.status = 409
|
||||
raise(Excon::Errors.status_error({:expects => 204}, response))
|
||||
else
|
||||
self.data[:last_modified][:servers].delete(server_id)
|
||||
self.data[:servers].delete(server_id)
|
||||
response.status = 204
|
||||
end
|
||||
response
|
||||
else
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
43
lib/fog/openstack/requests/compute/get_flavor_details.rb
Normal file
43
lib/fog/openstack/requests/compute/get_flavor_details.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def get_flavor_details(flavor_ref)
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => "flavors/#{flavor_ref}.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_flavor_details(flavor_ref)
|
||||
response = Excon::Response.new
|
||||
flavor = {
|
||||
'1' => { 'id' => '1', 'name' => '256 server', 'ram' => 256, 'disk' => 10, 'links' => [] },
|
||||
'2' => { 'id' => '2', 'name' => '512 server', 'ram' => 512, 'disk' => 20, 'links' => [] },
|
||||
'3' => { 'id' => '3', 'name' => '1GB server', 'ram' => 1024, 'disk' => 40, 'links' => [] },
|
||||
'4' => { 'id' => '4', 'name' => '2GB server', 'ram' => 2048, 'disk' => 80, 'links' => [] },
|
||||
'5' => { 'id' => '5', 'name' => '4GB server', 'ram' => 4096, 'disk' => 160, 'links' => [] },
|
||||
'6' => { 'id' => '6', 'name' => '8GB server', 'ram' => 8192, 'disk' => 320, 'links' => [] },
|
||||
'7' => { 'id' => '7', 'name' => '15.5GB server', 'ram' => 15872, 'disk' => 620, 'links' => [] }
|
||||
}[flavor_ref]
|
||||
if flavor
|
||||
response.status = 200
|
||||
response.body = {
|
||||
'flavor' => flavor
|
||||
}
|
||||
response
|
||||
else
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
17
lib/fog/openstack/requests/compute/get_image_details.rb
Normal file
17
lib/fog/openstack/requests/compute/get_image_details.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def get_image_details(image_id)
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => "images/#{image_id}.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
29
lib/fog/openstack/requests/compute/get_meta.rb
Normal file
29
lib/fog/openstack/requests/compute/get_meta.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def get_meta(collection_name, parent_id, key)
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => "#{collection_name}/#{parent_id}/metadata/#{key}"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_meta(collection_name, parent_id, key)
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = { 'meta' => {} }
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
32
lib/fog/openstack/requests/compute/get_server_details.rb
Normal file
32
lib/fog/openstack/requests/compute/get_server_details.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def get_server_details(server_id)
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => "servers/#{server_id}.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_server_details(server_id)
|
||||
response = Excon::Response.new
|
||||
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
|
||||
response.status = [200, 203][rand(1)]
|
||||
response.body = { 'server' => server }
|
||||
response
|
||||
else
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
32
lib/fog/openstack/requests/compute/list_addresses.rb
Normal file
32
lib/fog/openstack/requests/compute/list_addresses.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_addresses(server_id)
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => "servers/#{server_id}/ips.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_addresses(server_id)
|
||||
response = Excon::Response.new
|
||||
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
|
||||
response.status = [200, 203][rand(1)]
|
||||
response.body = { 'addresses' => server['addresses'] }
|
||||
response
|
||||
else
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
38
lib/fog/openstack/requests/compute/list_flavors.rb
Normal file
38
lib/fog/openstack/requests/compute/list_flavors.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_flavors
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => 'flavors.json'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_flavors
|
||||
response = Excon::Response.new
|
||||
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' }
|
||||
]
|
||||
}
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
38
lib/fog/openstack/requests/compute/list_flavors_detail.rb
Normal file
38
lib/fog/openstack/requests/compute/list_flavors_detail.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_flavors_detail
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => 'flavors/detail.json'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_flavors_detail
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = {
|
||||
'flavors' => [
|
||||
{ 'name' => '256 server', 'id' => '1', 'ram' => 256, 'disk' => 10, 'links' => [] },
|
||||
{ 'name' => '512 server', 'id' => '2', 'ram' => 512, 'disk' => 20, 'links' => [] },
|
||||
{ 'name' => '1GB server', 'id' => '3', 'ram' => 1024, 'disk' => 40, 'links' => [] },
|
||||
{ 'name' => '2GB server', 'id' => '4', 'ram' => 2048, 'disk' => 80, 'links' => [] },
|
||||
{ 'name' => '4GB server', 'id' => '5', 'ram' => 4096, 'disk' => 160, 'links' => [] },
|
||||
{ 'name' => '8GB server', 'id' => '6', 'ram' => 8192, 'disk' => 320, 'links' => [] },
|
||||
{ 'name' => '15.5GB server', 'id' => '7', 'ram' => 15872, 'disk' => 620, 'links' => [] }
|
||||
]
|
||||
}
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
33
lib/fog/openstack/requests/compute/list_images.rb
Normal file
33
lib/fog/openstack/requests/compute/list_images.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_images
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => 'images.json'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_images
|
||||
response = Excon::Response.new
|
||||
data = list_images_detail.body['images']
|
||||
images = []
|
||||
for image in data
|
||||
images << image.reject { |key, value| !['id', 'name'].include?(key) }
|
||||
end
|
||||
response.status = [200, 203][rand(1)]
|
||||
response.body = { 'images' => images }
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
39
lib/fog/openstack/requests/compute/list_images_detail.rb
Normal file
39
lib/fog/openstack/requests/compute/list_images_detail.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_images_detail
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => 'images/detail.json'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_images_detail
|
||||
response = Excon::Response.new
|
||||
|
||||
images = self.data[:images].values
|
||||
for image in images
|
||||
case image['status']
|
||||
when 'SAVING'
|
||||
if Time.now - self.data[:last_modified][:images][image['id']] >= Fog::Mock.delay
|
||||
image['status'] = 'ACTIVE'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
response.status = [200, 203][rand(1)]
|
||||
response.body = { 'images' => images.map {|image| image.reject {|key, value| !['id', 'name', 'status', 'updated'].include?(key)}} }
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
28
lib/fog/openstack/requests/compute/list_metadata.rb
Normal file
28
lib/fog/openstack/requests/compute/list_metadata.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_metadata(collection_name, parent_id)
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => "/#{collection_name}/#{parent_id}/metadata.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_metadata(collection_name, parent_id)
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = {}
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
32
lib/fog/openstack/requests/compute/list_private_addresses.rb
Normal file
32
lib/fog/openstack/requests/compute/list_private_addresses.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_private_addresses(server_id)
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => "servers/#{server_id}/ips/private.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_private_addresses(server_id)
|
||||
response = Excon::Response.new
|
||||
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
|
||||
response.status = [200, 203][rand(1)]
|
||||
response.body = { 'private' => server['addresses']['private'] }
|
||||
response
|
||||
else
|
||||
raise Fog::Compute::Rackspace::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
32
lib/fog/openstack/requests/compute/list_public_addresses.rb
Normal file
32
lib/fog/openstack/requests/compute/list_public_addresses.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_public_addresses(server_id)
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => "servers/#{server_id}/ips/public.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_public_addresses(server_id)
|
||||
response = Excon::Response.new
|
||||
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
|
||||
response.status = [200, 203][rand(1)]
|
||||
response.body = { 'public' => server['addresses']['public'] }
|
||||
response
|
||||
else
|
||||
raise Fog::Compute::Rackspace::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
33
lib/fog/openstack/requests/compute/list_servers.rb
Normal file
33
lib/fog/openstack/requests/compute/list_servers.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_servers
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => 'servers.json'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_servers
|
||||
response = Excon::Response.new
|
||||
data = list_servers_detail.body['servers']
|
||||
servers = []
|
||||
for server in data
|
||||
servers << server.reject { |key, value| !['id', 'name'].include?(key) }
|
||||
end
|
||||
response.status = [200, 203][rand(1)]
|
||||
response.body = { 'servers' => servers }
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
39
lib/fog/openstack/requests/compute/list_servers_detail.rb
Normal file
39
lib/fog/openstack/requests/compute/list_servers_detail.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_servers_detail
|
||||
request(
|
||||
:expects => [200, 203],
|
||||
:method => 'GET',
|
||||
:path => 'servers/detail.json'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_servers_detail
|
||||
response = Excon::Response.new
|
||||
|
||||
servers = self.data[:servers].values
|
||||
for server in servers
|
||||
case server['status']
|
||||
when 'BUILD'
|
||||
if Time.now - self.data[:last_modified][:servers][server['id']] > Fog::Mock.delay * 2
|
||||
server['status'] = 'ACTIVE'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
response.status = [200, 203][rand(1)]
|
||||
response.body = { 'servers' => servers }
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
lib/fog/openstack/requests/compute/reboot_server.rb
Normal file
24
lib/fog/openstack/requests/compute/reboot_server.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def reboot_server(server_id, type = 'SOFT')
|
||||
body = { 'reboot' => { 'type' => type }}
|
||||
server_action(server_id, body)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def reboot_server(server_id, type = 'SOFT')
|
||||
response = Excon::Response.new
|
||||
response.status = 202
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
30
lib/fog/openstack/requests/compute/rebuild_server.rb
Normal file
30
lib/fog/openstack/requests/compute/rebuild_server.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def rebuild_server(server_id, name, metadata=nil, personality=nil)
|
||||
|
||||
body = { 'rebuild' => {
|
||||
'name' => name
|
||||
}}
|
||||
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)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def rebuild_server(server_id, name, metadata, personality)
|
||||
response = Excon::Response.new
|
||||
response.status = 202
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
lib/fog/openstack/requests/compute/resize_server.rb
Normal file
24
lib/fog/openstack/requests/compute/resize_server.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def resize_server(server_id, flavor_ref)
|
||||
body = { 'resize' => { 'flavor' => { 'id' => flavor_ref }}}
|
||||
server_action(server_id, body)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def resize_server(server_id, flavor_ref)
|
||||
response = Excon::Response.new
|
||||
response.status = 202
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
30
lib/fog/openstack/requests/compute/revert_resized_server.rb
Normal file
30
lib/fog/openstack/requests/compute/revert_resized_server.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def revert_resized_server(server_id)
|
||||
body = { 'revertResize' => nil }
|
||||
server_action(server_id, body)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def revert_resized_server(server_id)
|
||||
response = Excon::Response.new
|
||||
response.status = 202
|
||||
|
||||
self.data[:servers][server_id]['flavorId'] = self.data[:servers][server_id]['old_flavorId']
|
||||
self.data[:servers][server_id].delete('old_flavorId')
|
||||
self.data[:last_modified][:servers][server_id] = Time.now
|
||||
self.data[:servers][server_id]['status'] = 'ACTIVE'
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
lib/fog/openstack/requests/compute/server_action.rb
Normal file
18
lib/fog/openstack/requests/compute/server_action.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def server_action(server_id, body, expects=202)
|
||||
request(
|
||||
:body => MultiJson.encode(body),
|
||||
:expects => expects,
|
||||
:method => 'POST',
|
||||
:path => "servers/#{server_id}/action.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
45
lib/fog/openstack/requests/compute/set_metadata.rb
Normal file
45
lib/fog/openstack/requests/compute/set_metadata.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Real
|
||||
|
||||
def set_metadata(collection_name, parent_id, metadata = {})
|
||||
request(
|
||||
:body => MultiJson.encode({ 'metadata' => metadata }),
|
||||
:expects => 200,
|
||||
:method => 'PUT',
|
||||
:path => "#{collection_name}/#{parent_id}/metadata"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def set_metadata(collection_name, parent_id, metadata = {})
|
||||
|
||||
if collection_name == "images" then
|
||||
if not list_images_detail.body['images'].detect {|_| _['id'] == parent_id}
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
if collection_name == "servers" then
|
||||
if not list_servers_detail.body['servers'].detect {|_| _['id'] == parent_id}
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
response = Excon::Response.new
|
||||
response.body = { "metadata" => metadata }
|
||||
response.status = 200
|
||||
response
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
45
lib/fog/openstack/requests/compute/update_meta.rb
Normal file
45
lib/fog/openstack/requests/compute/update_meta.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Real
|
||||
|
||||
def update_meta(collection_name, parent_id, key, value)
|
||||
request(
|
||||
:body => MultiJson.encode({ 'meta' => { key => value }}),
|
||||
:expects => 200,
|
||||
:method => 'PUT',
|
||||
:path => "#{collection_name}/#{parent_id}/metadata/#{key}"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def update_meta(collection_name, parent_id, key, value)
|
||||
|
||||
if collection_name == "images" then
|
||||
if not list_images_detail.body['images'].detect {|_| _['id'] == parent_id}
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
if collection_name == "servers" then
|
||||
if not list_servers_detail.body['servers'].detect {|_| _['id'] == parent_id}
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
response = Excon::Response.new
|
||||
response.body = { "meta" => { key => value } }
|
||||
response.status = 200
|
||||
response
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
46
lib/fog/openstack/requests/compute/update_metadata.rb
Normal file
46
lib/fog/openstack/requests/compute/update_metadata.rb
Normal file
|
@ -0,0 +1,46 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
|
||||
class Real
|
||||
|
||||
def update_metadata(collection_name, parent_id, metadata = {})
|
||||
request(
|
||||
:body => MultiJson.encode({ 'metadata' => metadata }),
|
||||
:expects => 200,
|
||||
:method => 'POST',
|
||||
:path => "#{collection_name}/#{parent_id}/metadata.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def update_metadata(collection_name, parent_id, metadata = {})
|
||||
|
||||
if collection_name == "images" then
|
||||
if not list_images_detail.body['images'].detect {|_| _['id'] == parent_id}
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
if collection_name == "servers" then
|
||||
if not list_servers_detail.body['servers'].detect {|_| _['id'] == parent_id}
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
#FIXME join w/ existing metadata here
|
||||
response = Excon::Response.new
|
||||
response.body = { "metadata" => metadata }
|
||||
response.status = 200
|
||||
response
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
35
lib/fog/openstack/requests/compute/update_server.rb
Normal file
35
lib/fog/openstack/requests/compute/update_server.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def update_server(server_id, options = {})
|
||||
request(
|
||||
:body => MultiJson.encode({ 'server' => options }),
|
||||
:expects => 200,
|
||||
:method => 'PUT',
|
||||
:path => "servers/#{server_id}.json"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def update_server(server_id, options)
|
||||
response = Excon::Response.new
|
||||
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
|
||||
if options['name']
|
||||
server['name'] = options['name']
|
||||
end
|
||||
response.status = 200
|
||||
response
|
||||
else
|
||||
raise Fog::Compute::OpenStack::NotFound
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -38,6 +38,10 @@ if Fog.mock?
|
|||
:ninefold_storage_token => 'ninefold_storage_token',
|
||||
# :public_key_path => '~/.ssh/id_rsa.pub',
|
||||
# :private_key_path => '~/.ssh/id_rsa',
|
||||
:openstack_api_key => 'openstack_api_key',
|
||||
:openstack_username => 'openstack_username',
|
||||
:openstack_tenant => 'openstack_tenant',
|
||||
:openstack_auth_url => 'openstack_auth_url',
|
||||
:rackspace_api_key => 'rackspace_api_key',
|
||||
:rackspace_username => 'rackspace_username',
|
||||
:slicehost_password => 'slicehost_password',
|
||||
|
|
35
tests/openstack/requests/compute/flavor_tests.rb
Normal file
35
tests/openstack/requests/compute/flavor_tests.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
Shindo.tests('Fog::Compute[:openstack] | flavor requests', ['openstack']) do
|
||||
|
||||
@flavor_format = {
|
||||
'disk' => Integer,
|
||||
'id' => String,
|
||||
'name' => String,
|
||||
'ram' => Integer,
|
||||
'links' => Array
|
||||
}
|
||||
|
||||
tests('success') do
|
||||
|
||||
tests('#get_flavor_details(1)').formats(@flavor_format) do
|
||||
Fog::Compute[:openstack].get_flavor_details("1").body['flavor']
|
||||
end
|
||||
|
||||
tests('#list_flavors').formats({'flavors' => [OpenStack::Compute::Formats::SUMMARY]}) do
|
||||
Fog::Compute[:openstack].list_flavors.body
|
||||
end
|
||||
|
||||
tests('#list_flavors_detail').formats({'flavors' => [@flavor_format]}) do
|
||||
Fog::Compute[:openstack].list_flavors_detail.body
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
tests('failure') do
|
||||
|
||||
tests('#get_flavor_details(0)').raises(Fog::Compute::OpenStack::NotFound) do
|
||||
Fog::Compute[:openstack].get_flavor_details("0")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
16
tests/openstack/requests/compute/helper.rb
Normal file
16
tests/openstack/requests/compute/helper.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
class OpenStack
|
||||
|
||||
module Compute
|
||||
|
||||
module Formats
|
||||
|
||||
SUMMARY = {
|
||||
'id' => String,
|
||||
'name' => String
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
64
tests/openstack/requests/compute/image_tests.rb
Normal file
64
tests/openstack/requests/compute/image_tests.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
Shindo.tests('Fog::Compute[:openstack] | image requests', ['openstack']) do
|
||||
|
||||
@image_format = {
|
||||
'created' => Fog::Nullable::String,
|
||||
'id' => String,
|
||||
'name' => String,
|
||||
'progress' => Fog::Nullable::Integer,
|
||||
'status' => String,
|
||||
'updated' => String,
|
||||
'minRam' => String,
|
||||
'minDisk' => String,
|
||||
#'server' => Hash,
|
||||
'metadata' => Hash,
|
||||
'links' => Array
|
||||
}
|
||||
|
||||
tests('success') do
|
||||
|
||||
@image_id = 1
|
||||
|
||||
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']
|
||||
end
|
||||
|
||||
tests('#list_images').formats({'images' => [OpenStack::Compute::Formats::SUMMARY]}) do
|
||||
Fog::Compute[:openstack].list_images.body
|
||||
end
|
||||
|
||||
tests('#list_images_detail').formats({'images' => [@image_format]}) do
|
||||
Fog::Compute[:openstack].list_images_detail.body
|
||||
end
|
||||
|
||||
unless Fog.mocking?
|
||||
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
|
||||
Fog::Compute[:openstack].delete_image(0)
|
||||
end
|
||||
|
||||
tests('#get_image_details(0)').raises(Fog::Compute::OpenStack::NotFound) do
|
||||
pending if Fog.mocking?
|
||||
Fog::Compute[:openstack].get_image_details(0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
89
tests/openstack/requests/compute/server_tests.rb
Normal file
89
tests/openstack/requests/compute/server_tests.rb
Normal file
|
@ -0,0 +1,89 @@
|
|||
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,
|
||||
'accessIPv4' => Fog::Nullable::String,
|
||||
'accessIPv6' => Fog::Nullable::String,
|
||||
'links' => Array
|
||||
}
|
||||
|
||||
tests('success') do
|
||||
|
||||
@server_id = nil
|
||||
|
||||
tests('#create_server("test", 1, 19)').formats(@server_format.merge('adminPass' => String)) do
|
||||
data = Fog::Compute[:openstack].create_server("test", 3, 1).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
|
||||
Fog::Compute[:openstack].get_server_details(@server_id).body['server']
|
||||
end
|
||||
|
||||
tests('#list_servers').formats({'servers' => [OpenStack::Compute::Formats::SUMMARY]}) do
|
||||
Fog::Compute[:openstack].list_servers.body
|
||||
end
|
||||
|
||||
tests('#list_servers_detail').formats({'servers' => [@server_format]}) do
|
||||
Fog::Compute[:openstack].list_servers_detail.body
|
||||
end
|
||||
|
||||
Fog::Compute[:openstack].servers.get(@server_id).wait_for { ready? }
|
||||
|
||||
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? }
|
||||
|
||||
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? }
|
||||
|
||||
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? }
|
||||
|
||||
tests("#delete_server(#{@server_id})").succeeds do
|
||||
Fog::Compute[:openstack].delete_server(@server_id)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
tests('failure') do
|
||||
|
||||
tests('#delete_server(0)').raises(Fog::Compute::OpenStack::NotFound) do
|
||||
Fog::Compute[:openstack].delete_server(0)
|
||||
end
|
||||
|
||||
tests('#get_server_details(0)').raises(Fog::Compute::OpenStack::NotFound) do
|
||||
Fog::Compute[:openstack].get_server_details(0)
|
||||
end
|
||||
|
||||
tests("#update_server(0, :name => 'fogupdatedserver', :adminPass => 'fogupdatedserver')").raises(Fog::Compute::OpenStack::NotFound) do
|
||||
Fog::Compute[:openstack].update_server(0, :name => 'fogupdatedserver', :adminPass => 'fogupdatedserver')
|
||||
end
|
||||
|
||||
tests('#reboot_server(0)').raises(Fog::Compute::OpenStack::NotFound) do
|
||||
pending if Fog.mocking?
|
||||
Fog::Compute[:openstack].reboot_server(0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue