1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Merge branch 'rupakg'

Conflicts:
	lib/fog/providers.rb
This commit is contained in:
geemus 2012-04-17 07:30:03 -05:00
commit db6525a709
105 changed files with 5540 additions and 2 deletions

View file

@ -10,6 +10,7 @@ Gem::Specification.new do |s|
s.date = '2012-03-27'
s.rubyforge_project = 'fog'
## Make sure your summary is short. The description may be as long
## as you like.
s.summary = "brings clouds to you"
@ -26,6 +27,10 @@ Gem::Specification.new do |s|
# s.require_paths << 'ext'
# s.extensions = %w[ext/extconf.rb]
## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
s.require_paths = %w[lib]
## If your gem includes any executables, list them here.
s.executables = ["fog"]

View file

@ -64,6 +64,7 @@ require 'fog/bin/ecloud'
require 'fog/bin/glesys'
require 'fog/bin/go_grid'
require 'fog/bin/google'
require 'fog/bin/hp'
require 'fog/bin/ibm'
require 'fog/bin/joyent'
require 'fog/bin/libvirt'

38
lib/fog/bin/hp.rb Normal file
View file

@ -0,0 +1,38 @@
class HP < Fog::Bin
class << self
def class_for(key)
case key
when :cdn
Fog::HP::CDN
when :compute
Fog::HP::Compute
when :storage
Fog::HP::Storage
else
raise ArgumentError, "Unrecognized service: #{key}"
end
end
def [](service)
@@connections ||= Hash.new do |hash, key|
hash[key] = case key
when :cdn
Fog::CDN.new(:provider => 'HP')
when :compute
Fog::Compute.new(:provider => 'HP')
when :storage
Fog::Storage.new(:provider => 'HP')
else
raise ArgumentError, "Unrecognized service: #{key.inspect}"
end
end
@@connections[service]
end
def services
Fog::HP.services
end
end
end

View file

@ -11,6 +11,9 @@ module Fog
when :aws
require 'fog/aws/cdn'
Fog::CDN::AWS.new(attributes)
when :hp
require 'fog/hp/cdn'
Fog::CDN::HP.new(attributes)
when :rackspace
require 'fog/rackspace/cdn'
Fog::CDN::Rackspace.new(attributes)

View file

@ -32,6 +32,9 @@ module Fog
when :gogrid
require 'fog/go_grid/compute'
Fog::Compute::GoGrid.new(attributes)
when :hp
require 'fog/hp/compute'
Fog::Compute::HP.new(attributes)
when :ibm
require 'fog/ibm/compute'
Fog::Compute::IBM.new(attributes)

View file

@ -44,6 +44,9 @@ An alternate file may be used by placing its path in the FOG_RC environment vari
:go_grid_shared_secret:
:google_storage_access_key_id:
:google_storage_secret_access_key:
:hp_account_id:
:hp_secret_key:
:hp_tenant_id:
:linode_api_key:
:local_root:
:bare_metal_cloud_password:

View file

@ -96,7 +96,12 @@ module Fog
attr_accessor :command, :stderr, :stdout, :status
def display_stdout
Formatador.display_line(stdout.split("\r\n"))
data = stdout.split("\r\n")
if data.is_a?(String)
Formatador.display_line(data)
elsif data.is_a?(Array)
Formatador.display_lines(data)
end
end
def display_stderr

234
lib/fog/hp.rb Normal file
View file

@ -0,0 +1,234 @@
require(File.expand_path(File.join(File.dirname(__FILE__), 'core')))
module Fog
module HP
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(:cdn, 'hp/cdn', 'CDN')
service(:compute, 'hp/compute', 'Compute')
service(:storage, 'hp/storage', 'Storage')
# legacy swauth 1.0/1.1 style authentication
def self.authenticate_v1(options, connection_options = {})
hp_auth_uri = options[:hp_auth_uri] || "https://region-a.geo-1.objects.hpcloudsvc.com/auth/v1.0/"
endpoint = URI.parse(hp_auth_uri)
@scheme = endpoint.scheme || "http"
@host = endpoint.host || "region-a.geo-1.objects.hpcloudsvc.com"
@port = endpoint.port.to_s || "80"
if (endpoint.path)
@auth_path = endpoint.path.slice(1, endpoint.path.length) # remove the leading slash
else
@auth_path = "auth/v1.0"
end
service_url = "#{@scheme}://#{@host}:#{@port}"
connection = Fog::Connection.new(service_url, false, connection_options)
@hp_account_id = options[:hp_account_id]
@hp_secret_key = options[:hp_secret_key]
response = connection.request({
:expects => [200, 204],
:headers => {
'X-Auth-Key' => @hp_secret_key,
'X-Auth-User' => @hp_account_id
},
:host => @host,
:port => @port,
:method => 'GET',
:path => @auth_path
})
response.headers.reject do |key, value|
!['X-Server-Management-Url', 'X-Storage-Url', 'X-CDN-Management-Url', 'X-Auth-Token'].include?(key)
end
return {
:auth_token => response.headers['X-Auth-Token'],
:endpoint_url => nil,
:cdn_endpoint_url => response.headers['X-Storage-Url']
}
end
# keystone based control services style authentication
def self.authenticate_v2(options, connection_options = {})
hp_auth_uri = options[:hp_auth_uri] || "https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/tokens"
# append /tokens if missing from auth uri
@hp_auth_uri = hp_auth_uri.include?('tokens')? hp_auth_uri : hp_auth_uri + "tokens"
endpoint = URI.parse(@hp_auth_uri)
@scheme = endpoint.scheme || "https"
@host = endpoint.host || "region-a.geo-1.identity.hpcloudsvc.com"
@port = endpoint.port.to_s || "35357"
if (endpoint.path)
@auth_path = endpoint.path.slice(1, endpoint.path.length) # remove the leading slash
else
@auth_path = "v2.0/tokens"
end
service_url = "#{@scheme}://#{@host}:#{@port}"
connection = Fog::Connection.new(service_url, false, connection_options)
### Implement HP Control Services Authentication services ###
# Get the style of auth credentials passed, defaults to access/secret key style
@hp_use_upass_auth_style = options[:hp_use_upass_auth_style] || false
@hp_account_id = options[:hp_account_id]
@hp_secret_key = options[:hp_secret_key]
@hp_tenant_id = options[:hp_tenant_id]
@hp_service_type = options[:hp_service_type]
@hp_avl_zone = options[:hp_avl_zone] || :az1
### Decide which auth style to use
unless (@hp_use_upass_auth_style)
# If Access Key style credentials are provided, use that
request_body = {
'auth' => {
'apiAccessKeyCredentials' => {
'accessKey' => "#{@hp_account_id}",
'secretKey' => "#{@hp_secret_key}"
}
}
}
else
# Otherwise use the Username/Password style
request_body = {
'auth' => {
'passwordCredentials' => {
'username' => "#{@hp_account_id}",
'password' => "#{@hp_secret_key}"
}
}
}
end
# add tenant_id if specified
request_body['auth']['tenantId'] = "#{@hp_tenant_id}" if @hp_tenant_id
### Make the call to CS to get auth token and service catalog
response = connection.request(
{
:expects => 200,
:headers => {
'Content-Type' => 'application/json'
},
:host => @host,
:port => @port,
:method => 'POST',
:body => MultiJson.encode(request_body),
:path => @auth_path
}
)
body = MultiJson.decode(response.body)
### fish out auth_token and endpoint for the service
auth_token = body['access']['token']['id']
endpoint_url = get_endpoint_from_catalog(body['access']['serviceCatalog'], @hp_service_type, @hp_avl_zone)
# If service is Storage, then get the CDN endpoint as well
if @hp_service_type == "object-store"
cdn_endpoint_url = get_endpoint_from_catalog(body['access']['serviceCatalog'], "hpext:cdn", @hp_avl_zone)
end
return {
:auth_token => auth_token,
:endpoint_url => endpoint_url,
:cdn_endpoint_url => cdn_endpoint_url
}
end
# CGI.escape, but without special treatment on spaces
def self.escape(str,extra_exclude_chars = '')
str.gsub(/([^a-zA-Z0-9_.-#{extra_exclude_chars}]+)/) do
'%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
end
end
private
def self.get_endpoint_from_catalog(service_catalog, service_type, avl_zone)
if service_catalog
service_item = service_catalog.select {|s| s["type"] == service_type}.first
if service_item and service_item['endpoints'] and
if avl_zone == :az1
endpoint_url = service_item['endpoints'][0]['publicURL'] if service_item['endpoints'][0]
elsif avl_zone == :az2
endpoint_url = service_item['endpoints'][1]['publicURL'] if service_item['endpoints'][1]
end
raise "Unable to retrieve endpoint service url from service catalog." if endpoint_url.nil?
return endpoint_url
end
else
raise "Unable to parse service catalog."
end
end
class Mock
def self.etag
Fog::Mock.random_hex(32)
end
def self.key_fingerprint
fingerprint = []
20.times do
fingerprint << Fog::Mock.random_hex(2)
end
fingerprint.join(':')
end
def self.key_material
private_key = OpenSSL::PKey::RSA.generate(1024)
public_key = private_key.public_key
return private_key.to_s, public_key.to_s
end
def self.user_id
"dev_" + Fog::Mock.random_numbers(14)
end
def self.instance_id
Fog::Mock.random_numbers(6)
end
def self.ip_address
ip = []
4.times do
ip << Fog::Mock.random_numbers(rand(3) + 1).to_i.to_s # remove leading 0
end
ip.join('.')
end
end
end
end

60
lib/fog/hp/README_HP.rdoc Normal file
View file

@ -0,0 +1,60 @@
= HP Cloud Extensions to Ruby Fog Library
HP contributed to the native Ruby library Fog, through an HP Cloud developed extension to Fog via
the Object Storage, Compute and CDN providers. By using the HP Cloud Extensions to Fog, developers
can write applications using Ruby that interacts with the HP Cloud Services without having to deal
with the underlying REST API or JSON/XML document formats.
== Background
This library is an extension of Fog[https://github.com/fog/fog], a Ruby open-source cloud
computing library. The code in this library, contains all HP-specific support and is being
contributed back to the primary open-source library.
The HP Cloud Ruby library currently supports HP Cloud Object Storage, Compute, CDN, and
support for other services will be added as available.
== Installation
sudo gem install fog
That's it! Try out the usage examples explained below to confirm your installation.
If you should ever need to remove the library:
sudo gem uninstall fog
== Usage
The Ruby Fog library is well documented on the community web site at {fog.io}[http://fog.io], but for specific examples
using HP's extensions, see:
* {HP Cloud Fog library - Object Storage Examples}[https://build.hpcloud.com/bindings/fog/object-storage]
* {HP Cloud Fog library - Compute Examples}[https://build.hpcloud.com/bindings/fog/compute]
* {HP Cloud Fog library - CDN Examples}[https://build.hpcloud.com/bindings/fog/cdn]
Having trouble? {Get help over at the Forums}[https://connect.hpcloud.com]
== Notice
The following notice applies to files included in the /lib/fog/hp directory and its sub-directories.
Copyright (c) 2011 Hewlett-Packard Development Company, L.P.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

130
lib/fog/hp/cdn.rb Normal file
View file

@ -0,0 +1,130 @@
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'hp'))
require 'fog/cdn'
module Fog
module CDN
class HP < Fog::Service
requires :hp_secret_key, :hp_account_id, :hp_tenant_id
recognizes :hp_auth_uri, :hp_cdn_uri, :persistent, :connection_options, :hp_use_upass_auth_style, :hp_auth_version
model_path 'fog/hp/models/cdn'
request_path 'fog/hp/requests/cdn'
request :get_containers
request :head_container
request :post_container
request :put_container
request :delete_container
module Utils
end
class Mock
include Utils
def self.data
@data ||= Hash.new do |hash, key|
hash[key] = {
:cdn_containers => {}
}
end
end
def self.reset
@data = nil
end
def initialize(options={})
@hp_account_id = options[:hp_account_id]
end
def data
self.class.data[@hp_account_id]
end
def reset_data
self.class.data.delete(@hp_account_id)
end
end
class Real
include Utils
def initialize(options={})
require 'multi_json'
@connection_options = options[:connection_options] || {}
### Set an option to use the style of authentication desired; :v1 or :v2 (default)
auth_version = options[:hp_auth_version] || :v2
### Pass the service type for object storage to the authentication call
options[:hp_service_type] = "hpext:cdn"
### Make the authentication call
if (auth_version == :v2)
# Call the control services authentication
credentials = Fog::HP.authenticate_v2(options, @connection_options)
### When using the v2 CS authentication, the CDN Mgmt comes from the service catalog
@hp_cdn_uri = credentials[:endpoint_url]
cdn_mgmt_url = @hp_cdn_uri
else
# Call the legacy v1.0/v1.1 authentication
credentials = Fog::HP.authenticate_v1(options, @connection_options)
# In case of legacy authentication systems, the user can pass the CDN Mgmt Uri
@hp_cdn_uri = options[:hp_cdn_uri] || "https://region-a.geo-1.cdnmgmt.hpcloudsvc.com/v1.0"
# In case of legacy authentication systems, the :cdn_endpoint_url will carry the cdn storage url
cdn_mgmt_url = "#{@hp_cdn_uri}#{URI.parse(credentials[:cdn_endpoint_url]).path}"
end
@auth_token = credentials[:auth_token]
@enabled = false
@persistent = options[:persistent] || false
if cdn_mgmt_url
uri = URI.parse(cdn_mgmt_url)
@host = uri.host
@path = uri.path.chomp("/")
@port = uri.port
@scheme = uri.scheme
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
@enabled = true
end
end
def enabled?
@enabled
end
def reload
@cdn_connection.reset
end
def request(params, parse_json = true, &block)
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]}",
}), &block)
rescue Excon::Errors::HTTPStatusError => error
raise case error
when Excon::Errors::NotFound
Fog::CDN::HP::NotFound.slurp(error)
else
error
end
end
if !response.body.empty? && parse_json && response.headers['Content-Type'] =~ %r{application/json}
response.body = MultiJson.decode(response.body)
end
response
end
end
end
end
end

181
lib/fog/hp/compute.rb Normal file
View file

@ -0,0 +1,181 @@
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'hp'))
require 'fog/compute'
module Fog
module Compute
class HP < Fog::Service
requires :hp_secret_key, :hp_account_id, :hp_tenant_id
recognizes :hp_auth_uri, :hp_servicenet, :persistent, :connection_options, :hp_use_upass_auth_style, :hp_auth_version, :hp_avl_zone
model_path 'fog/hp/models/compute'
model :address
collection :addresses
model :flavor
collection :flavors
model :image
collection :images
model :key_pair
collection :key_pairs
model :security_group
collection :security_groups
model :server
collection :servers
request_path 'fog/hp/requests/compute'
request :allocate_address
request :associate_address
request :change_password_server
#request :confirm_resized_server
request :create_image
request :create_key_pair
request :create_security_group
request :create_security_group_rule
request :create_server
request :delete_image
request :delete_key_pair
request :delete_security_group
request :delete_security_group_rule
request :delete_server
request :disassociate_address
request :get_address
request :get_flavor_details
request :get_image_details
request :get_security_group
request :get_server_details
request :list_addresses
request :list_flavors
request :list_flavors_detail
request :list_images
request :list_images_detail
request :list_key_pairs
request :list_security_groups
request :list_server_addresses
request :list_server_private_addresses
request :list_server_public_addresses
request :list_servers
request :list_servers_detail
request :reboot_server
request :rebuild_server
request :release_address
#request :resize_server
#request :revert_resized_server
request :server_action
request :update_server
class Mock
def self.data
@data ||= Hash.new do |hash, key|
hash[key] = {
:last_modified => {
:images => {},
:key_pairs => {},
:security_groups => {},
:servers => {},
:addresses => {}
},
:images => {},
:key_pairs => {},
:security_groups => {},
:servers => {},
:addresses => {}
}
end
end
def self.reset
@data = nil
end
def initialize(options={})
@hp_account_id = options[:hp_account_id]
end
def data
self.class.data[@hp_account_id]
end
def reset_data
self.class.data.delete(@hp_account_id)
end
end
class Real
def initialize(options={})
require 'multi_json'
@hp_secret_key = options[:hp_secret_key]
@hp_account_id = options[:hp_account_id]
@hp_servicenet = options[:hp_servicenet]
@connection_options = options[:connection_options] || {}
### Set an option to use the style of authentication desired; :v1 or :v2 (default)
auth_version = options[:hp_auth_version] || :v2
### Pass the service type for compute via the options hash
options[:hp_service_type] = "compute"
@hp_tenant_id = options[:hp_tenant_id]
### Make the authentication call
if (auth_version == :v2)
# Call the control services authentication
credentials = Fog::HP.authenticate_v2(options, @connection_options)
# the CS service catalog returns the cdn endpoint
@hp_compute_uri = credentials[:endpoint_url]
else
# Call the legacy v1.0/v1.1 authentication
credentials = Fog::HP.authenticate_v1(options, @connection_options)
# the user sends in the cdn endpoint
@hp_compute_uri = options[:hp_auth_uri]
end
@auth_token = credentials[:auth_token]
uri = URI.parse(@hp_compute_uri)
@host = @hp_servicenet == true ? "snet-#{uri.host}" : uri.host
@path = uri.path
@persistent = options[:persistent] || false
@port = uri.port
@scheme = uri.scheme
Excon.ssl_verify_peer = false if options[:hp_servicenet] == true
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
end
def reload
@connection.reset
end
def request(params, parse_json = true, &block)
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)
}), &block)
rescue Excon::Errors::HTTPStatusError => error
raise case error
when Excon::Errors::NotFound
Fog::Compute::HP::NotFound.slurp(error)
else
error
end
end
unless response.body.empty?
begin
response.body = MultiJson.decode(response.body)
rescue MultiJson::DecodeError => error
response.body #### the body is not in JSON format so just return it as it is
end
end
response
end
end
end
end
end

View file

@ -0,0 +1,71 @@
require 'fog/core/model'
module Fog
module Compute
class HP
class Address < Fog::Model
identity :id
attribute :ip
attribute :fixed_ip
attribute :instance_id
def initialize(attributes = {})
# assign server first to prevent race condition with new_record?
self.server = attributes.delete(:server)
super
end
def destroy
requires :id
connection.release_address(id)
true
end
def server=(new_server)
if new_server
associate(new_server)
else
disassociate
end
end
def save
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if identity
data = connection.allocate_address.body['floating_ip']
new_attributes = data.reject {|key,value| !['id', 'instance_id', 'ip', 'fixed_ip'].include?(key)}
merge_attributes(new_attributes)
if @server
self.server = @server
end
true
end
private
def associate(new_server)
if new_record?
@server = new_server
else
@server = nil
self.instance_id = new_server.id
connection.associate_address(instance_id, ip)
end
end
def disassociate
@server = nil
unless new_record?
connection.disassociate_address(instance_id, ip)
end
self.instance_id = nil
end
end
end
end
end

View file

@ -0,0 +1,29 @@
require 'fog/core/collection'
require 'fog/hp/models/compute/address'
module Fog
module Compute
class HP
class Addresses < Fog::Collection
model Fog::Compute::HP::Address
def all
data = connection.list_addresses.body['floating_ips']
load(data)
end
def get(address_id)
if address = connection.get_address(address_id).body['floating_ip']
new(address)
end
rescue Fog::Compute::HP::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,24 @@
require 'fog/core/model'
module Fog
module Compute
class HP
class Flavor < Fog::Model
identity :id
attribute :disk
attribute :name
attribute :ram
attribute :cores, :aliases => 'vcpus'
#def bits
# 64
#end
end
end
end
end

View file

@ -0,0 +1,28 @@
require 'fog/core/collection'
require 'fog/hp/models/compute/flavor'
module Fog
module Compute
class HP
class Flavors < Fog::Collection
model Fog::Compute::HP::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::HP::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,37 @@
require 'fog/core/model'
module Fog
module Compute
class HP
class Image < Fog::Model
identity :id
attribute :name
attribute :created_at, :aliases => 'created'
attribute :updated_at, :aliases => 'updated'
attribute :progress
attribute :status
attribute :minDisk, :aliases => 'min_disk'
attribute :minRam, :aliases => 'min_ram'
attribute :server, :aliases => 'server'
#attribute :metadata #TODO: Need to add it back when Metadata API is done
attribute :links
def destroy
requires :id
connection.delete_image(id)
true
end
def ready?
status == 'ACTIVE'
end
end
end
end
end

View file

@ -0,0 +1,34 @@
require 'fog/core/collection'
require 'fog/hp/models/compute/image'
module Fog
module Compute
class HP
class Images < Fog::Collection
model Fog::Compute::HP::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
self
end
def get(image_id)
data = connection.get_image_details(image_id).body['image']
new(data)
rescue Fog::Compute::HP::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,59 @@
require 'fog/core/model'
module Fog
module Compute
class HP
class KeyPair < Fog::Model
identity :name
attribute :fingerprint
attribute :public_key
attribute :private_key
attribute :user_id
attr_accessor :public_key
def destroy
requires :name
connection.delete_key_pair(name)
true
end
def save
requires :name
data = if public_key
connection.create_key_pair(name, public_key).body['keypair']
else
connection.create_key_pair(name).body['keypair']
end
new_attributes = data.reject {|key,value| !['fingerprint', 'public_key', 'name', 'private_key', 'user_id'].include?(key)}
merge_attributes(new_attributes)
true
end
def write(path="#{ENV['HOME']}/.ssh/hp_#{Fog.credential.to_s}_#{name}.pem")
if writable?
split_private_key = private_key.split(/\n/)
File.open(path, "w") do |f|
split_private_key.each {|line| f.puts line}
f.chmod 0600
end
"Key file built: #{path}"
else
"Invalid private key"
end
end
def writable?
!!(private_key && ENV.has_key?('HOME'))
end
end
end
end
end

View file

@ -0,0 +1,31 @@
require 'fog/core/collection'
require 'fog/hp/models/compute/key_pair'
module Fog
module Compute
class HP
class KeyPairs < Fog::Collection
model Fog::Compute::HP::KeyPair
def all
items = []
connection.list_key_pairs.body['keypairs'].each do |kp|
items = items + kp.map { |key, value| value }
end
load(items)
end
def get(key_pair_name)
if key_pair_name
self.all.select {|kp| kp.name == key_pair_name}.first
end
rescue Fog::Compute::HP::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,50 @@
require 'fog/core/model'
module Fog
module Compute
class HP
class SecurityGroup < Fog::Model
identity :id
attribute :name
attribute :description
attribute :rules
attribute :tenant_id
def destroy
requires :id
connection.delete_security_group(id)
true
end
def save
requires :name, :description
data = connection.create_security_group(name, description)
merge_attributes(data.body['security_group'])
true
end
def create_rule(range, ip_protocol = "tcp", cidr = "0.0.0.0/0", group_id=nil)
requires :id
connection.create_security_group_rule(id, ip_protocol, range.min, range.max, cidr, group_id)
end
def delete_rule(rule_id)
connection.delete_security_group_rule(rule_id)
true
end
def delete_all_rules()
self.rules.each do |rule|
delete_rule(rule['id'])
end
true
end
end
end
end
end

View file

@ -0,0 +1,29 @@
require 'fog/core/collection'
require 'fog/hp/models/compute/security_group'
module Fog
module Compute
class HP
class SecurityGroups < Fog::Collection
model Fog::Compute::HP::SecurityGroup
def all
items = connection.list_security_groups.body['security_groups']
load(items)
end
def get(security_group_id)
if security_group_id
sec_group = connection.get_security_group(security_group_id).body['security_group']
new(sec_group)
end
rescue Fog::Compute::HP::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,225 @@
require 'fog/compute/models/server'
module Fog
module Compute
class HP
class Server < Fog::Compute::Server
identity :id
attribute :addresses
attribute :flavor
attribute :host_id, :aliases => 'hostId'
attribute :image
attribute :metadata
attribute :name
attribute :personality
attribute :progress
attribute :accessIPv4
attribute :accessIPv6
attribute :state, :aliases => 'status'
attribute :created_at, :aliases => 'created'
attribute :updated_at, :aliases => 'updated'
attribute :tenant_id
attribute :user_id
attribute :key_name
# these are implemented as methods
attribute :image_id
attribute :flavor_id
attribute :private_ip_address
attribute :public_ip_address
attr_reader :password
attr_writer :private_key, :private_key_path, :public_key, :public_key_path, :username, :image_id, :flavor_id
def initialize(attributes = {})
# assign these attributes first to prevent race condition with new_record?
self.security_groups = attributes.delete(:security_groups)
self.min_count = attributes.delete(:min_count)
self.max_count = attributes.delete(:max_count)
super
end
def destroy
requires :id
connection.delete_server(id)
true
end
def images
requires :id
connection.images(:server => self)
end
def key_pair
requires :key_name
connection.key_pairs.get(key_name)
end
def key_pair=(new_keypair)
self.key_name = new_keypair && new_keypair.name
end
def private_ip_address
addr = addresses.nil? ? nil : addresses.fetch('private', []).first
addr["addr"] if addr
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
# FIX: Both the private and public ips are bundled under "private" network name
# So hack to get to the public ip address
if !addresses.nil?
addr = addresses.fetch('private', [])
# if we have more than 1 address, then the return the second address which is public
if addr.count > 1
addr[1]["addr"]
else
nil
end
else
nil
end
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_id
@image_id ||= (image.nil? ? nil : image["id"])
end
def image_id=(new_image_id)
@image_id = new_image_id
end
def flavor_id
@flavor_id ||= (flavor.nil? ? nil : flavor["id"])
end
def flavor_id=(new_flavor_id)
@flavor_id = new_flavor_id
end
def min_count=(new_min_count)
@min_count = new_min_count
end
def max_count=(new_max_count)
@max_count = new_max_count
end
def security_groups=(new_security_groups)
@security_groups = new_security_groups
end
def ready?
self.state == 'ACTIVE'
end
def change_password(admin_password)
requires :id
connection.change_password_server(id, admin_password)
true
end
def reboot(type = 'SOFT')
requires :id
connection.reboot_server(id, type)
true
end
def rebuild(image_id, name, admin_pass=nil, metadata=nil, personality=nil)
requires :id
connection.rebuild_server(id, image_id, name, admin_pass, metadata, personality)
true
end
def resize(flavor_id)
requires :id
connection.resize_server(id, flavor_id)
true
end
def revert_resize
requires :id
connection.revert_resized_server(id)
true
end
def confirm_resize
requires :id
connection.confirm_resized_server(id)
true
end
def create_image(name, metadata={})
requires :id
connection.create_image(id, name, metadata)
end
def save
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if identity
requires :flavor_id, :image_id, :name
options = {
'metadata' => metadata,
'personality' => personality,
'accessIPv4' => accessIPv4,
'accessIPv6' => accessIPv6,
'min_count' => @min_count,
'max_count' => @max_count,
'key_name' => key_name,
'security_groups' => @security_groups
}
options = options.reject {|key, value| value.nil?}
data = connection.create_server(name, flavor_id, image_id, 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

View file

@ -0,0 +1,36 @@
require 'fog/core/collection'
require 'fog/hp/models/compute/server'
module Fog
module Compute
class HP
class Servers < Fog::Collection
model Fog::Compute::HP::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::HP::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,50 @@
require 'fog/core/collection'
require 'fog/hp/models/storage/directory'
module Fog
module Storage
class HP
class Directories < Fog::Collection
model Fog::Storage::HP::Directory
def all
data = connection.get_containers.body
load(data)
end
def get(key, options = {})
read_header = nil
write_header = nil
data = connection.get_container(key, options)
directory = new(:key => key)
for key, value in data.headers
if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key)
directory.merge_attributes(key => value)
end
if key == 'X-Container-Read'
read_header = value
elsif key == 'X-Container-Write'
write_header = value
end
end
# set the acl on the directory based on the headers
if !(read_header.nil? && write_header.nil?)
directory.acl = connection.header_to_acl(read_header, write_header)
end
directory.files.merge_attributes(options)
directory.files.instance_variable_set(:@loaded, true)
data.body.each do |file|
directory.files << directory.files.new(file)
end
directory
rescue Fog::Storage::HP::NotFound
nil
end
end
end
end
end

View file

@ -0,0 +1,160 @@
require 'fog/core/model'
require 'fog/hp/models/storage/files'
module Fog
module Storage
class HP
class Directory < Fog::Model
identity :key, :aliases => 'name'
attribute :bytes, :aliases => 'X-Container-Bytes-Used'
attribute :count, :aliases => 'X-Container-Object-Count'
def acl=(new_acl)
if new_acl.nil?
new_acl = "private"
end
valid_acls = ['private', 'public-read', 'public-write', 'public-read-write']
unless valid_acls.include?(new_acl)
raise ArgumentError.new("acl must be one of [#{valid_acls.join(', ')}]")
end
@acl = new_acl
end
def destroy
requires :key
connection.delete_container(key)
# If CDN service is available, try to delete the container if it was CDN-enabled
if cdn_enabled?
begin
connection.cdn.delete_container(key)
rescue Fog::CDN::HP::NotFound
# ignore if cdn container not found
end
end
true
rescue Excon::Errors::NotFound, Fog::Storage::HP::NotFound
false
end
def files
@files ||= begin
Fog::Storage::HP::Files.new(
:directory => self,
:connection => connection
)
end
end
def public=(new_public)
if new_public
@acl = 'public-read'
else
@acl = 'private'
end
@public = new_public
end
def public?
if @acl.nil?
false
else
@acl == 'public-read'
end
end
def public_url
requires :key
@public_url ||= begin
begin response = connection.head_container(key)
# escape the key to cover for special char. in container names
url = "#{connection.url}/#{Fog::HP.escape(key)}"
rescue Fog::Storage::HP::NotFound => err
nil
end
end
end
def cdn_enable=(new_cdn_enable)
@cdn_enable ||= false
if (!connection.cdn.nil? && connection.cdn.enabled?)
@cdn_enable = new_cdn_enable
else
# since cdn service is not activated, container cannot be cdn-enabled
@cdn_enable = false
end
end
def cdn_enabled?
if (!connection.cdn.nil? && connection.cdn.enabled?)
begin response = connection.cdn.head_container(key)
cdn_header = response.headers.fetch('X-Cdn-Enabled', nil)
if (!cdn_header.nil? && cdn_header == 'True')
@cdn_enable = true
else
@cdn_enable = false
end
rescue Fog::CDN::HP::NotFound => err
@cdn_enable = false
end
else
@cdn_enable = false
end
end
def cdn_public_url
requires :key
@cdn_public_url ||= begin
# return the CDN public url from the appropriate uri from the header
begin response = connection.cdn.head_container(key)
if response.headers['X-Cdn-Enabled'] == 'True'
if connection.hp_cdn_ssl == true
response.headers.fetch('X-Cdn-Ssl-Uri', nil)
else
response.headers.fetch('X-Cdn-Uri', nil)
end
end
rescue Fog::CDN::HP::NotFound => err
nil
end
end
end
def save
requires :key
options = {}
if @acl
options.merge!(connection.acl_to_header(@acl))
end
connection.put_container(key, options)
# Added an extra check to see if CDN is enabled for the container
if (!connection.cdn.nil? && connection.cdn.enabled?)
# If CDN available, set the container to be CDN-enabled or not based on if it is marked as cdn_enable.
if @cdn_enable
# check to make sure that the container exists. If yes, cdn enable it.
begin response = connection.cdn.head_container(key)
### Deleting a container from CDN is much more expensive than flipping the bit to disable it
connection.cdn.post_container(key, {'X-CDN-Enabled' => 'True'})
rescue Fog::CDN::HP::NotFound => err
connection.cdn.put_container(key)
end
else
# check to make sure that the container exists. If yes, cdn disable it.
begin response = connection.cdn.head_container(key)
### Deleting a container from CDN is much more expensive than flipping the bit to disable it
connection.cdn.post_container(key, {'X-CDN-Enabled' => 'False'})
rescue Fog::CDN::HP::NotFound => err
# just continue, as container is not cdn-enabled.
end
end
end
true
end
end
end
end
end

View file

@ -0,0 +1,87 @@
require 'fog/core/model'
module Fog
module Storage
class HP
class File < Fog::Model
identity :key, :aliases => 'name'
attribute :content_length, :aliases => ['bytes', 'Content-Length'], :type => :integer
attribute :content_type, :aliases => ['content_type', 'Content-Type']
attribute :etag, :aliases => ['hash', 'Etag']
attribute :last_modified, :aliases => ['last_modified', 'Last-Modified'], :type => :time
def body
attributes[:body] ||= if last_modified
collection.get(identity).body
else
''
end
end
def body=(new_body)
attributes[:body] = new_body
end
def directory
@directory
end
def copy(target_directory_key, target_file_key)
requires :directory, :key
target_directory = connection.directories.new(:key => target_directory_key)
connection.put_object(target_directory_key, target_file_key, nil, {'X-Copy-From' => "/#{directory.key}/#{key}" })
target_directory.files.get(target_file_key)
end
def destroy
requires :directory, :key
connection.delete_object(directory.key, key)
true
end
def owner=(new_owner)
if new_owner
attributes[:owner] = {
:display_name => new_owner['DisplayName'],
:id => new_owner['ID']
}
end
end
#def public=(new_public)
# new_public
#end
def public_url
requires :key
self.collection.get_url(self.key)
end
def cdn_public_url
requires :key
self.collection.get_cdn_url(self.key)
end
def save(options = {})
requires :body, :directory, :key
options['Content-Type'] = content_type if content_type
data = connection.put_object(directory.key, key, body, options)
merge_attributes(data.headers)
self.content_length = Fog::Storage.get_body_size(body)
true
end
private
def directory=(new_directory)
@directory = new_directory
end
end
end
end
end

View file

@ -0,0 +1,103 @@
require 'fog/core/collection'
require 'fog/hp/models/storage/file'
module Fog
module Storage
class HP
class Files < Fog::Collection
attribute :directory
attribute :limit
attribute :marker
attribute :path
attribute :prefix
model Fog::Storage::HP::File
def all(options = {})
requires :directory
options = {
'limit' => limit,
'marker' => marker,
'path' => path,
'prefix' => prefix
}.merge!(options)
merge_attributes(options)
parent = directory.collection.get(
directory.key,
options
)
if parent
load(parent.files.map {|file| file.attributes})
else
nil
end
end
alias :each_file_this_page :each
def each
if !block_given?
self
else
subset = dup.all
subset.each_file_this_page {|f| yield f}
until subset.empty? || subset.length == (subset.limit || 10000)
subset = subset.all(:marker => subset.last.key)
subset.each_file_this_page {|f| yield f}
end
self
end
end
def get(key, &block)
requires :directory
data = connection.get_object(directory.key, key, &block)
file_data = data.headers.merge({
:body => data.body,
:key => key
})
new(file_data)
rescue Fog::Storage::HP::NotFound
nil
end
def get_url(key)
requires :directory
if self.directory.public_url
# escape the key to cover for special char. in object names
"#{self.directory.public_url}/#{Fog::HP.escape(key)}"
end
end
def get_cdn_url(key)
requires :directory
if self.directory.cdn_public_url
# escape the key to cover for special char. in object names
"#{self.directory.cdn_public_url}/#{Fog::HP.escape(key)}"
end
end
def head(key, options = {})
requires :directory
data = connection.head_object(directory.key, key)
file_data = data.headers.merge({
:key => key
})
new(file_data)
rescue Fog::Storage::HP::NotFound
nil
end
def new(attributes = {})
requires :directory
super({ :directory => directory }.merge!(attributes))
end
end
end
end
end

View file

@ -0,0 +1,38 @@
module Fog
module CDN
class HP
class Real
# Delete an existing container
#
# ==== Parameters
# * name<~String> - Name of container to delete
#
def delete_container(name)
response = request(
:expects => 204,
:method => 'DELETE',
:path => Fog::HP.escape(name)
)
response
end
end
class Mock # :nodoc:all
def delete_container(name)
response = Excon::Response.new
if self.data[:cdn_containers][name]
self.data[:cdn_containers].delete(name)
response.status = 204
response.body = ""
response
else
raise Fog::CDN::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,44 @@
module Fog
module CDN
class HP
class Real
# List existing cdn-enabled storage containers
#
# ==== Parameters
# * options<~Hash>:
# * 'enabled_only'<~Boolean> - Set to true to limit results to cdn enabled containers
# * 'limit'<~Integer> - Upper limit to number of results returned
# * 'marker'<~String> - Only return objects with name greater than this value
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Array>:
# * container<~String>: Name of container
def get_containers(options = {})
response = request(
:expects => [200, 204],
:method => 'GET',
:path => '',
:query => {'format' => 'json'}.merge!(options)
)
response
end
end
class Mock # :nodoc:all
def get_containers(options = {})
response = Excon::Response.new
data = self.data[:cdn_containers].map {|_,v| v}
response.body = data
response.status = 200
response
end
end
end
end
end

View file

@ -0,0 +1,50 @@
module Fog
module CDN
class HP
class Real
# List cdn properties for a container
#
# ==== Parameters
# * name<~String> - Name of container to retrieve info for
#
# ==== Returns
# * response<~Excon::Response>:
# * headers<~Hash>:
# * 'X-Cdn-Enabled'<~Boolean> - cdn status for container
# * 'X-Cdn-Uri'<~String> - cdn url for this container
# * 'X-Ttl'<~String> - integer seconds before data expires, defaults to 86400 (1 day)
# * 'X-Log-Retention'<~Boolean> - ?
def head_container(name)
response = request(
:expects => 204,
:method => 'HEAD',
:path => Fog::HP.escape(name),
:query => {'format' => 'json'}
)
response
end
end
class Mock # :nodoc:all
def head_container(name)
response = Excon::Response.new
headers = {}
if data = self.data[:cdn_containers][name]
data.each do |k,_|
headers[k] = data[k] if data[k]
end
response.headers = headers
response.status = 204
response.body = ""
response
else
raise Fog::CDN::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,52 @@
module Fog
module CDN
class HP
class Real
# modify CDN properties for a container
#
# ==== Parameters
# * name<~String> - Name for container, should be < 256 bytes and must not contain '/'
# # options<~Hash>:
# * 'X-CDN-Enabled'<~Boolean> - cdn status for container
# * 'X-CDN-URI'<~String> - cdn url for this container
# * 'X-TTL'<~String> - integer seconds before data expires, defaults to 86400 (1 day), in 900 (15 min.) to 1577836800 (50 years)
# * 'X-Log-Retention'<~Boolean> - ?
def post_container(name, options = {})
response = request(
:expects => [201, 202],
:headers => options,
:method => 'POST',
:path => Fog::HP.escape(name)
)
response
end
end
class Mock # :nodoc:all
def post_container(name, options = {})
response = Excon::Response.new
container_id = Fog::Mock.random_hex(33)
if data = self.data[:cdn_containers][name]
options.each do |k,v|
data[k] = options[k] if options[k]
end
response.headers = {
"X-Cdn-Ssl-Uri" => "https://a111.cdn.net/cdn-test.net/#{container_id}/abc",
"X-Cdn-Uri" => "http://#{container_id}.cdn-test.net",
"X-Trans-Id" => Fog::Mock.random_hex(34)
}
response.status = 202
response.body = "202 Accepted\n\nThe request is accepted for processing.\n\n "
self.data[:cdn_containers][name] = data
response
else
raise Fog::CDN::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,53 @@
module Fog
module CDN
class HP
class Real
# enable CDN for a container
#
# ==== Parameters
# * name<~String> - Name for container, should be < 256 bytes and must not contain '/'
# # options<~Hash>:
# * 'X-CDN-Enabled'<~Boolean> - cdn status for container
# * 'X-CDN-URI'<~String> - cdn url for this container
# * 'X-TTL'<~String> - integer seconds before data expires, defaults to 86400 (1 day), in 900 (15 min.) to 1577836800 (50 years)
# * 'X-Log-Retention'<~Boolean> - ?
def put_container(name, options = {})
response = request(
:expects => [201, 202],
:headers => options,
:method => 'PUT',
:path => Fog::HP.escape(name)
)
response
end
end
class Mock # :nodoc:all
def put_container(name, options = {})
response = Excon::Response.new
container_id = Fog::Mock.random_hex(33)
data = {
'x-cdn-ssl-uri' => "https://a111.cdn.net/cdn-test.net/#{container_id}/abc",
'cdn_enabled' => true,
'name' => name,
'x-cdn-uri' => "http://#{container_id}.cdn-test.net",
'ttl' => 86400,
'log_retention' => false
}
response.headers = {
"X-Cdn-Ssl-Uri" => "https://a111.cdn.net/cdn-test.net/#{container_id}/abc",
"X-Cdn-Uri" => "http://#{container_id}.cdn-test.net",
"X-Trans-Id" => Fog::Mock.random_hex(34)
}
response.status = 201
response.body = "201 Created\n\n\n\n "
self.data[:cdn_containers][name] = data
response
end
end
end
end
end

View file

@ -0,0 +1,49 @@
module Fog
module Compute
class HP
class Real
# Acquires a floating IP address
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'floating_ip'<~Hash> -
# * 'id'<~Integer> - Id of the address
# * 'ip'<~String> - Floating IP of the address
# * 'instance_id'<~String> - Id of the associated server instance
# * 'fixed_ip'<~String> - Fixed IP of the address
def allocate_address
request(
:body => nil,
:expects => 200,
:method => 'POST',
:path => 'os-floating-ips.json'
)
end
end
class Mock
def allocate_address
response = Excon::Response.new
response.status = 200
data = {
'instance_id' => Fog::HP::Mock.instance_id.to_i,
'ip' => Fog::HP::Mock.ip_address,
'fixed_ip' => Fog::HP::Mock.ip_address,
'id' => Fog::Mock.random_numbers(3).to_i
}
self.data[:last_modified][:addresses][data['id']] = Time.now
self.data[:addresses][data['id']] = data
response.body = { 'floating_ip' => data }
response
end
end
end
end
end

View file

@ -0,0 +1,42 @@
module Fog
module Compute
class HP
class Real
# Associate a floating IP address with existing server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to associate IP with
# * ip_address<~String> - IP address to associate with the server
#
def associate_address(server_id, ip_address)
body = { 'addFloatingIp' => { 'server' => server_id, 'address' => ip_address }}
server_action(server_id, body)
end
end
class Mock
def associate_address(server_id, ip_address)
response = Excon::Response.new
if server = self.data[:servers][server_id]
data = {"version"=>4, "addr"=>"#{ip_address}"}
if server['addresses']['private']
server['addresses']['private'] << data
else
server['addresses']['private'] = data
end
response.status = 202
else
#raise Fog::Compute::HP::NotFound
response.status = 500
raise(Excon::Errors.status_error({:expects => 200}, response))
end
response
end
end
end
end
end

View file

@ -0,0 +1,33 @@
module Fog
module Compute
class HP
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
if list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
if admin_password
response.body = { 'changePassword' => { 'adminPass' => admin_password }}
end
response.status = 202
else
#raise Fog::Compute::HP::NotFound
response.status = 500
raise(Excon::Errors.status_error({:expects => 200}, response))
end
response
end
end
end
end
end

View file

@ -0,0 +1,34 @@
module Fog
module Compute
class HP
class Real
# Confirm resizing
#
# ==== Parameters
# * server_id<~Integer> - Id of server to confirm
#
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
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

View file

@ -0,0 +1,63 @@
module Fog
module Compute
class HP
class Real
# Create an image from an existing server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to create image from
# * name<~String> - Name of the image
# * metadata<~Hash> - A hash of metadata options
# * 'ImageType'<~String> - type of the image i.e. Gold
# * 'ImageVersion'<~String> - version of the image i.e. 2.0
#
# ==== Returns
# Does not return a response body.
def create_image(server_id, name, metadata = {})
body = { 'createImage' =>
{ 'name' => name,
'metadata' =>
{ 'ImageType' => metadata[:image_type],
'ImageVersion' => metadata[:image_version]
}
}
}
server_action(server_id, body)
end
end
class Mock
def create_image(server_id, name, metadata = {})
response = Excon::Response.new
response.status = 202
image_id = Fog::Mock.random_numbers(6).to_s
data = {
'id' => image_id,
'server' => {"id"=>"3", "links"=>[{"href"=>"http://nova1:8774/v1.1/servers/#{server_id}", "rel"=>"bookmark"}]},
'links' => [{"href"=>"http://nova1:8774/v1.1/tenantid/images/#{image_id}", "rel"=>"self"}, {"href"=>"http://nova1:8774/tenantid/images/#{image_id}", "rel"=>"bookmark"}],
'metadata' => metadata || {},
'name' => name || "image_#{rand(999)}",
'progress' => 0,
'status' => 'SAVING',
'updated' => "",
'created' => ""
}
self.data[:last_modified][:images][data['id']] = Time.now
self.data[:images][data['id']] = data
response.headers = {'Content-Length' => '0', 'Content-Type' => 'text/html; charset=UTF-8', 'Date' => Time.now, 'Location' => "http://nova1:8774/v1.1/images/#{@image_id}"}
response.body = "" # { 'image' => data } no data is sent
response
end
end
end
end
end

View file

@ -0,0 +1,81 @@
module Fog
module Compute
class HP
class Real
# Create a new keypair
#
# ==== Parameters
# * key_name<~String> - Name of the keypair
# * public_key<~String> - The public key for the keypair
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'keypair'<~Hash> - The keypair data
# * 'public_key'<~String> - The public key for the keypair
# * 'private_key'<~String> - The private key for the keypair
# * 'user_id'<~String> - The user id
# * 'fingerprint'<~String> - SHA-1 digest of DER encoded private key
# * 'name'<~String> - Name of key
#
# {Openstack API Reference}[http://docs.openstack.org]
def create_key_pair(key_name, public_key = nil)
if public_key.nil?
data = {
'keypair' => {
'name' => key_name
}
}
else
data = {
'keypair' => {
'name' => key_name,
'public_key' => public_key
}
}
end
request(
:body => MultiJson.encode(data),
:expects => 200,
:method => 'POST',
:path => 'os-keypairs.json'
)
end
end
class Mock
def create_key_pair(key_name, public_key = nil)
response = Excon::Response.new
unless self.data[:key_pairs][key_name]
response.status = 200
private_key, new_public_key = Fog::HP::Mock.key_material
new_public_key = public_key if public_key # if public key was passed in
data = {
'public_key' => new_public_key,
'fingerprint' => Fog::HP::Mock.key_fingerprint,
'name' => key_name
}
self.data[:last_modified][:key_pairs][key_name] = Time.now
self.data[:key_pairs][key_name] = { 'keypair' => data }
if public_key
response.body = { 'keypair' => data.merge({'user_id' => Fog::HP::Mock.user_id,}) }
else
response.body = { 'keypair' => data.merge({'private_key' => private_key, 'user_id' => Fog::HP::Mock.user_id,}) }
end
else
#raise Fog::Compute::HP::NotFound
response.status = 400
raise(Excon::Errors.status_error({:expects => 200}, response))
end
response
end
end
end
end
end

View file

@ -0,0 +1,83 @@
module Fog
module Compute
class HP
class Real
# Create a new security group
#
# ==== Parameters
# * 'name'<~String> - name of the security group
# * 'description'<~String> - description of the security group
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'security_group'<~Array>:
# * 'rules'<~Array>: - array of security group rules
# * 'id'<~Integer> - id of the security group rule
# * 'from_port'<~Integer> - start port for rule i.e. 22 (or -1 for ICMP wildcard)
# * 'to_port'<~Integer> - end port for rule i.e. 22 (or -1 for ICMP wildcard)
# * 'ip_protocol'<~String> - ip protocol for rule, must be in ['tcp', 'udp', 'icmp']
# * 'group'<~Hash>:
# * Undefined
# * 'parent_group_id'<~Integer> - parent group id
# * 'ip_range'<~Hash>:
# * 'cidr'<~String> - ip range address i.e. '0.0.0.0/0'
# * 'id'<~Integer> - id of the security group
# * 'name'<~String> - name of the security group
# * 'description'<~String> - description of the security group
# * 'tenant_id'<~String> - tenant id of the user
#
# {Openstack API Reference}[http://docs.openstack.org]
def create_security_group(name, description)
data = {
'security_group' => {
'name' => name,
'description' => description
}
}
request(
:body => MultiJson.encode(data),
:expects => 200,
:method => 'POST',
:path => 'os-security-groups.json'
)
end
end
class Mock
def create_security_group(name, description)
# all spaces are removed
name = name.strip
description = description.strip
response = Excon::Response.new
if self.data[:security_groups].detect {|_,v| v['name'] == name}
response.status = 400
response.body = { "badRequest" => {"message" => "Security group #{name} already exists", "code" => 400}}
raise(Excon::Errors.status_error({:expects => 200}, response))
else
response.status = 200
data = {
'rules' => [],
'id' => Fog::Mock.random_numbers(3).to_i,
'tenant_id' => Fog::HP::Mock.user_id.to_s,
'name' => name,
'description' => description
}
self.data[:last_modified][:security_groups][data['id']] = Time.now
self.data[:security_groups][data['id']] = data
response.body = { 'security_group' => data }
end
response
end
end
end
end
end

View file

@ -0,0 +1,75 @@
module Fog
module Compute
class HP
class Real
# Create a new security group rule and attach it to a security group
#
# ==== Parameters
# * 'parent_group_id'<~Integer> - id of the parent security group
# * 'ip_protocol'<~String> - ip protocol for rule, must be in ['tcp', 'udp', 'icmp']
# * 'from_port'<~Integer> - start port for rule i.e. 22 (or -1 for ICMP wildcard)
# * 'to_port'<~Integer> - end port for rule i.e. 22 (or -1 for ICMP wildcard)
# * 'cidr'<~String> - ip range address i.e. '0.0.0.0/0'
# * 'group_id'<~Integer> - id of the security group to which this rule applies
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
#
# {Openstack API Reference}[http://docs.openstack.org]
def create_security_group_rule(parent_group_id, ip_protocol, from_port, to_port, cidr, group_id=nil)
data = {
'security_group_rule' => {
'parent_group_id' => parent_group_id,
'ip_protocol' => ip_protocol,
'from_port' => from_port,
'to_port' => to_port,
'cidr' => cidr,
'group_id' => group_id
}
}
request(
:body => MultiJson.encode(data),
:expects => 200,
:method => 'POST',
:path => 'os-security-group-rules.json'
)
end
end
class Mock
def create_security_group_rule(parent_group_id, ip_protocol, from_port, to_port, cidr, group_id=nil)
response = Excon::Response.new
group = self.data[:security_groups][parent_group_id]
if group
group['rules'] ||= []
response.status = 200
data = {
'from_port' => from_port.to_i,
'group' => {},
'ip_protocol' => ip_protocol,
'to_port' => to_port.to_i,
'parent_group_id' => parent_group_id,
'ip_range' => {
'cidr' => cidr
},
'id' => Fog::Mock.random_numbers(3).to_i
}
group['rules'][data['id']] = data
response.body = { 'security_group_rule' => data }
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,140 @@
module Fog
module Compute
class HP
class Real
# Create a new server
#
# ==== Parameters
# * name<~String> - Name of server
# * flavor_id<~Integer> - Id of flavor for server
# * image_id<~Integer> - Id of image for server
# * options<~Hash>:
# * 'metadata'<~Hash> - Up to 5 key value pairs containing 255 bytes of info
# * 'min_count'<~Integer> - Number of servers to create. Defaults to 1.
# * 'max_count'<~Integer> - Max. number of servers to create. Defaults to being equal to min_count.
# * 'key_name'<~String> - Name of keypair to be used
# * 'security_groups'<~Array> - one or more security groups to be used
# * 'availability_zone'<~String> - the availability zone to be used
# * 'personality'<~Array>: Up to 5 files to customize server
# * file<~Hash>:
# * 'contents'<~String> - Contents of file (10kb total of contents)
# * 'path'<~String> - Path to file (255 bytes total of path strings)
# * 'accessIPv4'<~String> - IPv4 IP address
# * 'accessIPv6'<~String> - IPv6 IP address
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'server'<~Hash>:
# * 'addresses'<~Hash>:
# * 'public'<~Array> - public address strings
# * 'private'<~Array> - private address strings
# * 'adminPass'<~String> - Admin password for server
# * 'flavorId'<~Integer> - Id of servers current flavor
# * 'hostId'<~String>
# * 'id'<~Integer> - Id of server
# * 'imageId'<~Integer> - Id of image used to boot server
# * 'metadata'<~Hash> - metadata
# * 'name'<~String> - Name of server
# * 'progress'<~Integer> - Progress through current status
# * 'status'<~String> - Current server status
def create_server(name, flavor_id, image_id, options = {})
data = {
'server' => {
'flavorRef' => flavor_id,
'imageRef' => image_id,
'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
min_count = options['min_count'] || 1
max_count = options['max_count'] || min_count
data['server']['min_count'] = min_count
data['server']['max_count'] = max_count
if options['key_name']
data['server']['key_name'] = options['key_name']
end
if options['security_groups']
data['server']['security_groups'] = []
for sg in options['security_groups']
data['server']['security_groups'] << {
'name' => sg
}
end
end
if options['availability_zone']
data['server']['availability_zone'] = options['availability_zone']
end
request(
:body => MultiJson.encode(data),
:expects => 202,
:method => 'POST',
:path => 'servers.json'
)
end
end
class Mock
def create_server(name, flavor_id, image_id, options = {})
response = Excon::Response.new
response.status = 202
#if options['security_groups']
# sec_group_name = options['security_groups'][0]
#else
# sec_group_name = "default"
#end
data = {
'addresses' => { "private"=>[{"version"=>4, "addr"=>Fog::HP::Mock.ip_address}] },
'flavor' => {"id"=>"#{flavor_id}", "links"=>[{"href"=>"http://nova1:8774/admin/flavors/#{flavor_id}", "rel"=>"bookmark"}]},
'id' => Fog::Mock.random_numbers(6).to_i,
'image' => {"id"=>"#{image_id}", "links"=>[{"href"=>"http://nova1:8774/admin/images/#{image_id}", "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' => name || "server_#{rand(999)}",
'accessIPv4' => options['accessIPv4'] || "",
'accessIPv6' => options['accessIPv6'] || "",
'progress' => 0,
'status' => 'BUILD',
'created' => "2012-01-01T13:32:20Z",
'updated' => "2012-01-01T13:32:20Z",
'user_id' => Fog::HP::Mock.user_id.to_s,
'tenant_id' => Fog::HP::Mock.user_id.to_s,
'uuid' => "95253a45-9ead-43c6-90b3-65da2ef048b3",
'config_drive' => "",
#'security_groups' => [{"name"=>"#{sec_group_name}", "links"=>[{"href"=>"http://nova1:8774/v1.1/admin//os-security-groups/111", "rel"=>"bookmark"}], "id"=>111}],
'key_name' => options['key_name'] || ""
}
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

View file

@ -0,0 +1,45 @@
module Fog
module Compute
class HP
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
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 = 500
raise(Excon::Errors.status_error({:expects => 202}, response))
end
end
end
end
end
end

View file

@ -0,0 +1,39 @@
module Fog
module Compute
class HP
class Real
# Delete a keypair
#
# ==== Parameters
# * key_name<~String> - Name of the keypair to delete
#
def delete_key_pair(key_name)
request(
:expects => 202,
:method => 'DELETE',
:path => "os-keypairs/#{key_name}"
)
end
end
class Mock
def delete_key_pair(key_name)
response = Excon::Response.new
if self.data[:key_pairs][key_name]
self.data[:last_modified][:key_pairs].delete(key_name)
self.data[:key_pairs].delete(key_name)
response.status = 202
response.body = "202 Accepted\n\nThe request is accepted for processing.\n\n "
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,41 @@
module Fog
module Compute
class HP
class Real
# Delete a security group
#
# ==== Parameters
# * id<~Integer> - Id of the security group to delete
#
#
# {Openstack API Reference}[http://docs.openstack.org]
def delete_security_group(security_group_id)
request(
:expects => 202,
:method => 'DELETE',
:path => "os-security-groups/#{security_group_id}"
)
end
end
class Mock
def delete_security_group(security_group_id)
response = Excon::Response.new
if self.data[:security_groups][security_group_id]
self.data[:last_modified][:security_groups].delete(security_group_id)
self.data[:security_groups].delete(security_group_id)
response.status = 202
response.body = "202 Accepted\n\nThe request is accepted for processing.\n\n "
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,49 @@
module Fog
module Compute
class HP
class Real
# Delete a security group rule
#
# ==== Parameters
# * id<~Integer> - id of the security group rule to delete
#
# {Openstack API Reference}[http://docs.openstack.org]
def delete_security_group_rule(security_group_rule_id)
request(
:expects => 202,
:method => 'DELETE',
:path => "os-security-group-rules/#{security_group_rule_id}"
)
end
end
class Mock
def delete_security_group_rule(security_group_rule_id)
response = Excon::Response.new
sg_rule = nil
self.data[:security_groups].each do |_, sgv|
if sgv['rules']
sg_rule = sgv['rules'].delete_if { |r| !r.nil? && r['id'] == security_group_rule_id }
break if sg_rule
end
end
if sg_rule && !sg_rule.empty?
response.status = 202
response.body = "202 Accepted\n\nThe request is accepted for processing.\n\n "
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,43 @@
module Fog
module Compute
class HP
class Real
# Delete an existing server
#
# ==== Parameters
# * id<~Integer> - Id of server to delete
#
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 => 202}, 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::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,39 @@
module Fog
module Compute
class HP
class Real
# Disassociate a floating IP address with existing server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to associate IP with
# * ip_address<~String> - IP address to associate with the server
#
def disassociate_address(server_id, ip_address)
body = { 'removeFloatingIp' => { 'server' => server_id, 'address' => ip_address }}
server_action(server_id, body)
end
end
class Mock
def disassociate_address(server_id, ip_address)
response = Excon::Response.new
if server = self.data[:servers][server_id]
data = server['addresses']['private'].reject {|a| a['addr'] == ip_address}
self.data[:servers][server_id]['addresses']['private'] = data
response.status = 202
else
#raise Fog::Compute::HP::NotFound
response.status = 500
raise(Excon::Errors.status_error({:expects => 200}, response))
end
response
end
end
end
end
end

View file

@ -0,0 +1,45 @@
module Fog
module Compute
class HP
class Real
# Get details about an existing floating IP address
#
# ==== Parameters
# * 'address_id'<~Integer> - Id of floating IP address get details for
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'floating_ip'<~Hash> -
# * 'id'<~Integer> - Id of the address
# * 'ip'<~String> - Floating IP of the address
# * 'instance_id'<~String> - Id of the associated server instance
# * 'fixed_ip'<~String> - Fixed IP of the address
def get_address(address_id)
request(
:expects => [200],
:method => 'GET',
:path => "os-floating-ips/#{address_id}"
)
end
end
class Mock
def get_address(address_id)
response = Excon::Response.new
if address = self.data[:addresses][address_id]
response.status = 200
response.body = { 'floating_ip' => address }
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,51 @@
module Fog
module Compute
class HP
class Real
# Get details for flavor by id
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'id'<~Integer> - Id of the flavor
# * 'name'<~String> - Name of the flavor
# * 'ram'<~Integer> - Amount of ram for the flavor
# * 'disk'<~Integer> - Amount of diskspace for the flavor
def get_flavor_details(flavor_id)
request(
:expects => [200, 203],
:method => 'GET',
:path => "flavors/#{flavor_id}.json"
)
end
end
class Mock
def get_flavor_details(flavor_id)
response = Excon::Response.new
flavor = {
1 => { 'name' => 'standard.xsmall', 'ram' => 1024, 'disk' => 30, 'id' => 1, 'rxtx_quota' => 0, 'vcpus' => 1, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/1", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/1", "rel"=>"bookmark"}] },
2 => { 'name' => 'standard.small', 'ram' => 2048, 'disk' => 60, 'id' => 2, 'rxtx_quota' => 0, 'vcpus' => 2, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/2", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/2", "rel"=>"bookmark"}] },
3 => { 'name' => 'standard.medium', 'ram' => 4096, 'disk' => 120, 'id' => 3, 'rxtx_quota' => 0, 'vcpus' => 2, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/3", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/3", "rel"=>"bookmark"}] },
4 => { 'name' => 'standard.large', 'ram' => 8192, 'disk' => 240, 'id' => 4, 'rxtx_quota' => 0, 'vcpus' => 4, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/4", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/4", "rel"=>"bookmark"}] },
5 => { 'name' => 'standard.xlarge', 'ram' => 16384, 'disk' => 480, 'id' => 5, 'rxtx_quota' => 0, 'vcpus' => 4, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/5", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/5", "rel"=>"bookmark"}] },
6 => { 'name' => 'standard.2xlarge', 'ram' => 32768, 'disk' => 960, 'id' => 6, 'rxtx_quota' => 0, 'vcpus' => 8, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/6", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/6", "rel"=>"bookmark"}] }
}[flavor_id]
if flavor
response.status = 200
response.body = {
'flavor' => flavor
}
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,43 @@
module Fog
module Compute
class HP
class Real
# Get details for image by id
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'id'<~Integer> - Id of the image
# * 'name'<~String> - Name of the image
# * 'serverId'<~Integer> - Id of server image was created from
# * 'status'<~Integer> - Status of image
# * 'updated'<~String> - Timestamp of last update
def get_image_details(image_id)
request(
:expects => [200, 203],
:method => 'GET',
:path => "images/#{image_id}.json"
)
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::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,57 @@
module Fog
module Compute
class HP
class Real
# Get details about a security group
#
# ==== Parameters
# * 'security_group_id'<~Integer> - Id of security group to get details for
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'security_group'<~Array>:
# * 'rules'<~Array>: - array of security group rules
# * 'id'<~Integer> - id of the security group rule
# * 'from_port'<~Integer> - start port for rule i.e. 22 (or -1 for ICMP wildcard)
# * 'to_port'<~Integer> - end port for rule i.e. 22 (or -1 for ICMP wildcard)
# * 'ip_protocol'<~String> - ip protocol for rule, must be in ['tcp', 'udp', 'icmp']
# * 'group'<~Hash>:
# * Undefined
# * 'parent_group_id'<~Integer> - parent group id
# * 'ip_range'<~Hash>:
# * 'cidr'<~String> - ip range address i.e. '0.0.0.0/0'
# * 'id'<~Integer> - id of the security group
# * 'name'<~String> - name of the security group
# * 'description'<~String> - description of the security group
# * 'tenant_id'<~String> - tenant id of the user
#
# {Openstack API Reference}[http://docs.openstack.org]
def get_security_group(security_group_id)
request(
:expects => [200],
:method => 'GET',
:path => "os-security-groups/#{security_group_id}"
)
end
end
class Mock
def get_security_group(security_group_id)
response = Excon::Response.new
if sec_group = self.data[:security_groups][security_group_id]
response.status = 200
response.body = { 'security_group' => sec_group }
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,52 @@
module Fog
module Compute
class HP
class Real
# Get details about a server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to get details for
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'server'<~Hash>:
# * 'addresses'<~Hash>:
# * 'public'<~Array> - public address strings
# * 'private'<~Array> - private address strings
# * 'flavorId'<~Integer> - Id of servers current flavor
# * 'hostId'<~String>
# * 'id'<~Integer> - Id of server
# * 'imageId'<~Integer> - Id of image used to boot server
# * 'metadata'<~Hash> - metadata
# * 'name<~String> - Name of server
# * 'progress'<~Integer> - Progress through current status
# * 'status'<~String> - Current server status
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::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,41 @@
module Fog
module Compute
class HP
class Real
# List all floating IP addresses
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'floating_ips'<~Array> -
# * 'id'<~Integer> - Id of the address
# * 'ip'<~String> - Floating IP of the address
# * 'instance_id'<~String> - Id of the associated server instance
# * 'fixed_ip'<~String> - Fixed IP of the address
def list_addresses
request(
:expects => 200,
:method => 'GET',
:path => "os-floating-ips.json"
)
end
end
class Mock
def list_addresses
response = Excon::Response.new
addresses = []
addresses = self.data[:addresses].values unless self.data[:addresses].nil?
response.status = 200
response.body = { 'floating_ips' => addresses }
response
end
end
end
end
end

View file

@ -0,0 +1,44 @@
module Fog
module Compute
class HP
class Real
# List all flavors (IDs and names only)
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'id'<~Integer> - Id of the flavor
# * 'name'<~String> - Name of the flavor
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' => 'standard.xsmall', 'id' => 1, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/1", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/1", "rel"=>"bookmark"}] },
{ 'name' => 'standard.small', 'id' => 2, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/2", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/2", "rel"=>"bookmark"}] },
{ 'name' => 'standard.medium', 'id' => 3, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/3", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/3", "rel"=>"bookmark"}] },
{ 'name' => 'standard.large', 'id' => 4, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/4", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/4", "rel"=>"bookmark"}] },
{ 'name' => 'standard.xlarge', 'id' => 5, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/5", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/5", "rel"=>"bookmark"}] },
{ 'name' => 'standard.2xlarge', 'id' => 6, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/6", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/6", "rel"=>"bookmark"}] }
]
}
response
end
end
end
end
end

View file

@ -0,0 +1,46 @@
module Fog
module Compute
class HP
class Real
# List all flavors
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'id'<~Integer> - Id of the flavor
# * 'name'<~String> - Name of the flavor
# * 'ram'<~Integer> - Amount of ram for the flavor
# * 'disk'<~Integer> - Amount of diskspace for the flavor
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' => 'standard.xsmall', 'ram' => 1024, 'disk' => 30, 'id' => 1, 'rxtx_quota' => 0, 'vcpus' => 1, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/1", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/1", "rel"=>"bookmark"}] },
{ 'name' => 'standard.small', 'ram' => 2048, 'disk' => 60, 'id' => 2, 'rxtx_quota' => 0, 'vcpus' => 2, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/2", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/2", "rel"=>"bookmark"}] },
{ 'name' => 'standard.medium', 'ram' => 4096, 'disk' => 120, 'id' => 3, 'rxtx_quota' => 0, 'vcpus' => 2, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/3", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/3", "rel"=>"bookmark"}] },
{ 'name' => 'standard.large', 'ram' => 8192, 'disk' => 240, 'id' => 4, 'rxtx_quota' => 0, 'vcpus' => 4, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/4", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/4", "rel"=>"bookmark"}] },
{ 'name' => 'standard.xlarge', 'ram' => 16384, 'disk' => 480, 'id' => 5, 'rxtx_quota' => 0, 'vcpus' => 4, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/5", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/5", "rel"=>"bookmark"}] },
{ 'name' => 'standard.2xlarge', 'ram' => 32768, 'disk' => 960, 'id' => 6, 'rxtx_quota' => 0, 'vcpus' => 8, 'rxtx_cap' => 0, 'swap' => 0, 'links' => [{"href"=>"http://nova1:8774/v1.1/admin/flavors/6", "rel"=>"self"}, {"href"=>"http://nova1:8774admin/flavors/6", "rel"=>"bookmark"}] }
]
}
response
end
end
end
end
end

View file

@ -0,0 +1,40 @@
module Fog
module Compute
class HP
class Real
# List all images (IDs and names only)
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'id'<~Integer> - Id of the image
# * 'name'<~String> - Name of the image
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

View file

@ -0,0 +1,49 @@
module Fog
module Compute
class HP
class Real
# List all images
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'id'<~Integer> - Id of the image
# * 'name'<~String> - Name of the image
# * 'updated'<~String> - Last update timestamp for image
# * 'created'<~String> - Creation timestamp for image
# * 'status'<~String> - Status of image
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', 'links', 'metadata', 'progress' ,'status', 'created', 'updated'].include?(key)}} }
response
end
end
end
end
end

View file

@ -0,0 +1,44 @@
module Fog
module Compute
class HP
class Real
# List all key pairs
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'keypairs'<~Array>:
# * 'keypair'<~Hash>:
# * 'public_key'<~String> - Public portion of the key
# * 'name'<~String> - Name of the key
# * 'fingerprint'<~String> - Fingerprint of the key
#
# {Openstack API Reference}[http://docs.openstack.org]
def list_key_pairs
request(
:expects => [200, 203],
:method => 'GET',
:path => 'os-keypairs.json'
)
end
end
class Mock
def list_key_pairs
response = Excon::Response.new
key_pairs = []
key_pairs = self.data[:key_pairs].values unless self.data[:key_pairs].nil?
response.status = [200, 203][rand(1)]
response.body = { 'keypairs' => key_pairs }
response
end
end
end
end
end

View file

@ -0,0 +1,54 @@
module Fog
module Compute
class HP
class Real
# List all security groups
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'security_groups'<~Array>:
# * 'rules'<~Array>: - array of security group rules
# * 'id'<~Integer> - id of the security group rule
# * 'from_port'<~Integer> - start port for rule i.e. 22 (or -1 for ICMP wildcard)
# * 'to_port'<~Integer> - end port for rule i.e. 22 (or -1 for ICMP wildcard)
# * 'ip_protocol'<~String> - ip protocol for rule, must be in ['tcp', 'udp', 'icmp']
# * 'group'<~Hash>:
# * Undefined
# * 'parent_group_id'<~Integer> - parent group id
# * 'ip_range'<~Hash>:
# * 'cidr'<~String> - ip range address i.e. '0.0.0.0/0'
# * 'id'<~Integer> - id of the security group
# * 'name'<~String> - name of the security group
# * 'description'<~String> - description of the security group
# * 'tenant_id'<~String> - tenant id of the user
#
# {Openstack API Reference}[http://docs.openstack.org]
def list_security_groups
request(
:expects => [200],
:method => 'GET',
:path => 'os-security-groups.json'
)
end
end
class Mock
def list_security_groups
response = Excon::Response.new
sec_groups = []
sec_groups = self.data[:security_groups].values unless self.data[:security_groups].nil?
response.status = 200
response.body = { 'security_groups' => sec_groups }
response
end
end
end
end
end

View file

@ -0,0 +1,42 @@
module Fog
module Compute
class HP
class Real
# List all server addresses
#
# ==== Parameters
# * server_id<~Integer> - Id of server to list addresses for
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'addresses'<~Hash>:
# * 'novanet_7':<~Array> - The network name can change based on setup
def list_server_addresses(server_id)
request(
:expects => 200,
:method => 'GET',
:path => "servers/#{server_id}/ips.json"
)
end
end
class Mock
def list_server_addresses(server_id)
response = Excon::Response.new
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
response.status = 200
response.body = { 'addresses' => server['addresses'] }
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,58 @@
module Fog
module Compute
class HP
class Real
# List private server addresses
#
# ==== Parameters
# * server_id<~Integer> - Id of server to list addresses for
# * network_name<~String> - The name of the network name i.e. public, private or custom name
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'private'<~Array> - Private ip addresses
def list_server_private_addresses(server_id, network_name)
response = request(
:expects => 200,
:method => 'GET',
:path => "servers/#{server_id}/ips/#{network_name}.json"
)
# return the first address
private_address = []
data = response.body["#{network_name}"][0]
if data
private_address << data
end
response.body = { 'private' => private_address }
response
end
end
class Mock
def list_server_private_addresses(server_id, network_name)
response = Excon::Response.new
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
private_address = []
data = nil
data = server['addresses']["#{network_name}"][0] if server['addresses']["#{network_name}"]
if data
private_address << data
end
response.status = 200
response.body = { 'private' => private_address }
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,58 @@
module Fog
module Compute
class HP
class Real
# List public server addresses
#
# ==== Parameters
# * server_id<~Integer> - Id of server to list addresses for
# * network_name<~String> - The name of the network name i.e. public, private or custom name
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'public'<~Array> - Public ip addresses
def list_server_public_addresses(server_id, network_name)
response = request(
:expects => 200,
:method => 'GET',
:path => "servers/#{server_id}/ips/#{network_name}.json"
)
# return everything except the first address
data = response.body["#{network_name}"]
if data
data.delete_at(0)
public_address = data
end
response.body = { 'public' => public_address }
response
end
end
class Mock
def list_server_public_addresses(server_id, network_name)
response = Excon::Response.new
if server = list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
# return everything except the first address
data = server['addresses']["#{network_name}"]
if data
data.delete_at(0)
public_address = data
end
response.status = 200
response.body = { 'public' => public_address }
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,41 @@
module Fog
module Compute
class HP
class Real
# List all servers (IDs and names only)
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'servers'<~Array>:
# * 'id'<~Integer> - Id of server
# * 'name<~String> - Name of server
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', 'links', 'uuid'].include?(key) }
end
response.status = [200, 203][rand(1)]
response.body = { 'servers' => servers }
response
end
end
end
end
end

View file

@ -0,0 +1,56 @@
module Fog
module Compute
class HP
class Real
# List all servers details
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'servers'<~Array>:
# * 'id'<~Integer> - Id of server
# * 'name<~String> - Name of server
# * 'imageId'<~Integer> - Id of image used to boot server
# * 'flavorId'<~Integer> - Id of servers current flavor
# * 'hostId'<~String>
# * 'status'<~String> - Current server status
# * 'progress'<~Integer> - Progress through current status
# * 'addresses'<~Hash>:
# * 'public'<~Array> - public address strings
# * 'private'<~Array> - private address strings
# * 'metadata'<~Hash> - metadata
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

View file

@ -0,0 +1,34 @@
module Fog
module Compute
class HP
class Real
# Reboot an existing server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to reboot
# * type<~String> - Type of reboot, must be in ['HARD', 'SOFT']
#
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
if list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
response.status = 202
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,32 @@
module Fog
module Compute
class HP
class Real
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
server_action(server_id, body, 202)
end
end
class Mock
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.status = 202
response
end
end
end
end
end

View file

@ -0,0 +1,39 @@
module Fog
module Compute
class HP
class Real
# Release an existing floating IP address
#
# ==== Parameters
# * id<~Integer> - Id of floating IP address to delete
#
def release_address(address_id)
request(
:expects => 202,
:method => 'DELETE',
:path => "os-floating-ips/#{address_id}"
)
end
end
class Mock
def release_address(address_id)
response = Excon::Response.new
if self.data[:addresses][address_id]
self.data[:last_modified][:addresses].delete(address_id)
self.data[:addresses].delete(address_id)
response.status = 202
response.body = "202 Accepted\n\nThe request is accepted for processing.\n\n "
else
raise Fog::Compute::HP::NotFound
end
response
end
end
end
end
end

View file

@ -0,0 +1,39 @@
module Fog
module Compute
class HP
class Real
# Reboot an existing server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to resize
# * size<~String> - new size. call list_flavors to get available flavors
#
def resize_server(server_id, flavor_id)
body = { 'resize' => { 'flavorRef' => flavor_id }}
server_action(server_id, body)
end
end
class Mock
# FIXME: should probably transition instead of skipping to VERIFY_RESIZE
def resize_server(server_id, flavor_id)
response = Excon::Response.new
response.status = 202
# keep track of this for reverts
self.data[:servers][server_id]['old_flavorId'] = self.data[:servers][server_id]['flavorId']
self.data[:servers][server_id]['flavorId'] = flavor_id
self.data[:last_modified][:servers][server_id] = Time.now
self.data[:servers][server_id]['status'] = 'VERIFY_RESIZE'
response
end
end
end
end
end

View file

@ -0,0 +1,35 @@
module Fog
module Compute
class HP
class Real
# Revert resizing
#
# ==== Parameters
# * server_id<~Integer> - Id of server to revert
#
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

View file

@ -0,0 +1,25 @@
module Fog
module Compute
class HP
class Real
# Server actions for an existing server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to reboot
# * body<~.to_json object> - Body of the request, describes the action (see reboot_server as an example)
# * expect<~Integer> - expected return, 202 except for confirm resize (204)
#
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

View file

@ -0,0 +1,42 @@
module Fog
module Compute
class HP
class Real
# Update an existing server
#
# ==== Parameters
# # server_id<~Integer> - Id of server to update
# * options<~Hash>:
# * adminPass<~String> - New admin password for server
# * name<~String> - New name for server
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::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,43 @@
module Fog
module Storage
class HP
class Real
# Delete an existing container
#
# ==== Parameters
# * name<~String> - Name of container to delete
#
def delete_container(name)
response = request(
:expects => 204,
:method => 'DELETE',
:path => Fog::HP.escape(name)
)
response
end
end
class Mock # :nodoc:all
def delete_container(container_name)
response = Excon::Response.new
if self.data[:containers][container_name].nil?
response.status = 404
raise Fog::Storage::HP::NotFound
elsif self.data[:containers][container_name] && !self.data[:containers][container_name][:objects].empty?
response.status = 409
raise(Excon::Errors.status_error({:expects => 204}, response))
else
self.data[:containers].delete(container_name)
response.status = 204
end
response
end
end
end
end
end

View file

@ -0,0 +1,44 @@
module Fog
module Storage
class HP
class Real
# Delete an existing object
#
# ==== Parameters
# * container<~String> - Name of container to delete
# * object<~String> - Name of object to delete
#
def delete_object(container, object)
response = request(
:expects => 204,
:method => 'DELETE',
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
)
response
end
end
class Mock # :nodoc:all
def delete_object(container_name, object_name, options = {})
response = Excon::Response.new
if container = self.data[:containers][container_name]
if (object = container[:objects][object_name])
response.status = 204
container[:objects].delete(object_name)
else
raise Fog::Storage::HP::NotFound
end
else
raise Fog::Storage::HP::NotFound
end
response
end
end
end
end
end

View file

@ -0,0 +1,92 @@
module Fog
module Storage
class HP
class Real
# Get details for container and total bytes stored
#
# ==== Parameters
# * container<~String> - Name of container to retrieve info for
# * options<~String>:
# * 'limit'<~String> - Maximum number of objects to return
# * 'marker'<~String> - Only return objects whose name is greater than marker
# * 'prefix'<~String> - Limits results to those starting with prefix
# * 'path'<~String> - Return objects nested in the pseudo path
#
# ==== Returns
# * response<~Excon::Response>:
# * headers<~Hash>:
# * 'X-Account-Container-Count'<~String> - Count of containers
# * 'X-Account-Bytes-Used'<~String> - Bytes used
# * body<~Array>:
# * 'bytes'<~Integer> - Number of bytes used by container
# * 'count'<~Integer> - Number of items in container
# * 'name'<~String> - Name of container
# * item<~Hash>:
# * 'bytes'<~String> - Size of object
# * 'content_type'<~String> Content-Type of object
# * 'hash'<~String> - Hash of object (etag?)
# * 'last_modified'<~String> - Last modified timestamp
# * 'name'<~String> - Name of object
def get_container(container, options = {})
options = options.reject {|key, value| value.nil?}
response = request(
:expects => 200,
:method => 'GET',
:path => Fog::HP.escape(container),
:query => {'format' => 'json'}.merge!(options)
)
response
end
end
class Mock # :nodoc:all
def get_container(container_name, options = {})
unless container_name
raise ArgumentError.new('container_name is required')
end
if options['delimiter']
Fog::Mock.not_implemented
end
response = Excon::Response.new
obj_count = 0
obj_total_bytes = 0
if container = self.data[:containers][container_name]
contents = container[:objects].values.sort {|x,y| x['Key'] <=> y['Key']}.reject do |object|
(options['prefix'] && object['Key'][0...options['prefix'].length] != options['prefix']) ||
(options['marker'] && object['Key'] <= options['marker'])
end.map do |object|
obj_count = obj_count + 1
obj_total_bytes = obj_total_bytes + object['Content-Length'].to_i
data = {
'name' => object['Key'],
'hash' => object['ETag'],
'bytes' => object['Content-Length'].to_i,
'content_type' => object['Content-Type'],
'last_modified' => Time.parse(object['Date'])
}
data
end
response.status = 200
response.body = contents
response.headers = {
'X-Container-Object-Count' => obj_count,
'X-Container-Bytes-Used' => obj_total_bytes,
'Accept-Ranges' => 'bytes',
'Content-Type' => container['Content-Type'],
'Content-Length' => container['Content-Length']
}
response
else
raise Fog::Storage::HP::NotFound
end
end
end
end
end
end

View file

@ -0,0 +1,71 @@
module Fog
module Storage
class HP
class Real
# List existing storage containers
#
# ==== Parameters
# * options<~Hash>:
# * 'limit'<~Integer> - Upper limit to number of results returned
# * 'marker'<~String> - Only return objects with name greater than this value
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Array>:
# * container<~Hash>:
# * 'bytes'<~Integer>: - Number of bytes used by container
# * 'count'<~Integer>: - Number of items in container
# * 'name'<~String>: - Name of container
def get_containers(options = {})
options = options.reject {|key, value| value.nil?}
response = request(
:expects => [200, 204],
:method => 'GET',
:path => '',
:query => {'format' => 'json'}.merge!(options)
)
response
end
end
class Mock # :nodoc:all
def get_containers(options = {})
response = Excon::Response.new
acc_cont_count = 0
acc_obj_count = 0
acc_obj_bytes = 0
containers = self.data[:containers].map do |key, container|
acc_cont_count = acc_cont_count + 1
obj_count = 0
container[:objects].values.map do |object|
acc_obj_count = acc_obj_count + 1
acc_obj_bytes = acc_obj_bytes + object['Content-Length'].to_i
obj_count = obj_count + 1
container['Object-Count'] = obj_count
end
data = {
'name' => key,
'count' => container['Object-Count'].to_i,
'bytes' => container['Content-Length'].to_i
}
data
end
response.body = containers
response.headers = {
'X-Account-Object-Count' => acc_obj_count,
'X-Account-Bytes-Used' => acc_obj_bytes,
'X-Account-Container-Count' => acc_cont_count,
'Accept-Ranges' => 'bytes'
}
response.status = 200
response
end
end
end
end
end

View file

@ -0,0 +1,77 @@
module Fog
module Storage
class HP
class Real
# Get details for an object
#
# ==== Parameters
# * container<~String> - Name of container to look in
# * object<~String> - Name of object to look for
#
def get_object(container, object, &block)
response = request({
:block => block,
:expects => 200,
:method => 'GET',
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
}, false, &block)
response
end
end
class Mock # :nodoc:all
def get_object(container_name, object_name, options = {}, &block)
unless container_name
raise ArgumentError.new('container_name is required')
end
unless object_name
raise ArgumentError.new('object_name is required')
end
response = Excon::Response.new
if (container = self.data[:containers][container_name])
if (object = container[:objects][object_name])
if options['If-Match'] && options['If-Match'] != object['ETag']
response.status = 412
elsif options['If-Modified-Since'] && options['If-Modified-Since'] > Time.parse(object['Last-Modified'])
response.status = 304
elsif options['If-None-Match'] && options['If-None-Match'] == object['ETag']
response.status = 304
elsif options['If-Unmodified-Since'] && options['If-Unmodified-Since'] < Time.parse(object['Last-Modified'])
response.status = 412
else
response.status = 200
for key, value in object
case key
when 'Cache-Control', 'Content-Disposition', 'Content-Encoding', 'Content-Length', 'Content-MD5', 'Content-Type', 'ETag', 'Expires', 'Last-Modified', /^X-Object-Meta-/
response.headers[key] = value
end
end
unless block_given?
response.body = object[:body]
else
data = StringIO.new(object[:body])
remaining = data.length
while remaining > 0
chunk = data.read([remaining, Excon::CHUNK_SIZE].min)
block.call(chunk)
remaining -= Excon::CHUNK_SIZE
end
end
end
else
raise Fog::Storage::HP::NotFound
end
else
raise Fog::Storage::HP::NotFound
end
response
end
end
end
end
end

View file

@ -0,0 +1,40 @@
module Fog
module Storage
class HP
class Real
# List number of objects and total bytes stored
#
# ==== Parameters
# * container<~String> - Name of container to retrieve info for
#
# ==== Returns
# * response<~Excon::Response>:
# * headers<~Hash>:
# * 'X-Container-Object-Count'<~String> - Count of containers
# * 'X-Container-Bytes-Used'<~String> - Bytes used
def head_container(container)
response = request(
:expects => 204,
:method => 'HEAD',
:path => Fog::HP.escape(container),
:query => {'format' => 'json'}
)
response
end
end
class Mock # :nodoc:all
def head_container(container_name)
response = get_container(container_name)
response.body = nil
response
end
end
end
end
end

View file

@ -0,0 +1,37 @@
module Fog
module Storage
class HP
class Real
# List number of containers and total bytes stored
#
# ==== Returns
# * response<~Excon::Response>:
# * headers<~Hash>:
# * 'X-Account-Container-Count'<~String> - Count of containers
# * 'X-Account-Bytes-Used'<~String> - Bytes used
def head_containers
response = request(
:expects => 204,
:method => 'HEAD',
:path => '',
:query => {'format' => 'json'}
)
response
end
end
class Mock # :nodoc:all
def head_containers
response = get_containers
response.body = nil
response
end
end
end
end
end

View file

@ -0,0 +1,35 @@
module Fog
module Storage
class HP
class Real
# Get headers for object
#
# ==== Parameters
# * container<~String> - Name of container to look in
# * object<~String> - Name of object to look for
#
def head_object(container, object)
response = request({
:expects => 200,
:method => 'HEAD',
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
}, false)
response
end
end
class Mock # :nodoc:all
def head_object(container_name, object_name, options = {})
response = get_object(container_name, object_name, options)
response.body = nil
response
end
end
end
end
end

View file

@ -0,0 +1,48 @@
module Fog
module Storage
class HP
class Real
# Create a new container
#
# ==== Parameters
# * name<~String> - Name for container, should be < 256 bytes and must not contain '/'
#
def put_container(name, options = {})
response = request(
:expects => [201, 202],
:headers => options,
:method => 'PUT',
:path => Fog::HP.escape(name)
)
response
end
end
class Mock # :nodoc:all
def put_container(container_name, options = {})
acl = options['X-Container-Read'] || 'private'
if !['private', 'public-read'].include?(acl)
#raise Excon::Errors::BadRequest.new('invalid X-Container-Read')
else
self.data[:acls][:container][container_name] = self.class.acls(acl)
end
response = Excon::Response.new
container = {
:objects => {},
}
if self.data[:containers][container_name]
response.status = 202
else
response.status = 201
self.data[:containers][container_name] = container
end
response
end
end
end
end
end

View file

@ -0,0 +1,94 @@
module Fog
module Storage
class HP
class Real
# Create a new object
#
# ==== Parameters
# * container<~String> - Name for container, should be < 256 bytes and must not contain '/'
#
def put_object(container, object, data, options = {})
data = Fog::Storage.parse_data(data)
headers = data[:headers].merge!(options)
if headers.has_key?('Transfer-Encoding')
headers.delete('Content-Length')
end
response = request(
:body => data[:body],
:expects => 201,
:headers => headers,
:method => 'PUT',
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
)
response
end
end
class Mock # :nodoc:all
def put_object(container_name, object_name, data, options = {})
response = Excon::Response.new
### Take care of case of copy operation
source = options['X-Copy-From']
if (source && data.nil?)
# split source container and object
_, source_container_name, source_object_name = source.split('/')
# dup object into target object
source_container = self.data[:containers][source_container_name]
container = self.data[:containers][container_name]
if (source_container && container)
response.status = 201
source_object = source_container[:objects][source_object_name]
target_object = source_object.dup
target_object.merge!({
'Key' => object_name,
'Date' => Fog::Time.now.to_date_header
})
container[:objects][object_name] = target_object
else
raise Fog::Storage::HP::NotFound
end
else
data = Fog::Storage.parse_data(data)
unless data[:body].is_a?(String)
data[:body] = data[:body].read
end
if (container = self.data[:containers][container_name])
response.status = 201
object = {
:body => data[:body],
'Content-Type' => options['Content-Type'] || data[:headers]['Content-Type'],
'ETag' => Fog::HP::Mock.etag,
'Key' => object_name,
'Date' => Fog::Time.now.to_date_header,
'Content-Length' => options['Content-Length'] || data[:headers]['Content-Length'],
}
for key, value in options
case key
when 'Cache-Control', 'Content-Disposition', 'Content-Encoding', 'Content-MD5', 'Expires', /^X-Object-Meta-/
object[key] = value
end
end
container[:objects][object_name] = object
response.headers = {
'Content-Length' => object['Content-Length'],
'Content-Type' => object['Content-Type'],
'ETag' => object['ETag'],
'Date' => object['Date']
}
else
raise Fog::Storage::HP::NotFound
end
end
response
end
end
end
end
end

200
lib/fog/hp/storage.rb Normal file
View file

@ -0,0 +1,200 @@
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'hp'))
require 'fog/storage'
module Fog
module Storage
class HP < Fog::Service
requires :hp_secret_key, :hp_account_id, :hp_tenant_id
recognizes :hp_auth_uri, :hp_servicenet, :hp_cdn_ssl, :hp_cdn_uri, :persistent, :connection_options, :hp_use_upass_auth_style, :hp_auth_version
model_path 'fog/hp/models/storage'
model :directory
collection :directories
model :file
collection :files
request_path 'fog/hp/requests/storage'
request :delete_container
request :delete_object
request :get_container
request :get_containers
request :get_object
request :head_container
request :head_containers
request :head_object
request :put_container
request :put_object
module Utils
def cdn
unless @hp_cdn_uri.nil?
@cdn ||= Fog::CDN.new(
:provider => 'HP',
:hp_account_id => @hp_account_id,
:hp_secret_key => @hp_secret_key,
:hp_auth_uri => @hp_auth_uri,
:hp_cdn_uri => @hp_cdn_uri,
:hp_tenant_id => @hp_tenant_id,
:connection_options => @connection_options
)
if @cdn.enabled?
@cdn
end
else
nil
end
end
def url
"#{@scheme}://#{@host}:#{@port}#{@path}"
end
def acl_to_header(acl)
header = {}
case acl
when "private"
header['X-Container-Read'] = ""
header['X-Container-Write'] = ""
when "public-read"
header['X-Container-Read'] = ".r:*,.rlistings"
when "public-write"
header['X-Container-Write'] = "*"
when "public-read-write"
header['X-Container-Read'] = ".r:*,.rlistings"
header['X-Container-Write'] = "*"
end
header
end
def header_to_acl(read_header=nil, write_header=nil)
acl = nil
if read_header.nil? && write_header.nil?
acl = nil
elsif !read_header.nil? && read_header.include?(".r:*") && write_header.nil?
acl = "public-read"
elsif !write_header.nil? && write_header.include?("*") && read_header.nil?
acl = "public-write"
elsif !read_header.nil? && read_header.include?(".r:*") && !write_header.nil? && write_header.include?("*")
acl = "public-read-write"
end
end
end
class Mock
include Utils
def self.acls(type)
type
end
def self.data
@data ||= Hash.new do |hash, key|
hash[key] = {
:acls => {
:container => {},
:object => {}
},
:containers => {}
}
end
end
def self.reset
@data = nil
end
def initialize(options={})
require 'mime/types'
@hp_secret_key = options[:hp_secret_key]
@hp_account_id = options[:hp_account_id]
end
def data
self.class.data[@hp_account_id]
end
def reset_data
self.class.data.delete(@hp_account_id)
end
end
class Real
include Utils
attr_reader :hp_cdn_ssl
def initialize(options={})
require 'mime/types'
require 'multi_json'
@hp_secret_key = options[:hp_secret_key]
@hp_account_id = options[:hp_account_id]
@hp_auth_uri = options[:hp_auth_uri]
@hp_cdn_ssl = options[:hp_cdn_ssl]
@connection_options = options[:connection_options] || {}
### Set an option to use the style of authentication desired; :v1 or :v2 (default)
auth_version = options[:hp_auth_version] || :v2
### Pass the service type for object storage to the authentication call
options[:hp_service_type] = "object-store"
@hp_tenant_id = options[:hp_tenant_id]
### Make the authentication call
if (auth_version == :v2)
# Call the control services authentication
credentials = Fog::HP.authenticate_v2(options, @connection_options)
# the CS service catalog returns the cdn endpoint
@hp_storage_uri = credentials[:endpoint_url]
@hp_cdn_uri = credentials[:cdn_endpoint_url]
else
# Call the legacy v1.0/v1.1 authentication
credentials = Fog::HP.authenticate_v1(options, @connection_options)
# the user sends in the cdn endpoint
@hp_storage_uri = options[:hp_auth_uri]
@hp_cdn_uri = options[:hp_cdn_uri]
end
@auth_token = credentials[:auth_token]
uri = URI.parse(@hp_storage_uri)
@host = options[:hp_servicenet] == true ? "snet-#{uri.host}" : uri.host
@path = uri.path
@persistent = options[:persistent] || false
@port = uri.port
@scheme = uri.scheme
Excon.ssl_verify_peer = false if options[:hp_servicenet] == true
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
end
def reload
@connection.reset
end
def request(params, parse_json = true, &block)
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]}",
}), &block)
rescue Excon::Errors::HTTPStatusError => error
raise case error
when Excon::Errors::NotFound
Fog::Storage::HP::NotFound.slurp(error)
else
error
end
end
if !response.body.empty? && parse_json && response.headers['Content-Type'] =~ %r{application/json}
response.body = MultiJson.decode(response.body)
end
response
end
end
end
end
end

View file

@ -10,6 +10,7 @@ require 'fog/ecloud'
require 'fog/glesys'
require 'fog/go_grid'
require 'fog/google'
require 'fog/hp'
require 'fog/ibm'
require 'fog/joyent'
require 'fog/libvirt'
@ -29,3 +30,4 @@ require 'fog/vsphere'
require 'fog/voxel'
require 'fog/xenserver'
require 'fog/zerigo'
require 'fog/zerigo'

View file

@ -14,6 +14,9 @@ module Fog
when :google
require 'fog/google/storage'
Fog::Storage::Google.new(attributes)
when :hp
require 'fog/hp/storage'
Fog::Storage::HP.new(attributes)
when :ibm
require 'fog/ibm/storage'
Fog::Storage::IBM.new(attributes)

View file

@ -22,6 +22,14 @@ def compute_providers
:glesys => {
:mocked => false
},
:hp => {
:server_attributes => {
:flavor_id => 100,
:image_id => 1242,
:name => "fog_#{Time.now.to_i}"
},
:mocked => true
},
:ibm => {
:server_attributes => {},
:mocked => true

View file

@ -12,7 +12,7 @@ def array_differences(array_a, array_b)
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', 'ibm', 'joyent', 'libvirt', 'linode', 'local', 'ninefold', 'baremetalcloud', 'openstack', 'ovirt', 'rackspace', 'slicehost', 'stormondemand', 'voxel', 'vsphere', 'zerigo']
all_providers = ['aws', 'bluebox', 'brightbox', 'dnsimple', 'dnsmadeeasy', 'dynect', 'ecloud', 'glesys', 'gogrid', 'google', 'hp', '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)[/]")

View file

@ -30,6 +30,9 @@ if Fog.mock?
:go_grid_shared_secret => 'go_grid_shared_secret',
:google_storage_access_key_id => 'google_storage_access_key_id',
:google_storage_secret_access_key => 'google_storage_secret_access_key',
:hp_account_id => 'hp_account_id',
:hp_secret_key => 'hp_secret_key',
:hp_tenant_id => 'hp_tenant_id',
:ibm_username => 'ibm_username',
:ibm_password => 'ibm_password',
:joyent_username => "joyentuser",

View file

@ -0,0 +1,18 @@
Shindo.tests("Fog::Compute[:hp] | address", [:hp]) do
@base_image_id = ENV["BASE_IMAGE_ID"] ||= 1242
model_tests(Fog::Compute[:hp].addresses, {}, true) do
@server = Fog::Compute[:hp].servers.create(:name => "fogservertests", :flavor_id => 100, :image_id => @base_image_id)
@server.wait_for { ready? }
tests('#server=').succeeds do
@instance.server = @server
end
@server.destroy
end
end

View file

@ -0,0 +1,5 @@
Shindo.tests("Fog::Compute[:hp] | addresses", [:hp]) do
collection_tests(Fog::Compute[:hp].addresses, {}, true)
end

View file

@ -0,0 +1,27 @@
Shindo.tests("Fog::Compute[:hp] | key_pair", [:hp]) do
model_tests(Fog::Compute[:hp].key_pairs, {:name => 'fogkeyname'}, true)
after do
@keypair.destroy
end
tests("new keypair") do
@keypair = Fog::Compute[:hp].key_pairs.create(:name => 'testkey')
test ("writable?") do
@keypair.writable? == true
end
end
tests("existing keypair") do
Fog::Compute[:hp].key_pairs.create(:name => 'testkey')
@keypair = Fog::Compute[:hp].key_pairs.get('testkey')
test("writable?") do
@keypair.writable? == false
end
end
end

View file

@ -0,0 +1,5 @@
Shindo.tests("Fog::Compute[:hp] | key_pairs", [:hp]) do
collection_tests(Fog::Compute[:hp].key_pairs, {:name => 'fogkeyname'}, true)
end

View file

@ -0,0 +1,36 @@
Shindo.tests("Fog::Compute[:hp] | security_group", [:hp]) do
model_tests(Fog::Compute[:hp].security_groups, {:name => 'foggroupname', :description => 'foggroupdescription'}, true)
tests("a group with trailing whitespace") do
@group = Fog::Compute[:hp].security_groups.create(:name => " foggroup with spaces ", :description => " fog group desc ")
test("all spaces are removed from name") do
@group.name == " foggroup with spaces ".strip!
end
test("all spaces are removed from description") do
@group.description == " fog group desc ".strip!
end
@other_group = Fog::Compute[:hp].security_groups.create(:name => 'other group', :description => 'another group')
test("authorize access by another security group") do
sgrule = @group.create_rule(80..80, "tcp", nil, @other_group.id)
@sg_rule_id = sgrule.body['security_group_rule']['id']
@group.reload
s = @group.rules.select {|r| r['id'] == @sg_rule_id unless r.nil?}
s[0]['id'] == @sg_rule_id
end
test("revoke access from another security group") do
@group.delete_rule(@sg_rule_id)
@group.reload
s = @group.rules.select {|r| r['id'] == @sg_rule_id unless r.nil?}
s.empty?
end
@other_group.destroy
@group.destroy
end
end

View file

@ -0,0 +1,5 @@
Shindo.tests("Fog::Compute[:hp] | security_groups", [:hp]) do
collection_tests(Fog::Compute[:hp].security_groups, {:name => 'foggroupname', :description => 'foggroupdescription'}, true)
end

View file

@ -0,0 +1,56 @@
Shindo.tests('Fog::CDN[:hp] | container requests', [:hp]) do
@cdn_containers_format = [{
'x-cdn-ssl-uri' => String,
'cdn_enabled' => Fog::Boolean,
'name' => String,
'x-cdn-uri' => String,
'ttl' => Integer,
'log_retention' => Fog::Boolean
}]
tests('success') do
tests("#put_container('fogcdncontainertests')").succeeds do
Fog::CDN[:hp].put_container('fogcdncontainertests')
end
tests("duplicate #put_container('fogcdncontainertests')").succeeds do
Fog::CDN[:hp].put_container('fogcdncontainertests')
end
tests("#get_containers").formats(@cdn_containers_format) do
Fog::CDN[:hp].get_containers.body
end
tests("#post_container('fogcdncontainertests', {'x-ttl' => 3200})").succeeds do
Fog::CDN[:hp].post_container('fogcdncontainertests', {'x-ttl' => 3200})
end
tests("#head_container('fogcdncontainertests')").succeeds do
Fog::CDN[:hp].head_container('fogcdncontainertests')
end
tests("#delete_container('fogcdncontainertests')").succeeds do
Fog::CDN[:hp].delete_container('fogcdncontainertests')
end
end
tests('failure') do
tests("#post_container('fognoncdncontainer', {'x-ttl' => 3200})").raises(Fog::CDN::HP::NotFound) do
Fog::CDN[:hp].post_container('fogcdnnoncontainer', {'x-ttl' => 3200})
end
tests("#head_container('fognoncdncontainer')").raises(Fog::CDN::HP::NotFound) do
Fog::CDN[:hp].head_container('fognoncdncontainer')
end
tests("#delete_container('fognoncdncontainer')").raises(Fog::CDN::HP::NotFound) do
Fog::CDN[:hp].delete_container('fognoncdncontainer')
end
end
end

View file

@ -0,0 +1,72 @@
Shindo.tests('Fog::Compute[:hp] | address requests', [:hp]) do
@floating_ips_format = {
'instance_id' => Fog::Nullable::Integer,
'ip' => Fog::Nullable::String,
'fixed_ip' => Fog::Nullable::String,
'id' => Integer
}
@base_image_id = ENV["BASE_IMAGE_ID"] ||= 1242
tests('success') do
tests("#list_addresses").formats({'floating_ips' => [@floating_ips_format]}) do
Fog::Compute[:hp].list_addresses.body
end
tests("#allocate_address").formats(@floating_ips_format) do
data = Fog::Compute[:hp].allocate_address.body['floating_ip']
@address_id = data['id']
@ip_address = data['ip']
data
end
tests("#get_address('#{@address_id}')").formats(@floating_ips_format) do
Fog::Compute[:hp].get_address(@address_id).body['floating_ip']
end
@server = Fog::Compute[:hp].servers.create(:name => 'fogaddresstests', :flavor_id => 100, :image_id => @base_image_id)
@server.wait_for { ready? }
tests("#associate_address('#{@server.id}', '#{@ip_address}')").succeeds do
Fog::Compute[:hp].associate_address(@server.id, @ip_address)
tests("#get_address").returns(@server.id, "associated to valid instance id") do
pending if Fog.mocking?
Fog::Compute[:hp].get_address(@address_id).body['floating_ip']['instance_id']
end
end
tests("#disassociate_address('#{@server.id}', '#{@ip_address}')").succeeds do
Fog::Compute[:hp].disassociate_address(@server.id, @ip_address)
end
@server.destroy
tests("#release_address('#{@address_id}')").succeeds do
Fog::Compute[:hp].release_address(@address_id)
end
end
tests('failure') do
tests("#get_address('invalidaddress', 'invalidip')").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].get_address('invalidaddress')
end
tests("#associate_address('invalidserver', 'invalidip')").raises(Excon::Errors::InternalServerError) do
Fog::Compute[:hp].associate_address('invalidserver', 'invalidip')
end
tests("#disassociate_address('invalidserver', 'invalidip')").raises(Excon::Errors::InternalServerError) do
Fog::Compute[:hp].disassociate_address('invalidserver', 'invalidip')
end
tests("#release_address('invalidaddress')").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].release_address('invalidaddress')
end
end
end

View file

@ -0,0 +1,45 @@
Shindo.tests('Fog::Compute[:hp] | flavor requests', [:hp]) do
@flavor_format = {
'rxtx_quota' => Integer,
'rxtx_cap' => Integer,
'vcpus' => Integer,
'swap' => Integer,
'disk' => Integer,
'ram' => Integer,
'id' => Integer,
'links' => [Hash],
'name' => String
}
@list_flavors_format = {
'id' => Integer,
'name' => String,
'links' => [Hash]
}
tests('success') do
tests('#list_flavors').formats({'flavors' => [@list_flavors_format]}) do
Fog::Compute[:hp].list_flavors.body
end
tests('#get_flavor_details(1)').formats(@flavor_format) do
Fog::Compute[:hp].get_flavor_details(1).body['flavor']
end
tests('#list_flavors_detail').formats({'flavors' => [@flavor_format]}) do
Fog::Compute[:hp].list_flavors_detail.body
end
end
tests('failure') do
tests('#get_flavor_details(9999)').raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].get_flavor_details(9999)
end
end
end

View file

@ -0,0 +1,79 @@
Shindo.tests('Fog::Compute[:hp] | image requests', [:hp]) do
@image_format = {
'id' => String,
'links' => [Hash],
'metadata' => Fog::Nullable::Hash,
'server' => Fog::Nullable::Hash,
'name' => String,
'progress' => Fog::Nullable::Integer,
'status' => String,
'created' => Fog::Nullable::String,
'updated' => Fog::Nullable::String
}
@list_images_format = {
'id' => String,
'links' => Fog::Nullable::Array,
'name' => String
}
@base_image_id = ENV["BASE_IMAGE_ID"] ||= 1242
tests('success') do
@server_name = "fogservertest"
@image_name = "fogimagetest"
@server = Fog::Compute[:hp].servers.create(:name => @server_name, :flavor_id => 100, :image_id => @base_image_id)
@server.wait_for { ready? }
@image_id = nil
tests("#create_image(#{@server.id}, #{@image_name})").formats({}) do
response = Fog::Compute[:hp].create_image(@server.id, @image_name)
# no data is returned for the call, so get id off the header
@image_id = response.headers["Location"].split("/")[5]
{}
end
unless Fog.mocking?
Fog::Compute[:hp].images.get(@image_id).wait_for { ready? }
end
tests("#get_image_details(#{@image_id})").formats(@image_format) do
pending if Fog.mocking?
Fog::Compute[:hp].get_image_details(@image_id).body['image']
end
tests('#list_images').formats({'images' => [@list_images_format]}) do
Fog::Compute[:hp].list_images.body
end
tests('#list_images_detail').formats({'images' => [@image_format]}) do
Fog::Compute[:hp].list_images_detail.body
end
unless Fog.mocking?
Fog::Compute[:hp].images.get(@image_id).wait_for { ready? }
end
tests("#delete_image(#{@image_id})").succeeds do
pending if Fog.mocking?
Fog::Compute[:hp].delete_image(@image_id)
end
@server.destroy
end
tests('failure') do
tests('#delete_image(0)').raises(Excon::Errors::InternalServerError) do
Fog::Compute[:hp].delete_image(0)
end
tests('#get_image_details(0)').raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].get_image_details(0)
end
end
end

View file

@ -0,0 +1,65 @@
Shindo.tests('Fog::Compute[:hp] | key pair requests', [:hp]) do
tests('success') do
@keypair_format = {
'public_key' => String,
'fingerprint' => String,
'name' => String
}
@keypairs_format = {
'keypairs' => [{
'keypair' => {
'public_key' => String,
'fingerprint' => String,
'name' => Fog::Nullable::String
}
}]
}
@key_pair_name = 'fog_create_key_pair'
@public_key_material = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA1SL+kgze8tvSFW6Tyj3RyZc9iFVQDiCKzjgwn2tS7hyWxaiDhjfY2mBYSZwFdKN+ZdsXDJL4CPutUg4DKoQneVgIC1zuXrlpPbaT0Btu2aFd4qNfJ85PBrOtw2GrWZ1kcIgzZ1mMbQt6i1vhsySD2FEj+5kGHouNxQpI5dFR5K+nGgcTLFGnzb/MPRBk136GVnuuYfJ2I4va/chstThoP8UwnoapRHcBpwTIfbmmL91BsRVqjXZEUT73nxpxFeXXidYwhHio+5dXwE0aM/783B/3cPG6FVoxrBvjoNpQpAcEyjtRh9lpwHZtSEW47WNzpIW3PhbQ8j4MryznqF1Rhw=='
tests("#create_key_pair('#{@key_pair_name}')").formats({'keypair' => @keypair_format.merge({'private_key' => String, 'user_id' => String})}) do
body = Fog::Compute[:hp].create_key_pair(@key_pair_name).body
tests("private_key").returns(OpenSSL::PKey::RSA, "is a valid private RSA key") do
OpenSSL::PKey::RSA.new(body['keypair']['private_key']).class
end
body
end
tests('#list_key_pairs').formats(@keypairs_format) do
Fog::Compute[:hp].list_key_pairs.body
end
tests("#delete_key_pair('#{@key_pair_name}')").succeeds do
Fog::Compute[:hp].delete_key_pair(@key_pair_name)
end
tests("#create_key_pair('fog_import_key_pair', '#{@public_key_material}')").formats({'keypair' => @keypair_format.merge({'user_id' => String})}) do
Fog::Compute[:hp].create_key_pair('fog_import_key_pair', @public_key_material).body
end
tests("#delete_key_pair('fog_import_key_pair)").succeeds do
Fog::Compute[:hp].delete_key_pair('fog_import_key_pair')
end
end
tests('failure') do
tests("#delete_key_pair('not_a_key_name')").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].delete_key_pair('not_a_key_name')
end
@key_pair = Fog::Compute[:hp].key_pairs.create(:name => 'fog_key_pair')
tests("duplicate #create_key_pair('#{@key_pair.name}')").raises(Excon::Errors::BadRequest) do
Fog::Compute[:hp].create_key_pair(@key_pair.name)
end
@key_pair.destroy
end
end

View file

@ -0,0 +1,54 @@
Shindo.tests('Fog::Compute[:hp] | security group requests', [:hp]) do
@security_group_rule_format = {
'from_port' => Integer,
'group' => Fog::Nullable::Hash,
'ip_protocol' => String,
'to_port' => Integer,
'parent_group_id' => Integer,
'ip_range' => {
'cidr' => String
},
'id' => Integer
}
tests('success') do
@security_group = Fog::Compute[:hp].security_groups.create(:name => 'fog_security_group', :description => 'tests group')
tests("tcp #create_security_group_rule('#{@security_group.id}', 'tcp', '80', '80', '0.0.0.0/0'}')").formats({'security_group_rule' => @security_group_rule_format}) do
data = Fog::Compute[:hp].create_security_group_rule(@security_group.id, 'tcp', '80', '80', '0.0.0.0/0').body
@sec_group_rule_id_1 = data['security_group_rule']['id']
data
end
tests("icmp #create_security_group_rule('#{@security_group.id}', 'icmp', '-1', '-1', '0.0.0.0/0'}')").formats({'security_group_rule' => @security_group_rule_format}) do
data = Fog::Compute[:hp].create_security_group_rule(@security_group.id, 'icmp', '-1', '-1', '0.0.0.0/0').body
@sec_group_rule_id_2 = data['security_group_rule']['id']
data
end
tests("tcp #delete_security_group_rule('#{@sec_group_rule_id_1}')").succeeds do
Fog::Compute[:hp].delete_security_group_rule(@sec_group_rule_id_1).body
end
tests("icmp #delete_security_group_rule('#{@sec_group_rule_id_2}')").succeeds do
Fog::Compute[:hp].delete_security_group_rule(@sec_group_rule_id_2).body
end
@security_group.destroy
end
tests('failure') do
tests("#create_security_group_rule(0, 'tcp', '80', '80', '0.0.0.0/0'}')").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].create_security_group_rule(0, 'tcp', '80', '80', '0.0.0.0/0')
end
tests("#delete_security_group_rule(0)").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].delete_security_group_rule(0)
end
end
end

View file

@ -0,0 +1,64 @@
Shindo.tests('Fog::Compute[:hp] | security group requests', [:hp]) do
@security_groups_format = {
'security_groups' => [{
'rules' => [Fog::Nullable::Hash],
'tenant_id' => String,
'id' => Integer,
'name' => String,
'description' => String
}]
}
@security_group_format = {
'rules' => [Fog::Nullable::Hash],
'tenant_id' => String,
'id' => Integer,
'name' => String,
'description' => String
}
tests('success') do
tests("#create_security_group('fog_security_group', 'tests group')").formats({'security_group' => @security_group_format}) do
data = Fog::Compute[:hp].create_security_group('fog_security_group', 'tests group').body
@sec_group_id = data['security_group']['id']
data
end
tests("#get_security_group('#{@sec_group_id}')").formats({'security_group' => @security_group_format}) do
Fog::Compute[:hp].get_security_group(@sec_group_id).body
end
tests("#list_security_groups").formats(@security_groups_format) do
Fog::Compute[:hp].list_security_groups.body
end
tests("#delete_security_group('#{@sec_group_id}')").succeeds do
Fog::Compute[:hp].delete_security_group(@sec_group_id).body
end
end
tests('failure') do
@security_group = Fog::Compute[:hp].security_groups.create(:name => 'fog_security_group_fail', :description => 'tests group')
tests("duplicate #create_security_group(#{@security_group.name}, #{@security_group.description})").raises(Excon::Errors::BadRequest) do
Fog::Compute[:hp].create_security_group(@security_group.name, @security_group.description)
end
tests("#get_security_group(0)").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].get_security_group(0)
end
tests("#delete_security_group(0)").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].delete_security_group(0)
end
@security_group.destroy
end
end

Some files were not shown because too many files have changed in this diff Show more