Merge pull request #1505 from rupakg/update_hpfog_0.0.19_to_upstream_fog_1.9.0

Update hpfog 0.0.19 to upstream fog 1.9.0 (2)
This commit is contained in:
Rupak Ganguly 2013-01-25 14:54:40 -08:00
Родитель d93f3bfd77 99a3cb5c4f
Коммит 23f3e94756
105 изменённых файлов: 4195 добавлений и 240 удалений

Просмотреть файл

@ -10,7 +10,6 @@ Gem::Specification.new do |s|
s.date = '2013-01-19'
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"

Просмотреть файл

@ -3,6 +3,8 @@ class HP < Fog::Bin
def class_for(key)
case key
when :block_storage
Fog::HP::BlockStorage
when :cdn
Fog::CDN::HP
when :compute
@ -17,11 +19,16 @@ class HP < Fog::Bin
def [](service)
@@connections ||= Hash.new do |hash, key|
hash[key] = case key
when :block_storage
Fog::HP::BlockStorage.new
when :cdn
Fog::Logger.warning("HP[:cdn] is deprecated, use CDN[:hp] instead")
Fog::CDN.new(:provider => 'HP')
when :compute
Fog::Logger.warning("HP[:compute] is deprecated, use Compute[:hp] instead")
Fog::Compute.new(:provider => 'HP')
when :storage
Fog::Logger.warning("HP[:storage] is deprecated, use Storage[:hp] instead")
Fog::Storage.new(:provider => 'HP')
else
raise ArgumentError, "Unrecognized service: #{key.inspect}"

Просмотреть файл

@ -46,9 +46,10 @@ 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_access_key:
:hp_secret_key:
:hp_tenant_id:
:hp_avl_zone:
:linode_api_key:
:local_root:
:bare_metal_cloud_password:

Просмотреть файл

@ -2,6 +2,12 @@ require 'fog/core'
module Fog
module HP
# define a specific version for the HP Provider
unless const_defined?(:VERSION)
VERSION = '0.0.19'
end
extend Fog::Provider
module Errors
@ -13,10 +19,14 @@ module Fog
data = nil
message = nil
else
data = Fog::JSON.decode(error.response.body)
message = data['message']
if message.nil? and !data.values.first.nil?
message = data.values.first['message']
begin
data = Fog::JSON.decode(error.response.body)
message = data['message']
if message.nil? and !data.values.first.nil?
message = data.values.first['message']
end
rescue MultiJson::DecodeError
message = error.response.body #### body is not in JSON format, so just return as is
end
end
@ -29,6 +39,7 @@ module Fog
class InternalServerError < ServiceError; end
class Conflict < ServiceError; end
class NotFound < ServiceError; end
class Forbidden < ServiceError; end
class ServiceUnavailable < ServiceError; end
class BadRequest < ServiceError
@ -47,6 +58,7 @@ module Fog
service(:cdn, 'hp/cdn', 'CDN')
service(:compute, 'hp/compute', 'Compute')
service(:storage, 'hp/storage', 'Storage')
service(:block_storage, 'hp/block_storage', 'BlockStorage')
# legacy swauth 1.0/1.1 style authentication
def self.authenticate_v1(options, connection_options = {})
@ -61,14 +73,17 @@ module Fog
@auth_path = "auth/v1.0"
end
service_url = "#{@scheme}://#{@host}:#{@port}"
# Set the User-Agent
@user_agent = options[:user_agent]
set_user_agent_header(connection_options, "hpfog v1/#{Fog::HP::VERSION}", @user_agent)
connection = Fog::Connection.new(service_url, false, connection_options)
@hp_account_id = options[:hp_account_id]
@hp_access_key = options[:hp_access_key]
@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
'X-Auth-User' => @hp_access_key
},
:host => @host,
:port => @port,
@ -101,16 +116,19 @@ module Fog
@auth_path = "v2.0/tokens"
end
service_url = "#{@scheme}://#{@host}:#{@port}"
# Set the User-Agent. If the caller sets a user_agent, use it.
@user_agent = options[:user_agent]
set_user_agent_header(connection_options, "hpfog/#{Fog::HP::VERSION}", @user_agent)
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_access_key = options[:hp_access_key]
@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
@hp_avl_zone = options[:hp_avl_zone]
### Decide which auth style to use
unless (@hp_use_upass_auth_style)
@ -118,7 +136,7 @@ module Fog
request_body = {
'auth' => {
'apiAccessKeyCredentials' => {
'accessKey' => "#{@hp_account_id}",
'accessKey' => "#{@hp_access_key}",
'secretKey' => "#{@hp_secret_key}"
}
}
@ -128,17 +146,17 @@ module Fog
request_body = {
'auth' => {
'passwordCredentials' => {
'username' => "#{@hp_account_id}",
'username' => "#{@hp_access_key}",
'password' => "#{@hp_secret_key}"
}
}
}
end
# add tenant_id if specified
request_body['auth']['tenantId'] = "#{@hp_tenant_id}" if @hp_tenant_id
request_body['auth']['tenantId'] = @hp_tenant_id if @hp_tenant_id
### Make the call to CS to get auth token and service catalog
response = service.request(
response = connection.request(
{
:expects => 200,
:headers => {
@ -157,9 +175,9 @@ module Fog
### 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)
# If service is Storage, then get the CDN endpoint as well. 'Name' is unique instead of 'Type'
if @hp_service_type == "Object Storage"
cdn_endpoint_url = get_endpoint_from_catalog(body['access']['serviceCatalog'], "CDN", @hp_avl_zone)
end
return {
@ -180,19 +198,31 @@ module Fog
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
raise "Unable to parse service catalog." unless service_catalog
service_item = service_catalog.detect do |s|
# 'Name' is unique instead of 'Type'
s["name"] == service_type
end
if service_item and service_item['endpoints']
endpoint = service_item['endpoints'].detect do |ep|
ep['region'] == avl_zone
end
endpoint_url = endpoint['publicURL'] if endpoint
raise "Unable to retrieve endpoint service url for availability zone '#{avl_zone}' from service catalog. " if endpoint_url.nil?
return endpoint_url
end
end
def self.set_user_agent_header(conn_opts, base_str, client_str)
if client_str
user_agent = {'User-Agent' => base_str + " (#{client_str})"}
else
raise "Unable to parse service catalog."
user_agent = {'User-Agent' => base_str}
end
if conn_opts[:headers]
conn_opts[:headers] = user_agent.merge!(conn_opts[:headers])
else
conn_opts[:headers] = user_agent
end
end

113
lib/fog/hp/CHANGELOG.hp Normal file
Просмотреть файл

@ -0,0 +1,113 @@
0.0.19 18/01/2013
=================
- update Block Storage namespace to be Fog::HP::BlockStorage
- merge with upstream fog v1.8.0
- deprecate hp_account_id to use hp_access_key instead
0.0.18 12/04/2012
=================
- add support for controlled access via cross-tenant ACLs
- add support for creating bootable volumes
- add support for creating persistent server instances using bootable volumes
0.0.17 10/16/2012
=================
- add support for generating temporary urls
- add support for retrieving encrypted password for Windows instances
- add support for creating Windows instances
0.0.16 08/15/2012
=================
- add support for User-Agent string in header
- add support for Snapshots API to BlockStorage provider
- add support for Volumes API to BlockStorage provider
- add BlockStorage service to HP provider
- upgrade to excon 0.14.0 to take advantage of instrumentation
- add a head method for the directories collection
- update image model
- update put_object and get_object to accept blocks
0.0.15 06/08/2012
=================
- add metadata attribute in server and image models to manage metadata
- add metadata model and request layer functionality with mocking support
- add tests for metadata
- upgrade to excon 0.13.0 to take advantage of ssl passthru functionality
- add security_groups attribute to the server model
- add support for future availability zones for all HP services
- change hp_avl_zone to be a required parameter for all HP services
- add support for console output in compute service
- add helper method for cdn public ssl url
- add tests for storage, compute and cdn services
- improve quality of mocks to match real implementation
0.0.14 02/23/2012
=================
- minor fix for public ip address
- minor fix for exceptions raised by CDN service
- add keypair get/set methods to server model
0.0.13 02/09/2012
=================
- provide access to availability zones for compute
- minor fix for CS authentication uri
- update inline documentation
- update README_HP with copyright message
0.0.12 02/02/2012
=================
- integrate CS authentication
- refactor HP provider to work with legacy v1 authentication as well
- integrate CDN to work with Storage provider
- add additional attributes for CDN provider
- remove bits and add cores as alias to vcpus in flavor model
- update inline documentation
- update README_HP with copyright message
0.0.11 01/09/2012
=================
- add ability to customize various connection timeouts options
- add CDN service capabilities
- integrate the CDN service with the Storage service
- add a new CDN Uri option to Storage service
- incorporate Diablo 4 API changes
- update image, server and flavor models
- update create_image and create_server calls
- add rebuild_server and change_password_server calls
- new extensions APIs
- add keypair model and request layer with mocking support
- add security group model and request layer with mocking support
- add security group rule model and request layer with mocking support
- add address model and request layer with mocking support
- update server model with address management methods
- update server creation to use keypairs, security groups and other options
- update inline documentation
0.0.10 10/18/2011
=================
- merge with upstream fog v1.0.0
0.0.9 09/21/2011
================
- minor bug fixes
- add support for special char. including '?' in container and object names
- fix public_url for special char. in container and object names
0.0.8 08/29/2011
================
- add README_HP.rdoc
- add CHANGELOG.hp
- remove resize_server, confirm_resized_server and revert_resized_server from HP Cloud Compute
0.0.7 08/10/2011
================
- minor fixes
- added acl support to directory
- added public? method to directory model
- added mock support for HP Cloud Object Storage
0.0.6 07/26/2011
================
- initial release with name change to 'hpfog'
- HP provider for HP Cloud Object Storage
- HP provider for HP Cloud Compute

Просмотреть файл

@ -29,11 +29,14 @@ If you should ever need to remove the library:
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]
* {HP Cloud Fog library - Object Storage Examples}[https://docs.hpcloud.com/bindings/fog/object-storage]
* {HP Cloud Fog library - Compute Examples}[https://docs.hpcloud.com/bindings/fog/compute]
* {HP Cloud Fog library - CDN Examples}[https://docs.hpcloud.com/bindings/fog/cdn]
* {HP Cloud Fog library - Block Storage Examples}[https://docs.hpcloud.com/bindings/fog/block-storage]
Having trouble? Get help over at the {Forums}[https://community.hpcloud.com/forum] or
at the {Knowledge Base}[https://community.hpcloud.com/knowledge-base] areas.
Having trouble? {Get help over at the Forums}[https://connect.hpcloud.com]
== Notice
@ -56,5 +59,3 @@ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
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.

169
lib/fog/hp/block_storage.rb Normal file
Просмотреть файл

@ -0,0 +1,169 @@
require 'fog/hp'
module Fog
module HP
class BlockStorage < Fog::Service
requires :hp_secret_key, :hp_tenant_id, :hp_avl_zone
recognizes :hp_auth_uri
recognizes :persistent, :connection_options
recognizes :hp_use_upass_auth_style, :hp_auth_version, :user_agent
recognizes :hp_access_key, :hp_account_id # :hp_account_id is deprecated use hp_access_key instead
secrets :hp_secret_key
model_path 'fog/hp/models/block_storage'
model :volume
collection :volumes
collection :bootable_volumes
model :snapshot
collection :snapshots
request_path 'fog/hp/requests/block_storage'
request :create_volume
request :delete_volume
request :get_bootable_volume_details
request :get_volume_details
request :list_bootable_volumes
request :list_volumes
request :create_snapshot
request :delete_snapshot
request :get_snapshot_details
request :list_snapshots
module Utils
def compute
@compute ||= Fog::Compute.new(
:provider => 'HP',
:hp_access_key => @hp_access_key,
:hp_secret_key => @hp_secret_key,
:hp_auth_uri => @hp_auth_uri,
:hp_tenant_id => @hp_tenant_id,
:hp_avl_zone => @hp_avl_zone,
:connection_options => @connection_options
)
end
end
class Mock
include Utils
def self.data
@data ||= Hash.new do |hash, key|
hash[key] = {
:volumes => {},
:snapshots => {}
}
end
end
def self.reset
@data = nil
end
def initialize(options={})
# deprecate hp_account_id
if options[:hp_account_id]
Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
@hp_access_key = options.delete(:hp_account_id)
end
@hp_access_key = options[:hp_access_key]
unless @hp_access_key
raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
end
end
def data
self.class.data[@hp_access_key]
end
def reset_data
self.class.data.delete(@hp_access_key)
end
end
class Real
include Utils
def initialize(options={})
# deprecate hp_account_id
if options[:hp_account_id]
Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
options[:hp_access_key] = options.delete(:hp_account_id)
end
@hp_access_key = options[:hp_access_key]
unless @hp_access_key
raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
end
@hp_secret_key = options[:hp_secret_key]
@hp_auth_uri = options[:hp_auth_uri]
@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 name for object storage to the authentication call
options[:hp_service_type] = "Block Storage"
@hp_tenant_id = options[:hp_tenant_id]
@hp_avl_zone = options[:hp_avl_zone]
### 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 block storage endpoint
@hp_block_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 block storage endpoint
@hp_block_uri = options[:hp_auth_uri]
end
@auth_token = credentials[:auth_token]
@persistent = options[:persistent] || false
uri = URI.parse(@hp_block_uri)
@host = uri.host
@path = uri.path
@port = uri.port
@scheme = uri.scheme
@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::HP::BlockStorage::NotFound.slurp(error)
else
error
end
end
if !response.body.empty? && parse_json && response.headers['Content-Type'] =~ %r{application/json}
response.body = Fog::JSON.decode(response.body)
end
response
end
end
end
end
end

Просмотреть файл

@ -5,8 +5,11 @@ 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
requires :hp_secret_key, :hp_tenant_id, :hp_avl_zone
recognizes :hp_auth_uri, :hp_cdn_uri
recognizes :hp_use_upass_auth_style, :hp_auth_version, :user_agent
recognizes :persistent, :connection_options
recognizes :hp_access_key, :hp_account_id # :hp_account_id is deprecated use hp_access_key instead
secrets :hp_secret_key
@ -39,15 +42,23 @@ module Fog
end
def initialize(options={})
@hp_account_id = options[:hp_account_id]
# deprecate hp_account_id
if options[:hp_account_id]
Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
@hp_access_key = options.delete(:hp_account_id)
end
@hp_access_key = options[:hp_access_key]
unless @hp_access_key
raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
end
end
def data
self.class.data[@hp_account_id]
self.class.data[@hp_access_key]
end
def reset_data
self.class.data.delete(@hp_account_id)
self.class.data.delete(@hp_access_key)
end
end
@ -56,11 +67,22 @@ module Fog
include Utils
def initialize(options={})
# deprecate hp_account_id
if options[:hp_account_id]
Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
options[:hp_access_key] = options.delete(:hp_account_id)
end
@hp_access_key = options[:hp_access_key]
unless @hp_access_key
raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
end
@hp_secret_key = options[:hp_secret_key]
@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"
### Pass the service name for object storage to the authentication call
options[:hp_service_type] = "CDN"
@hp_tenant_id = options[:hp_tenant_id]
### Make the authentication call
if (auth_version == :v2)

Просмотреть файл

@ -5,8 +5,11 @@ 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
requires :hp_secret_key, :hp_tenant_id, :hp_avl_zone
recognizes :hp_auth_uri
recognizes :hp_use_upass_auth_style, :hp_auth_version, :user_agent
recognizes :persistent, :connection_options
recognizes :hp_access_key, :hp_account_id # :hp_account_id is deprecated use hp_access_key instead
secrets :hp_secret_key
@ -19,6 +22,8 @@ module Fog
collection :images
model :key_pair
collection :key_pairs
model :meta
collection :metadata
model :security_group
collection :security_groups
model :server
@ -27,6 +32,7 @@ module Fog
request_path 'fog/hp/requests/compute'
request :allocate_address
request :associate_address
request :attach_volume
request :change_password_server
#request :confirm_resized_server
request :create_image
@ -34,15 +40,21 @@ module Fog
request :create_security_group
request :create_security_group_rule
request :create_server
request :create_persistent_server
request :delete_image
request :delete_key_pair
request :delete_meta
request :delete_security_group
request :delete_security_group_rule
request :delete_server
request :detach_volume
request :disassociate_address
request :get_address
request :get_console_output
request :get_flavor_details
request :get_image_details
request :get_meta
request :get_windows_password
request :get_security_group
request :get_server_details
request :list_addresses
@ -51,10 +63,12 @@ module Fog
request :list_images
request :list_images_detail
request :list_key_pairs
request :list_metadata
request :list_security_groups
request :list_server_addresses
request :list_server_private_addresses
request :list_server_public_addresses
request :list_server_volumes
request :list_servers
request :list_servers_detail
request :reboot_server
@ -63,9 +77,55 @@ module Fog
#request :resize_server
#request :revert_resized_server
request :server_action
request :set_metadata
request :update_meta
request :update_metadata
request :update_server
module Utils
# extract windows password from log
def extract_password_from_log(log_text)
encrypted_text = ""
section = []
return if log_text.nil?
log_text.each_line do |line|
case line
when /^-----BEGIN (\w+)/
section.push $1
next
when /^-----END (\w+)/
section.pop
next
end
case section
when ["BASE64"]
encrypted_text << line
end
end
# return the encrypted portion only
encrypted_text
end
def encrypt_using_public_key(text, public_key_data)
return if (text.nil? || public_key_data.nil?)
public_key = OpenSSL::PKey::RSA.new(public_key_data)
encrypted_text = public_key.public_encrypt(text).strip
Base64.encode64(encrypted_text)
end
def decrypt_using_private_key(encrypted_text, private_key_data)
return if (encrypted_text.nil? || private_key_data.nil?)
private_key = OpenSSL::PKey::RSA.new(private_key_data)
from_base64 = Base64.decode64(encrypted_text)
private_key.private_decrypt(from_base64).strip
end
end
class Mock
include Utils
def self.data
@data ||= Hash.new do |hash, key|
@ -91,30 +151,46 @@ module Fog
end
def initialize(options={})
@hp_account_id = options[:hp_account_id]
# deprecate hp_account_id
if options[:hp_account_id]
Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
@hp_access_key = options.delete(:hp_account_id)
end
@hp_access_key = options[:hp_access_key]
unless @hp_access_key
raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
end
end
def data
self.class.data[@hp_account_id]
self.class.data[@hp_access_key]
end
def reset_data
self.class.data.delete(@hp_account_id)
self.class.data.delete(@hp_access_key)
end
end
class Real
include Utils
def initialize(options={})
# deprecate hp_account_id
if options[:hp_account_id]
Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
options[:hp_access_key] = options.delete(:hp_account_id)
end
@hp_access_key = options[:hp_access_key]
unless @hp_access_key
raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
end
@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"
### Pass the service name for compute via the options hash
options[:hp_service_type] = "Compute"
@hp_tenant_id = options[:hp_tenant_id]
### Make the authentication call
@ -133,12 +209,11 @@ module Fog
@auth_token = credentials[:auth_token]
uri = URI.parse(@hp_compute_uri)
@host = @hp_servicenet == true ? "snet-#{uri.host}" : uri.host
@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
@ -166,12 +241,8 @@ module Fog
error
end
end
unless response.body.empty?
begin
response.body = Fog::JSON.decode(response.body)
rescue MultiJson::DecodeError => error
response.body #### the body is not in JSON format so just return it as it is
end
if !response.body.empty? && parse_json && response.headers['Content-Type'] =~ %r{application/json}
response.body = Fog::JSON.decode(response.body)
end
response
end

Просмотреть файл

@ -0,0 +1,28 @@
require 'fog/core/collection'
require 'fog/hp/models/block_storage/volume'
module Fog
module HP
class BlockStorage
class BootableVolumes < Fog::Collection
model Fog::HP::BlockStorage::Volume
def all
data = service.list_bootable_volumes.body['volumes']
load(data)
end
def get(volume_id)
volume = service.get_bootable_volume_details(volume_id).body['volume']
new(volume)
rescue Fog::HP::BlockStorage::NotFound
nil
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,56 @@
require 'fog/core/model'
module Fog
module HP
class BlockStorage
class Snapshot < Fog::Model
identity :id
attribute :name, :aliases => 'displayName'
attribute :description, :aliases => 'displayDescription'
attribute :size
attribute :status
attribute :created_at, :aliases => 'createdAt'
attribute :volume_id, :aliases => 'volumeId'
#attribute :metadata
def initialize(attributes = {})
# assign these attributes first to prevent race condition with persisted?
self.force = attributes.delete(:force) # force snapshotting of attached volumes
super
end
def destroy
requires :id
service.delete_snapshot(id)
true
end
def force=(new_force)
@force = new_force
end
def ready?
self.status == 'available'
end
def save
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted?
requires :name, :volume_id
options = {
#'metadata' => metadata, # TODO: Add metadata when snapshots support it
'force' => @force
}
options = options.reject {|key, value| value.nil?}
data = service.create_snapshot(name, description, volume_id, options)
merge_attributes(data.body['snapshot'])
true
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,29 @@
require 'fog/core/collection'
require 'fog/hp/models/block_storage/snapshot'
module Fog
module HP
class BlockStorage
class Snapshots < Fog::Collection
model Fog::HP::BlockStorage::Snapshot
def all
data = service.list_snapshots.body['snapshots']
load(data)
end
def get(snapshot_id)
if snapshot = service.get_snapshot_details(snapshot_id).body['snapshot']
new(snapshot)
end
rescue Fog::HP::BlockStorage::NotFound
nil
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,102 @@
require 'fog/core/model'
module Fog
module HP
class BlockStorage
class Volume < Fog::Model
identity :id
attribute :name, :aliases => 'displayName'
attribute :description, :aliases => 'displayDescription'
attribute :size
attribute :status
attribute :type, :aliases => 'volumeType'
attribute :created_at, :aliases => 'createdAt'
attribute :availability_zone, :aliases => 'availabilityZone'
attribute :snapshot_id, :aliases => 'snapshotId'
attribute :source_image_id, :aliases => 'sourceImageRef' # only for bootable volumes
attribute :attachments
attribute :metadata
attr_reader :server_id
attr_reader :device
def initialize(attributes = {})
# assign these attributes first to prevent race condition with new_record?
self.image_id = attributes.delete(:image_id)
super
end
def device
attachments[0]['device'] if has_attachments?
end
def server_id
attachments[0]['serverId'] if has_attachments?
end
# used for creating bootable volumes
def image_id=(new_image_id)
@image_id = new_image_id
end
# a volume can be attached to only one server at a time
def has_attachments?
!(attachments.nil? || attachments.empty? || attachments[0].empty?)
end
def in_use?
self.status == 'in-use'
end
def ready?
self.status == 'available'
end
# volume can be attached to only one server at a time
def attach(new_server_id, device)
requires :id
unless in_use?
data = service.compute.attach_volume(new_server_id, id, device)
merge_attributes(:attachments => attachments << data.body['volumeAttachment'])
true
else
false
end
end
def detach
requires :id
if has_attachments?
service.compute.detach_volume(server_id, id)
end
true
end
def destroy
requires :id
service.delete_volume(id)
true
end
def save
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted?
requires :name, :size
options = {
'metadata' => metadata,
'snapshot_id' => snapshot_id,
'imageRef' => @image_id
}
options = options.reject {|key, value| value.nil?}
data = service.create_volume(name, description, size, options)
merge_attributes(data.body['volume'])
true
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,28 @@
require 'fog/core/collection'
require 'fog/hp/models/block_storage/volume'
module Fog
module HP
class BlockStorage
class Volumes < Fog::Collection
model Fog::HP::BlockStorage::Volume
def all
data = service.list_volumes.body['volumes']
load(data)
end
def get(volume_id)
volume = service.get_volume_details(volume_id).body['volume']
new(volume)
rescue Fog::HP::BlockStorage::NotFound
nil
end
end
end
end
end

Просмотреть файл

@ -20,7 +20,6 @@ module Fog
def destroy
requires :id
service.release_address(id)
true
end

Просмотреть файл

@ -1,4 +1,5 @@
require 'fog/core/model'
require 'fog/openstack/models/compute/metadata'
module Fog
module Compute
@ -13,15 +14,53 @@ module Fog
attribute :updated_at, :aliases => 'updated'
attribute :progress
attribute :status
attribute :minDisk, :aliases => 'min_disk'
attribute :minRam, :aliases => 'min_ram'
attribute :server, :aliases => 'server'
attribute :server
attribute :metadata
attribute :links
# these values are extracted from metadata
attr_reader :min_disk
attr_reader :min_ram
attr_reader :image_type
attr_reader :architecture
def metadata
@metadata ||= begin
Fog::Compute::HP::Metadata.new({
:service => service,
:parent => self
})
end
end
def metadata=(new_metadata={})
metas = []
new_metadata.each_pair {|k,v| metas << {"key" => k, "value" => v} }
metadata.load(metas)
end
def min_disk
m = metadata.get("min_disk")
m.value unless m.nil?
end
def min_ram
m = metadata.get("min_ram")
m.value unless m.nil?
end
def image_type
m = metadata.get("image_type")
m.value unless m.nil?
end
def architecture
m = metadata.get("architecture")
m.value unless m.nil?
end
def destroy
requires :id
service.delete_image(id)
true
end

Просмотреть файл

@ -9,14 +9,9 @@ module Fog
model Fog::Compute::HP::Image
attribute :server
def all
data = service.list_images_detail.body['images']
load(data)
if server
self.replace(self.select {|image| image.server.id == server.id})
end
self
end

Просмотреть файл

@ -13,18 +13,14 @@ module Fog
attribute :private_key
attribute :user_id
attr_accessor :public_key
def destroy
requires :name
service.delete_key_pair(name)
true
end
def save
requires :name
data = if public_key
service.create_key_pair(name, public_key).body['keypair']
else
@ -36,7 +32,6 @@ module Fog
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|

Просмотреть файл

@ -0,0 +1,29 @@
require 'fog/core/model'
require 'fog/hp/models/meta_parent'
module Fog
module Compute
class HP
class Meta < Fog::Model
include Fog::Compute::HP::MetaParent
identity :key
attribute :value
def destroy
requires :identity
service.delete_meta(collection_name, @parent.id, key)
true
end
def save
requires :identity, :value
service.update_meta(collection_name, @parent.id, key, value)
true
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,79 @@
require 'fog/core/collection'
require 'fog/hp/models/meta_parent'
require 'fog/hp/models/compute/meta'
require 'fog/hp/models/compute/image'
require 'fog/hp/models/compute/server'
module Fog
module Compute
class HP
class Metadata < Fog::Collection
model Fog::Compute::HP::Meta
include Fog::Compute::HP::MetaParent
def all
requires :parent
if @parent.id
metadata = service.list_metadata(collection_name, @parent.id).body['metadata']
metas = []
metadata.each_pair {|k,v| metas << {"key" => k, "value" => v} }
load(metas)
end
end
def destroy(key)
requires :parent
service.delete_meta(collection_name, @parent.id, key)
rescue Fog::Compute::HP::NotFound
nil
end
def get(key)
requires :parent
data = service.get_meta(collection_name, @parent.id, key).body["meta"]
metas = []
data.each_pair {|k,v| metas << {"key" => k, "value" => v} }
new(metas[0])
rescue Fog::Compute::HP::NotFound
nil
end
def new(attributes = {})
requires :parent
super({ :parent => @parent }.merge!(attributes))
end
def set(data=nil)
requires :parent
service.set_metadata(collection_name, @parent.id, meta_hash(data))
end
def update(data=nil)
requires :parent
service.update_metadata(collection_name, @parent.id, meta_hash(data))
end
private
def meta_hash(data=nil)
if data.nil?
data={}
self.each do |meta|
if meta.is_a?(Fog::Compute::HP::Meta) then
data.store(meta.key, meta.value)
else
data.store(meta["key"], meta["value"])
end
end
end
data
end
end
end
end
end

Просмотреть файл

@ -1,4 +1,5 @@
require 'fog/compute/models/server'
require 'fog/hp/models/compute/metadata'
module Fog
module Compute
@ -24,6 +25,8 @@ module Fog
attribute :tenant_id
attribute :user_id
attribute :key_name
attribute :security_groups
attribute :config_drive
# these are implemented as methods
attribute :image_id
attribute :flavor_id
@ -31,27 +34,44 @@ module Fog
attribute :public_ip_address
attr_reader :password
attr_writer :image_id, :flavor_id
attr_writer :private_key, :private_key_path
attr_writer :public_key, :public_key_path
attr_writer :username, :image_id, :flavor_id, :network_name
def initialize(attributes = {})
# assign these attributes first to prevent race condition with persisted?
self.security_groups = attributes.delete(:security_groups)
# assign these attributes first to prevent race condition with new_record?
self.min_count = attributes.delete(:min_count)
self.max_count = attributes.delete(:max_count)
self.block_device_mapping = attributes.delete(:block_device_mapping)
super
end
def console_output(num_lines)
requires :id
service.get_console_output(id, num_lines)
end
def metadata
@metadata ||= begin
Fog::Compute::HP::Metadata.new({
:service => service,
:parent => self
})
end
end
def metadata=(new_metadata={})
metas = []
new_metadata.each_pair {|k,v| metas << {"key" => k, "value" => v} }
metadata.load(metas)
end
def destroy
requires :id
service.delete_server(id)
true
end
def images
requires :id
service.images(:server => self)
end
def key_pair
requires :key_name
@ -62,16 +82,29 @@ module Fog
self.key_name = new_keypair && new_keypair.name
end
def network_name
@network_name ||= "private"
end
def private_ip_address
addr = addresses.nil? ? nil : addresses.fetch('private', []).first
addr = addresses.nil? ? nil : addresses.fetch(network_name, []).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', [])
addr = addresses.fetch(network_name, [])
# if we have more than 1 address, then the return the second address which is public
if addr.count > 1
addr[1]["addr"]
@ -83,6 +116,15 @@ module Fog
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
@ -107,12 +149,8 @@ module Fog
@max_count = new_max_count
end
def security_groups=(new_security_groups)
@security_groups = new_security_groups
end
def security_groups
@security_groups
def block_device_mapping=(new_block_device_mapping)
@block_device_mapping = new_block_device_mapping
end
def ready?
@ -125,6 +163,11 @@ module Fog
true
end
def windows_password()
requires :id
service.get_windows_password(id)
end
def reboot(type = 'SOFT')
requires :id
service.reboot_server(id, type)
@ -160,21 +203,38 @@ module Fog
service.create_image(id, name, metadata)
end
def volume_attachments
requires :id
if vols = service.list_server_volumes(id).body
vols["volumeAttachments"]
end
end
def save
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted?
requires :flavor_id, :image_id, :name
requires :flavor_id, :name
meta_hash = {}
metadata.each { |meta| meta_hash.store(meta.key, meta.value) }
options = {
'metadata' => metadata,
'metadata' => meta_hash,
'personality' => personality,
'accessIPv4' => accessIPv4,
'accessIPv6' => accessIPv6,
'min_count' => @min_count,
'max_count' => @max_count,
'key_name' => key_name,
'security_groups' => @security_groups
'security_groups' => security_groups,
'config_drive' => config_drive
}
options = options.reject {|key, value| value.nil?}
data = service.create_server(name, flavor_id, image_id, options)
# either create a regular server or a persistent server based on input
if image_id
# create a regular server using the image
data = service.create_server(name, flavor_id, image_id, options)
elsif image_id.nil? && !@block_device_mapping.nil? && !@block_device_mapping.empty?
# create a persistent server using the bootable volume in the block_device_mapping
data = service.create_persistent_server(name, flavor_id, @block_device_mapping, options)
end
merge_attributes(data.body['server'])
true
end
@ -193,6 +253,10 @@ module Fog
retry
end
def username
@username ||= 'root'
end
private
def adminPass=(new_admin_pass)

Просмотреть файл

@ -0,0 +1,33 @@
module Fog
module Compute
class HP
module MetaParent
def parent
@parent
end
def parent=(new_parent)
@parent = new_parent
end
def collection_name
if @parent.class == Fog::Compute::HP::Image
return "images"
elsif @parent.class == Fog::Compute::HP::Server
return "servers"
else
raise "Metadata is not supported for this model type."
end
end
def metas_to_hash(metas)
hash = {}
metas.each { |meta| hash.store(meta.key, meta.value) }
hash
end
end
end
end
end

Просмотреть файл

@ -14,10 +14,39 @@ module Fog
load(data)
end
def head(key, options = {})
data = service.head_container(key)
directory = create_directory(key, data)
# set the cdn state for the directory
directory.cdn_enabled?
directory
rescue Fog::Storage::HP::NotFound
nil
end
def get(key, options = {})
data = service.get_container(key, options)
directory = create_directory(key, data)
# set the files for the directory
directory.files.merge_attributes(options)
directory.files.instance_variable_set(:@loaded, true)
data.body.each do |file|
directory.files << directory.files.new(file)
end
# set the cdn state for the directory
directory.cdn_enabled?
directory
rescue Fog::Storage::HP::NotFound
nil
end
private
def create_directory(key, data)
read_header = nil
write_header = nil
data = service.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)
@ -31,16 +60,12 @@ module Fog
end
# set the acl on the directory based on the headers
if !(read_header.nil? && write_header.nil?)
directory.acl = service.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)
read_acl, write_acl = service.header_to_perm_acl(read_header, write_header)
# do not want to expose the read_acl and write_acl as writable attributes
directory.instance_variable_set(:@read_acl, read_acl)
directory.instance_variable_set(:@write_acl, write_acl)
end
directory
rescue Fog::Storage::HP::NotFound
nil
end
end

Просмотреть файл

@ -12,15 +12,86 @@ module Fog
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"
def initialize(attributes = {})
@read_acl = []
@write_acl = []
super
end
def read_acl
@read_acl || []
end
def write_acl
@write_acl || []
end
def can_read?(user)
return false if @read_acl.nil?
list_users_with_read.include?(user)
end
def can_write?(user)
return false if @write_acl.nil?
list_users_with_write.include?(user)
end
def can_read_write?(user)
can_read?(user) && can_write?(user)
end
def list_users_with_read
users = []
users = @read_acl.map {|acl| acl.split(':')[1]} unless @read_acl.nil?
return users
end
def list_users_with_write
users = []
users = @write_acl.map {|acl| acl.split(':')[1]} unless @write_acl.nil?
return users
end
def grant(perm, users=nil)
# support passing in a list of users in a comma-separated list or as an Array
if users.is_a?(String)
user_list = users.split(',')
else
user_list = users
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(', ')}]")
r_acl, w_acl = service.perm_to_acl(perm, user_list)
unless r_acl.nil? || r_acl.empty?
@read_acl = [] if @read_acl.nil?
@read_acl = @read_acl + r_acl
@read_acl.uniq!
end
@acl = new_acl
unless w_acl.nil? || w_acl.empty?
@write_acl = [] if @write_acl.nil?
@write_acl = @write_acl + w_acl
@write_acl.uniq!
end
true
end
def revoke(perm, users=nil)
# support passing in a list of users in a comma-separated list or as an Array
if users.is_a?(String)
user_list = users.split(',')
else
user_list = users
end
r_acl, w_acl = service.perm_to_acl(perm, user_list)
unless r_acl.nil? || r_acl.empty?
@read_acl = [] if @read_acl.nil?
@read_acl = @read_acl - r_acl
@read_acl.uniq!
end
unless w_acl.nil? || w_acl.empty?
@write_acl = [] if @write_acl.nil?
@write_acl = @write_acl - w_acl
@write_acl.uniq!
end
true
end
def destroy
@ -50,18 +121,19 @@ module Fog
def public=(new_public)
if new_public
@acl = 'public-read'
self.grant("pr")
else
@acl = 'private'
self.revoke("pr")
end
@public = new_public
end
def public?
if @acl.nil?
false
@read_acl = [] if @read_acl.nil?
if @read_acl.include?(".r:*")
true
else
@acl == 'public-read'
false
end
end
@ -70,7 +142,7 @@ module Fog
@public_url ||= begin
begin response = service.head_container(key)
# escape the key to cover for special char. in container names
url = "#{service.url}/#{Fog::HP.escape(key)}"
url = service.public_url(key)
rescue Fog::Storage::HP::NotFound => err
nil
end
@ -96,7 +168,8 @@ module Fog
else
@cdn_enable = false
end
rescue Fog::CDN::HP::NotFound => err
# If CDN endpoint is unreachable, a SocketError is raised
rescue Fog::CDN::HP::NotFound, Excon::Errors::SocketError
@cdn_enable = false
end
else
@ -110,24 +183,32 @@ module Fog
# return the CDN public url from the appropriate uri from the header
begin response = service.cdn.head_container(key)
if response.headers['X-Cdn-Enabled'] == 'True'
if service.hp_cdn_ssl == true
response.headers.fetch('X-Cdn-Ssl-Uri', nil)
else
response.headers.fetch('X-Cdn-Uri', nil)
end
response.headers.fetch('X-Cdn-Uri', nil)
end
rescue Fog::CDN::HP::NotFound => err
rescue Fog::CDN::HP::NotFound
nil
end
end
end
def save
def cdn_public_ssl_url
requires :key
options = {}
if @acl
options.merge!(service.acl_to_header(@acl))
@cdn_public_ssl_url ||= begin
# return the CDN public ssl url from the appropriate uri from the header
begin response = service.cdn.head_container(key)
if response.headers['X-Cdn-Enabled'] == 'True'
response.headers.fetch('X-Cdn-Ssl-Uri', nil)
end
rescue Fog::CDN::HP::NotFound
nil
end
end
end
def save(options = {})
requires :key
# write out the acls into the headers before save
options.merge!(service.perm_acl_to_header(@read_acl, @write_acl))
service.put_container(key, options)
# Added an extra check to see if CDN is enabled for the container
if (!service.cdn.nil? && service.cdn.enabled?)
@ -137,16 +218,20 @@ module Fog
begin response = service.cdn.head_container(key)
### Deleting a container from CDN is much more expensive than flipping the bit to disable it
service.cdn.post_container(key, {'X-CDN-Enabled' => 'True'})
rescue Fog::CDN::HP::NotFound => err
rescue Fog::CDN::HP::NotFound
service.cdn.put_container(key)
rescue Excon::Errors::SocketError
# means that the CDN endpoint is unreachable
end
else
# check to make sure that the container exists. If yes, cdn disable it.
begin response = service.cdn.head_container(key)
### Deleting a container from CDN is much more expensive than flipping the bit to disable it
service.cdn.post_container(key, {'X-CDN-Enabled' => 'False'})
rescue Fog::CDN::HP::NotFound => err
rescue Fog::CDN::HP::NotFound
# just continue, as container is not cdn-enabled.
rescue Excon::Errors::SocketError
# means that the CDN endpoint is unreachable
end
end
end

Просмотреть файл

@ -65,6 +65,16 @@ module Fog
self.collection.get_cdn_url(self.key)
end
def cdn_public_ssl_url
requires :key
self.collection.get_cdn_ssl_url(self.key)
end
def temp_signed_url(expires_secs, method)
requires :directory, :key
service.get_object_temp_url(directory.key, key, expires_secs, method)
end
def save(options = {})
requires :body, :directory, :key
options['Content-Type'] = content_type if content_type

Просмотреть файл

@ -80,6 +80,14 @@ module Fog
end
end
def get_cdn_ssl_url(key)
requires :directory
if self.directory.cdn_public_ssl_url
# escape the key to cover for special char. in object names
"#{self.directory.cdn_public_ssl_url}/#{Fog::HP.escape(key)}"
end
end
def head(key, options = {})
requires :directory
data = service.head_object(directory.key, key)

Просмотреть файл

@ -0,0 +1,55 @@
require 'fog/core/collection'
require 'fog/hp/models/storage/shared_directory'
module Fog
module Storage
class HP
class SharedDirectories < Fog::Collection
model Fog::Storage::HP::SharedDirectory
def all
nil
end
def head(url)
data = service.head_shared_container(url)
shared_directory = new(:url => url)
for key, value in data.headers
if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key)
shared_directory.merge_attributes(key => value)
end
end
shared_directory
# throws exception Fog::HP::Errors::Forbidden if insufficient access
rescue Fog::Storage::HP::NotFound
nil
end
def get(url)
data = service.get_shared_container(url)
shared_directory = new(:url => url)
for key, value in data.headers
if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key)
shared_directory.merge_attributes(key => value)
end
end
# set the files for the directory
shared_directory.files.instance_variable_set(:@loaded, true)
data.body.each do |file|
shared_directory.files << shared_directory.files.new(file)
end
shared_directory
# throws exception Fog::HP::Errors::Forbidden if insufficient access
rescue Fog::Storage::HP::NotFound
nil
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,39 @@
require 'fog/core/model'
require 'fog/hp/models/storage/shared_files'
module Fog
module Storage
class HP
class SharedDirectory < Fog::Model
identity :url
attribute :bytes, :aliases => 'X-Container-Bytes-Used'
attribute :count, :aliases => 'X-Container-Object-Count'
def files
@files ||= begin
Fog::Storage::HP::SharedFiles.new(
:shared_directory => self,
:service => service
)
end
end
def destroy
requires :url
# delete is not allowed
false
end
def save(options = {})
requires :url
# put is not allowed
false
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,67 @@
require 'fog/core/model'
module Fog
module Storage
class HP
class SharedFile < Fog::Model
identity :key, :aliases => 'name'
attribute :url
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 url
"#{self.collection.shared_directory.url}/#{key}"
end
def body
attributes[:body] ||= if last_modified
collection.get(identity).body
else
''
end
end
def body=(new_body)
attributes[:body] = new_body
end
def destroy
requires :shared_directory, :key
service.delete_shared_object(self.url)
true
# throws exception Fog::HP::Errors::Forbidden if insufficient access
rescue Fog::Storage::HP::NotFound
false
end
def shared_directory
@shared_directory
end
def save(options = {})
requires :shared_directory, :key
options['Content-Type'] = content_type if content_type
data = service.put_shared_object(shared_directory.url, key, body, options)
merge_attributes(data.headers)
self.content_length = Fog::Storage.get_body_size(body)
true
# throws exception Fog::HP::Errors::Forbidden if insufficient access
rescue Fog::Storage::HP::NotFound
false
end
private
def shared_directory=(new_shared_directory)
@shared_directory = new_shared_directory
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,64 @@
require 'fog/core/collection'
require 'fog/hp/models/storage/shared_file'
module Fog
module Storage
class HP
class SharedFiles < Fog::Collection
attribute :shared_directory
model Fog::Storage::HP::SharedFile
def all
requires :shared_directory
parent = shared_directory.collection.get(shared_directory.url)
if parent
load(parent.files.map {|file| file.attributes})
else
nil
end
# throws exception Fog::HP::Errors::Forbidden if insufficient access
rescue Fog::Storage::HP::NotFound
nil
end
def get(key, &block)
requires :shared_directory
shared_object_url = "#{shared_directory.url}/#{key}"
data = service.get_shared_object(shared_object_url, &block)
file_data = data.headers.merge({
:body => data.body,
:key => key
})
new(file_data)
# throws exception Fog::HP::Errors::Forbidden if insufficient access
rescue Fog::Storage::HP::NotFound
nil
end
def head(key)
requires :shared_directory
shared_object_url = "#{shared_directory.url}/#{key}"
data = service.head_shared_object(shared_object_url)
file_data = data.headers.merge({
:body => '',
:key => key
})
new(file_data)
# throws exception Fog::HP::Errors::Forbidden if insufficient access
rescue Fog::Storage::HP::NotFound
nil
end
def new(attributes = {})
requires :shared_directory
super({ :shared_directory => shared_directory }.merge!(attributes))
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,76 @@
module Fog
module HP
class BlockStorage
class Real
# Create a new block storage snapshot
#
# ==== Parameters
# * name<~String> - Name of the snapshot
# * description<~String> - Description of the snapshot
# * volume_id<~Integer> - Id of the volume to create snapshot of
# * options<~Hash>:
# * 'force'<~Boolean> - Not implemented yet. True or False, to allow online snapshots (i.e. when volume is attached)
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * snapshot<~Hash>:
# * 'id'<~Integer>: - Id for the snapshot
# * 'displayName'<~String>: - Name of the snapshot
# * 'displayDescription'<~String>: - Description of the snapshot
# * 'size'<~Integer>: - Size in GB for the snapshot
# * 'status'<~String>: - Status of the snapshot i.e. "creating"
# * 'volumeId'<~Integer>: - Id of the volume from which the snapshot was created
# * 'createdAt'<~String>: - Timestamp in UTC when snapshot was created
def create_snapshot(name, description, volume_id, options={})
data = {
'snapshot' => {
'display_name' => name,
'display_description' => description,
'volume_id' => volume_id
}
}
l_options = ['force']
l_options.select{|o| options[o]}.each do |key|
data['snapshot'][key] = options[key]
end
request(
:body => Fog::JSON.encode(data),
:expects => 200,
:method => 'POST',
:path => "os-snapshots"
)
end
end
class Mock # :nodoc:all
def create_snapshot(name, description, volume_id, options={})
response = Excon::Response.new
if self.data[:volumes][volume_id]
response.status = 200
data = {
'id' => Fog::Mock.random_numbers(3).to_i,
'displayName' => name,
'displayDescription' => description,
'size' => self.data[:volumes][volume_id]['size'],
'status' => 'available',
'volumeId' => volume_id,
'createdAt' => Time.now.to_s
}
self.data[:snapshots][data['id']] = data
response.body = { 'snapshot' => data }
else
raise Fog::HP::BlockStorage::NotFound
end
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,87 @@
module Fog
module HP
class BlockStorage
class Real
# Create a new block storage volume
#
# ==== Parameters
# * name<~String> - Name of the volume
# * description<~String> - Description of the volume
# * size<~Integer> - Size of the volume (in GBs)
# * options<~Hash>:
# * 'snapshot_id'<~String> - Id of the volume snapshot to create the volume from. The request is invalid if both the snapshot_id and the imageRef parameters are specified and are not null.
# * 'imageRef'<~String> - Id of the image to create the volume from. This creates a bootable volume. The request is invalid if both the snapshot_id and the imageRef parameters are specified and are not null.
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * volume<~Hash>:
# * 'id'<~Integer> - Id for the volume
# * 'displayName'<~String> - Name of the volume
# * 'displayDescription'<~String> - Description of the volume
# * 'size'<~Integer> - Size in GB for the volume
# * 'status'<~String> - Status of the volume i.e. "creating"
# * 'volumeType'<~String> - Type of the volume
# * 'snapshotId'<~String> - Id of the snapshot, the volume was created from.
# * 'imageRef'<~String> - Id of the image, the volume was created from. A not null value means it is a bootable volume.
# * 'createdAt'<~String> - Timestamp in UTC when volume was created
# * 'availabilityZone'<~String> - Availability zone i.e. "nova"
# * attachments<~Array>: Array of hashes of attachments
# * metadata<~Hash>: Hash of metadata for the volume
def create_volume(name, description, size, options={})
data = {
'volume' => {
'display_name' => name,
'display_description' => description,
'size' => size
}
}
l_options = ['snapshot_id', 'imageRef', 'metadata']
l_options.select{|o| options[o]}.each do |key|
data['volume'][key] = options[key]
end
request(
:body => Fog::JSON.encode(data),
:expects => 200,
:method => 'POST',
:path => "os-volumes"
)
end
end
class Mock # :nodoc:all
def create_volume(name, description, size, options={})
if options['snapshotId'] && options['imageRef']
raise Fog::Errors::BadRequest.new("Snapshot and image cannot be specified together.")
else
response = Excon::Response.new
response.status = 200
data = {
'id' => Fog::Mock.random_numbers(3).to_i,
'displayName' => name,
'displayDescription' => description,
'size' => size,
'status' => 'available',
'snapshotId' => options['snapshot_id'] || "",
#'imageRef' => options['imageRef'] || "", # TODO: not implemented to preserve backward compatibility
'volumeType' => nil,
'availabilityZone' => 'nova',
'createdAt' => Time.now.to_s,
'metadata' => options['metadata'] || {},
'attachments' => [{}]
}
self.data[:volumes][data['id']] = data
response.body = { 'volume' => data }
response
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,38 @@
module Fog
module HP
class BlockStorage
class Real
# Delete an existing block storage snapshot
#
# ==== Parameters
# * snapshot_id<~Integer> - Id of the snapshot to delete
#
def delete_snapshot(snapshot_id)
response = request(
:expects => 202,
:method => 'DELETE',
:path => "os-snapshots/#{snapshot_id}"
)
response
end
end
class Mock # :nodoc:all
def delete_snapshot(snapshot_id)
response = Excon::Response.new
if self.data[:snapshots][snapshot_id]
self.data[:snapshots].delete(snapshot_id)
response.status = 202
else
raise Fog::HP::BlockStorage::NotFound
end
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,38 @@
module Fog
module HP
class BlockStorage
class Real
# Delete an existing block storage volume
#
# ==== Parameters
# * volume_id<~Integer> - Id of the volume to delete
#
def delete_volume(volume_id)
response = request(
:expects => 202,
:method => 'DELETE',
:path => "os-volumes/#{volume_id}"
)
response
end
end
class Mock # :nodoc:all
def delete_volume(volume_id)
response = Excon::Response.new
if self.data[:volumes][volume_id]
self.data[:volumes].delete(volume_id)
response.status = 202
else
raise Fog::HP::BlockStorage::NotFound
end
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,59 @@
module Fog
module HP
class BlockStorage
class Real
# Get details for existing block storage bootable volume
#
# ==== Parameters
# * volume_id<~Integer> - Id of the volume to get
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * volume<~Hash>:
# * 'id'<~Integer> - Id for the volume
# * 'displayName'<~String> - Name of the volume
# * 'displayDescription'<~String> - Description of the volume
# * 'size'<~Integer> - Size in GB for the volume
# * 'status'<~String> - Status of the volume i.e. "available"
# * 'volumeType'<~String> - Type of the volume
# * 'snapshotId'<~String> - Id of the volume snapshot
# * 'sourceImageRef'<~String> - Id of the volume snapshot
# * 'createdAt'<~String> - Timestamp in UTC when volume was created
# * 'availabilityZone'<~String> - Availability zone i.e. "nova"
# * attachments<~Array> Array of hashes of attachments
# * metadata<~Hash> Hash of metadata for the volume
def get_bootable_volume_details(volume_id)
response = request(
:expects => 200,
:method => 'GET',
:path => "hp-bootable-volumes/#{volume_id}"
)
response
end
end
class Mock # :nodoc:all
def get_bootable_volume_details(volume_id)
unless volume_id
raise ArgumentError.new('volume_id is required')
end
response = Excon::Response.new
if volume = self.data[:volumes][volume_id]
response.status = 200
response.body = { 'volume' => volume }
response
else
raise Fog::HP::BlockStorage::NotFound
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,54 @@
module Fog
module HP
class BlockStorage
class Real
# Get details for existing block storage snapshot
#
# ==== Parameters
# * snapshot_id<~Integer> - Id of the snapshot to get
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * snapshot<~Hash>:
# * 'id'<~Integer>: - Id for the snapshot
# * 'displayName'<~String>: - Name of the snapshot
# * 'displayDescription'<~String>: - Description of the snapshot
# * 'size'<~Integer>: - Size in GB for the snapshot
# * 'status'<~String>: - Status of the snapshot i.e. "available"
# * 'volumeId'<~Integer>: - Id of the volume from which the snapshot was created
# * 'createdAt'<~String>: - Timestamp in UTC when volume was created
def get_snapshot_details(snapshot_id)
response = request(
:expects => 200,
:method => 'GET',
:path => "os-snapshots/#{snapshot_id}"
)
response
end
end
class Mock # :nodoc:all
def get_snapshot_details(snapshot_id)
unless snapshot_id
raise ArgumentError.new('snapshot_id is required')
end
response = Excon::Response.new
if snapshot = self.data[:snapshots][snapshot_id]
response.status = 200
response.body = { 'snapshot' => snapshot }
response
else
raise Fog::HP::BlockStorage::NotFound
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,58 @@
module Fog
module HP
class BlockStorage
class Real
# Get details for existing block storage volume
#
# ==== Parameters
# * volume_id<~Integer> - Id of the volume to get
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * volume<~Hash>:
# * 'id'<~Integer>: - Id for the volume
# * 'displayName'<~String>: - Name of the volume
# * 'displayDescription'<~String>: - Description of the volume
# * 'size'<~Integer>: - Size in GB for the volume
# * 'status'<~String>: - Status of the volume i.e. "available"
# * 'volumeType'<~String>: - Type of the volume
# * 'snapshotId'<~String>: - Id of the volume snapshot
# * 'createdAt'<~String>: - Timestamp in UTC when volume was created
# * 'availabilityZone'<~String>: - Availability zone i.e. "nova"
# * attachments<~Array>: Array of hashes of attachments
# * metadata<~Hash>: Hash of metadata for the volume
def get_volume_details(volume_id)
response = request(
:expects => 200,
:method => 'GET',
:path => "os-volumes/#{volume_id}"
)
response
end
end
class Mock # :nodoc:all
def get_volume_details(volume_id)
unless volume_id
raise ArgumentError.new('volume_id is required')
end
response = Excon::Response.new
if volume = self.data[:volumes][volume_id]
response.status = 200
response.body = { 'volume' => volume }
response
else
raise Fog::HP::BlockStorage::NotFound
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,53 @@
module Fog
module HP
class BlockStorage
class Real
# List existing block storage bootbale volumes
#
# ==== Parameters
# None
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Array>:
# * volumes<~Hash>:
# * 'id'<~Integer>: - Id for the volume
# * 'displayName'<~String>: - Name of the volume
# * 'displayDescription'<~String>: - Description of the volume
# * 'size'<~Integer>: - Size in GB for the volume
# * 'status'<~String>: - Status of the volume i.e. "available"
# * 'volumeType'<~String>: - Type of the volume
# * 'snapshotId'<~String>: - Id of the source snapshot used to create volume
# * 'sourceImageRef'<~String>: - Id of the source image used to create volume
# * 'createdAt'<~String>: - Timestamp in UTC when volume was created
# * 'availabilityZone'<~String>: - Availability zone i.e. "nova"
# * attachments<~Array>: Array of hashes of attachments
# * metadata<~Hash>: Hash of metadata for the volume
def list_bootable_volumes
response = request(
:expects => 200,
:method => 'GET',
:path => "hp-bootable-volumes"
)
response
end
end
class Mock # :nodoc:all
def list_bootable_volumes
response = Excon::Response.new
volumes = []
volumes = self.data[:volumes].values unless self.data[:volumes].nil?
response.status = 200
response.body = { 'volumes' => volumes }
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,48 @@
module Fog
module HP
class BlockStorage
class Real
# List existing block storage snapshots
#
# ==== Parameters
# None
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Array>:
# * snapshots<~Hash>:
# * 'id'<~Integer>: - Id for the snapshot
# * 'displayName'<~String>: - Name of the snapshot
# * 'displayDescription'<~String>: - Description of the snapshot
# * 'size'<~Integer>: - Size in GB for the snapshot
# * 'status'<~String>: - Status of the snapshot i.e. "available"
# * 'volumeId'<~Integer>: - Id of the volume from which the snapshot was created
# * 'createdAt'<~String>: - Timestamp in UTC when volume was created
def list_snapshots
response = request(
:expects => 200,
:method => 'GET',
:path => 'os-snapshots'
)
response
end
end
class Mock # :nodoc:all
def list_snapshots
response = Excon::Response.new
snapshots = []
snapshots = self.data[:snapshots].values unless self.data[:snapshots].nil?
response.status = 200
response.body = { 'snapshots' => snapshots }
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,52 @@
module Fog
module HP
class BlockStorage
class Real
# List existing block storage volumes
#
# ==== Parameters
# None
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Array>:
# * volumes<~Hash>:
# * 'id'<~Integer>: - Id for the volume
# * 'displayName'<~String>: - Name of the volume
# * 'displayDescription'<~String>: - Description of the volume
# * 'size'<~Integer>: - Size in GB for the volume
# * 'status'<~String>: - Status of the volume i.e. "available"
# * 'volumeType'<~String>: - Type of the volume
# * 'snapshotId'<~String>: - Id of the volume snapshot
# * 'createdAt'<~String>: - Timestamp in UTC when volume was created
# * 'availabilityZone'<~String>: - Availability zone i.e. "nova"
# * attachments<~Array>: Array of hashes of attachments
# * metadata<~Hash>: Hash of metadata for the volume
def list_volumes
response = request(
:expects => 200,
:method => 'GET',
:path => 'os-volumes'
)
response
end
end
class Mock # :nodoc:all
def list_volumes
response = Excon::Response.new
volumes = []
volumes = self.data[:volumes].values unless self.data[:volumes].nil?
response.status = 200
response.body = { 'volumes' => volumes }
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,78 @@
module Fog
module Compute
class HP
class Real
# Attach a block storage volume to an existing server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to attach the volume to
# * volume_id<~Integer> - Id of the volume to be attached to the server
# * device<~String> - Device name that is the mount point that the volume will be attached to. e.g. /dev/sdf
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'volumeAttachment'<~Hash>:
# * <~Hash>
# * 'volumeId':<~Integer> - The volume id
# * 'device':<~String> - The name of the device
def attach_volume(server_id, volume_id, device)
data = { 'volumeAttachment' =>
{ 'volumeId' => volume_id,
'device' => device
}
}
response = request(
:body => Fog::JSON.encode(data),
:expects => 200,
:method => 'POST',
:path => "servers/#{server_id}/os-volume_attachments"
)
response
end
end
class Mock # :nodoc:all
def attach_volume(server_id, volume_id, device)
response = Excon::Response.new
if server = self.data[:servers][server_id]
# mock the case when the volume is already attached to the server
if server['volumeAttachments'] && server['volumeAttachments'].select {|v| v['id'] == volume_id}
response.status = 400
response.body = '{"badRequest": {"message": "Volume status must be available", "code": 400}}'
raise(Excon::Errors.status_error({:expects => 200}, response))
else
resp_data = { "volumeAttachment" =>
{
"volumeId" => volume_id,
"id" => volume_id
}
}
response.body = resp_data
response.status = 200
data = {
"device" => device,
"serverId" => server_id,
"id" => volume_id,
"volumeId" => volume_id,
}
if server['volumeAttachments']
server['volumeAttachments'] << data
else
server['volumeAttachments'] = [data]
end
end
else
raise Fog::Compute::HP::NotFound
end
response
end
end
end
end
end

Просмотреть файл

@ -18,10 +18,7 @@ module Fog
def create_image(server_id, name, metadata = {})
body = { 'createImage' =>
{ 'name' => name,
'metadata' =>
{ 'ImageType' => metadata[:image_type],
'ImageVersion' => metadata[:image_version]
}
'metadata' => metadata
}
}
server_action(server_id, body)
@ -39,19 +36,19 @@ module Fog
data = {
'id' => image_id,
'server' => {"id"=>"3", "links"=>[{"href"=>"http://nova1:8774/v1.1/servers/#{server_id}", "rel"=>"bookmark"}]},
'server' => {"id"=>server_id, "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' => ""
'updated' => "2012-01-01T13:32:20Z",
'created' => "2012-01-01T13:32:20Z"
}
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.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

Просмотреть файл

@ -0,0 +1,168 @@
module Fog
module Compute
class HP
class Real
# Create a new persistent server i.e. use a bootable volume instead of an image
#
# ==== Parameters
# * name<~String> - Name of server
# * flavor_id<~Integer> - Id of flavor for server
# * block_device_mapping<~Array>: Use bootable volumes to create persistent instances
# * <~Hash>:
# * 'volume_size'<~String> - Size of the volume. Ignored, and automatically picked up from the volume
# * 'volume_id'<~String> - Id of the bootable volume to use
# * 'delete_on_termination'<~String> - Setting this to '1' (True) means that the volume gets deleted when the instance is killed. Set it to '0' to preserve the volume.
# * 'device_name'<~String> - Block device name e.g. "vda"
# * 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
# * '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>:
# * 'private'<~Array> - private and public fixed and floating ip addresses
# * 'flavor'<~Hash>
# * 'id'<~String> - id of the flavor
# * 'links'<~Array> - array of flavor links
# * 'id'<~Integer> - id of server
# * 'links'<~Array> - array of server links
# * 'hostId'<~String>
# * 'metadata'<~Hash> - metadata
# * 'name'<~String> - name of server
# * 'accessIPv4'<~String> - IPv4 ip address
# * 'accessIPv6'<~String> - IPv6 ip address
# * 'progress'<~Integer> - progress through current status
# * 'status'<~String> - current server status
# * 'created'<~String> - created date time stamp
# * 'updated'<~String> - updated date time stamp
# * 'user_id'<~String> - user id
# * 'tenant_id'<~String> - tenant id
# * 'uuid'<~String> - uuid of the server
# * 'config_drive'<~String> - config drive
# * 'security_groups'<~Array of Hash>
# * 'id'<~Integer> - id of the security group
# * 'name'<~String> - name of the security group
# * 'links'<~Array> - array of security group links
# * 'key_name'<~String> - name of the keypair
# * 'adminPass'<~String> - admin password for server
def create_persistent_server(name, flavor_id, block_device_mapping = [], options = {})
data = {
'server' => {
'flavorRef' => flavor_id,
'imageRef' => nil,
'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['config_drive']
data['server']['config_drive'] = options['config_drive']
end
if block_device_mapping
data['server']['block_device_mapping'] = block_device_mapping
end
request(
:body => Fog::JSON.encode(data),
:expects => 200,
:method => 'POST',
:path => 'os-volumes_boot'
)
end
end
class Mock
def create_persistent_server(name, flavor_id, block_device_mapping = [], options = {})
response = Excon::Response.new
if block_device_mapping && !block_device_mapping.empty?
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,
'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.status = 200
response
else
response.status = 400
raise(Excon::Errors::BadRequest, "No boot volume or boot image specified")
end
end
end
end
end
end

Просмотреть файл

@ -8,16 +8,15 @@ module Fog
# ==== Parameters
# * name<~String> - Name of server
# * flavor_id<~Integer> - Id of flavor for server
# * image_id<~Integer> - Id of image for server
# * image_id<~Integer> - Id of image for server. If block_device_mapping is passed, this is ignored.
# * 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>:
# * '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
@ -28,17 +27,34 @@ module Fog
# * 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
# * 'private'<~Array> - private and public fixed and floating ip addresses
# * 'flavor'<~Hash>
# * 'id'<~String> - id of the flavor
# * 'links'<~Array> - array of flavor links
# * 'id'<~Integer> - id of server
# * 'image'<~Hash> - id of image used to boot server
# * 'id'<~String> - id of the image
# * 'links'<~Array> - array of image links
# * 'links'<~Array> - array of server links
# * '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
# * 'name'<~String> - name of server
# * 'accessIPv4'<~String> - IPv4 ip address
# * 'accessIPv6'<~String> - IPv6 ip address
# * 'progress'<~Integer> - progress through current status
# * 'status'<~String> - current server status
# * 'created'<~String> - created date time stamp
# * 'updated'<~String> - updated date time stamp
# * 'user_id'<~String> - user id
# * 'tenant_id'<~String> - tenant id
# * 'uuid'<~String> - uuid of the server
# * 'config_drive'<~String> - config drive
# * 'security_groups'<~Array of Hash>
# * 'id'<~Integer> - id of the security group
# * 'name'<~String> - name of the security group
# * 'links'<~Array> - array of security group links
# * 'key_name'<~String> - name of the keypair
# * 'adminPass'<~String> - admin password for server
def create_server(name, flavor_id, image_id, options = {})
data = {
'server' => {
@ -81,8 +97,8 @@ module Fog
}
end
end
if options['availability_zone']
data['server']['availability_zone'] = options['availability_zone']
if options['config_drive']
data['server']['config_drive'] = options['config_drive']
end
request(
@ -101,11 +117,11 @@ module Fog
response = Excon::Response.new
response.status = 202
#if options['security_groups']
# sec_group_name = options['security_groups'][0]
#else
# sec_group_name = "default"
#end
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"}]},
@ -125,7 +141,7 @@ module Fog
'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}],
'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

Просмотреть файл

@ -0,0 +1,55 @@
module Fog
module Compute
class HP
class Real
# Delete metadata item for specific collections
#
# ==== Parameters
# * 'collection_name'<~String> - name of the collection i.e. images, servers for which the metadata is intented.
# * 'parent_id'<~Integer> - id of the collection i.e. image_id or the server_id
# * 'key'<~String> - key for the metadata item
#
# ==== Returns
# * response<~Excon::Response>:
# * body: Empty response body
#
def delete_meta(collection_name, parent_id, key)
request(
:expects => 204,
:method => 'DELETE',
:path => "#{collection_name}/#{parent_id}/metadata/#{key}"
)
end
end
class Mock
def delete_meta(collection_name, parent_id, key)
if collection_name == "images" then
if get_image_details(parent_id)
self.data[:images][parent_id]['metadata'].delete(key)
else
raise Fog::Compute::HP::NotFound
end
end
if collection_name == "servers" then
if get_server_details(parent_id)
self.data[:servers][parent_id]['metadata'].delete(key)
else
raise Fog::Compute::HP::NotFound
end
end
response = Excon::Response.new
response.status = 204
response
end
end
end
end
end

Просмотреть файл

@ -25,14 +25,14 @@ module Fog
response = Excon::Response.new
sg_rule = nil
self.data[:security_groups].each do |_, sgv|
if sgv['rules']
sg_rule_index = sgv['rules'].find_index { |r| !r.nil? && r['id'] == security_group_rule_id }
if sg_rule_index
sg_rule = sgv['rules'].delete_at sg_rule_index
end
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 "

Просмотреть файл

@ -0,0 +1,47 @@
module Fog
module Compute
class HP
class Real
# Detach a block storage volume from an existing server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to attach the volume to
# * volume_id<~Integer> - Id of the volume to be attached to the server
#
# ==== Returns
# * response<~Excon::Response>:
# * body: Empty
def detach_volume(server_id, volume_id)
response = request(
:expects => 202,
:method => 'DELETE',
:path => "servers/#{server_id}/os-volume_attachments/#{volume_id}"
)
response
end
end
class Mock # :nodoc:all
def detach_volume(server_id, volume_id)
response = Excon::Response.new
if server = self.data[:servers][server_id]
if server['volumeAttachments'] && server['volumeAttachments'].select {|v| v['volumeId'] == volume_id}
data = server['volumeAttachments'].reject {|v| v['volumeId'] == volume_id}
self.data[:servers][server_id]['volumeAttachments'] = data
response.status = 202
else
raise Fog::Compute::HP::NotFound
end
else
raise Fog::Compute::HP::NotFound
end
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,43 @@
module Fog
module Compute
class HP
class Real
require 'fog/aws/parsers/compute/get_console_output'
# Retrieve console output for specified instance
#
# ==== Parameters
# * server_id<~Integer> - Id of instance to get console output from
# * num_lines<~Integer> - Number of lines of console output from the end
# ==== Returns
# # * response<~Excon::Response>:
# * body<~Hash>:
# * 'output'<~String> - Console output
#
def get_console_output(server_id, num_lines)
body = { 'os-getConsoleOutput' => { 'length' => num_lines }}
server_action(server_id, body, 200)
end
end
class Mock
def get_console_output(server_id, num_lines)
output = ""
response = Excon::Response.new
if list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
(1..num_lines).each {|i| output += "Console Output Line #{i} \r\n"}
response.body = { 'output' => output }
response.status = 200
else
raise Fog::Compute::HP::NotFound
end
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,57 @@
module Fog
module Compute
class HP
class Real
# Get metadata item for specific collections
#
# ==== Parameters
# * 'collection_name'<~String> - name of the collection i.e. images, servers for which the metadata is intended.
# * 'parent_id'<~Integer> - id of the collection i.e. image_id or the server_id
# * 'key'<~String> - key for the metadata item
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * meta<~Hash>: hash of key/value pair for the metadata item found
#
def get_meta(collection_name, parent_id, key)
request(
:expects => [200, 203],
:method => 'GET',
:path => "#{collection_name}/#{parent_id}/metadata/#{key}"
)
end
end
class Mock
def get_meta(collection_name, parent_id, key)
if collection_name == "images" then
if get_image_details(parent_id)
raise Fog::Compute::HP::NotFound unless midata = self.data[:images][parent_id]['metadata'].fetch(key, nil)
else
raise Fog::Compute::HP::NotFound
end
end
if collection_name == "servers" then
if get_server_details(parent_id)
raise Fog::Compute::HP::NotFound unless midata = self.data[:servers][parent_id]['metadata'].fetch(key, nil)
else
raise Fog::Compute::HP::NotFound
end
end
response = Excon::Response.new
response.status = 200
response.body = { 'meta' => { key => midata } }
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,43 @@
module Fog
module Compute
class HP
class Real
# Retrieves the encrypted administrator password for a server running Windows.
#
# ==== Parameters
# * server_id<~Integer> - Id of server
#
# ==== Returns
# * password_data<~string>: Encrypted password for a server running Windows
#
def get_windows_password(server_id)
# get console output assuming that the server is already in active state
log_output = get_console_output(server_id, 400).body['output']
# decrypt the log output to extract the encrypted, base64-encoded password
encrypted_password = extract_password_from_log(log_output)
end
end
class Mock
def get_windows_password(server_id)
# need to mock out the private key as well
private_key = OpenSSL::PKey::RSA.generate(1024)
public_key = private_key.public_key
### The original password is Passw0rd
encoded_password = encrypt_using_public_key("Passw0rd", public_key)
if list_servers_detail.body['servers'].detect {|_| _['id'] == server_id}
# mock output for this call get_console_output(server_id, 400).body['output']
log_output = "start junk [cloud-init] Encrypt random password\n-----BEGIN BASE64-ENCODED ENCRYPTED PASSWORD-----\n#{encoded_password}-----END BASE64-ENCODED ENCRYPTED PASSWORD-----\nend junk [cloud-init] Done\n"
encrypted_password = extract_password_from_log(log_output)
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,56 @@
module Fog
module Compute
class HP
class Real
# List metadata for specific collections
#
# ==== Parameters
# * 'collection_name'<~String> - name of the collection i.e. images, servers for which the metadata is intended.
# * 'parent_id'<~Integer> - id of the collection i.e. image_id or the server_id
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * metadata<~Hash>: hash of key/value pair for the metadata items found
#
def list_metadata(collection_name, parent_id)
request(
:expects => [200, 203],
:method => 'GET',
:path => "/#{collection_name}/#{parent_id}/metadata.json"
)
end
end
class Mock
def list_metadata(collection_name, parent_id)
mdata = {}
if collection_name == "images" then
if get_image_details(parent_id)
mdata = self.data[:images][parent_id]['metadata']
else
raise Fog::Compute::HP::NotFound
end
end
if collection_name == "servers" then
if get_server_details(parent_id)
mdata = self.data[:servers][parent_id]['metadata']
else
raise Fog::Compute::HP::NotFound
end
end
response = Excon::Response.new
response.status = 200
response.body = {'metadata' => mdata}
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,49 @@
module Fog
module Compute
class HP
class Real
# List all volumes attached to a server
#
# ==== Parameters
# * server_id<~Integer> - Id of server to list attached volumes for
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * 'volumeAttachments'<~Array>:
# * <~Hash>
# * 'device':<~String> - The name of the device
# * 'serverId':<~Integer> - The server id to which thsi volume is attached
# * 'id':<~Integer> - The volume id
# * 'volumeId':<~Integer> - The volume id
def list_server_volumes(server_id)
response = request(
:expects => 200,
:method => 'GET',
:path => "servers/#{server_id}/os-volume_attachments"
)
response
end
end
class Mock # :nodoc:all
def list_server_volumes(server_id)
response = Excon::Response.new
volumes = []
if server = self.data[:servers][server_id]
volumes = server['volumeAttachments']
response.status = 200
response.body = { 'volumeAttachments' => volumes }
response
else
raise Fog::Compute::HP::NotFound
end
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,60 @@
module Fog
module Compute
class HP
class Real
# Set metadata for specific collections
#
# ==== Parameters
# * 'collection_name'<~String> - name of the collection i.e. images, servers for which the metadata is intented.
# * 'parent_id'<~Integer> - id of the collection i.e. image_id or the server_id
# * 'metadata'<~Hash> - A hash of key/value pairs containing the metadata
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * metadata<~Hash> - key/value pairs of metadata items
#
def set_metadata(collection_name, parent_id, metadata = {})
request(
:body => Fog::JSON.encode({ 'metadata' => metadata }),
:expects => 200,
:method => 'PUT',
:path => "#{collection_name}/#{parent_id}/metadata"
)
end
end
class Mock
def set_metadata(collection_name, parent_id, metadata = {})
if collection_name == "images" then
if get_image_details(parent_id)
self.data[:images][parent_id]['metadata'] = metadata
else
raise Fog::Compute::HP::NotFound
end
end
if collection_name == "servers" then
if get_server_details(parent_id)
self.data[:servers][parent_id]['metadata'] = metadata
else
raise Fog::Compute::HP::NotFound
end
end
response = Excon::Response.new
response.body = { "metadata" => metadata }
response.status = 200
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,61 @@
module Fog
module Compute
class HP
class Real
# Set or update metadata item for specific collections
#
# ==== Parameters
# * 'collection_name'<~String> - name of the collection i.e. images, servers for which the metadata is intented.
# * 'parent_id'<~Integer> - id of the collection i.e. image_id or the server_id
# * 'key'<~String> - key for the metadata item
# * 'value'<~String> - value for the metadata item
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * meta<~Hash>: hash of key/value pair for the metadata item updated
#
def update_meta(collection_name, parent_id, key, value)
request(
:body => Fog::JSON.encode({ 'meta' => { key => value }}),
:expects => 200,
:method => 'PUT',
:path => "#{collection_name}/#{parent_id}/metadata/#{key}"
)
end
end
class Mock
def update_meta(collection_name, parent_id, key, value)
if collection_name == "images" then
if get_image_details(parent_id)
self.data[:images][parent_id]['metadata'][key] = value
else
raise Fog::Compute::HP::NotFound
end
end
if collection_name == "servers" then
if get_server_details(parent_id)
self.data[:servers][parent_id]['metadata'][key] = value
else
raise Fog::Compute::HP::NotFound
end
end
response = Excon::Response.new
response.body = { "meta" => { key => value } }
response.status = 200
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,60 @@
module Fog
module Compute
class HP
class Real
# Update metadata for specific collections
#
# ==== Parameters
# * 'collection_name'<~String> - name of the collection i.e. images, servers for which the metadata is intented.
# * 'parent_id'<~Integer> - id of the collection i.e. image_id or the server_id
# * 'metadata'<~Hash> - A hash of key/value pairs containing the metadata
# ==== Returns
# * response<~Excon::Response>:
# * body<~Hash>:
# * metadata<~Hash> - all key/value pairs of metadata items merged with existing metadata
#
def update_metadata(collection_name, parent_id, metadata = {})
request(
:body => Fog::JSON.encode({ 'metadata' => metadata }),
:expects => 200,
:method => 'POST',
:path => "#{collection_name}/#{parent_id}/metadata.json"
)
end
end
class Mock
def update_metadata(collection_name, parent_id, metadata = {})
if collection_name == "images" then
if get_image_details(parent_id)
newmetadata = self.data[:images][parent_id]['metadata'].merge!(metadata)
else
raise Fog::Compute::HP::NotFound
end
end
if collection_name == "servers" then
if get_server_details(parent_id)
newmetadata = self.data[:servers][parent_id]['metadata'].merge!(metadata)
else
raise Fog::Compute::HP::NotFound
end
end
response = Excon::Response.new
response.body = { "metadata" => newmetadata }
response.status = 200
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,38 @@
module Fog
module Storage
class HP
class Real
# Delete a shared object
#
# ==== Parameters
# * shared_object_url<~String> - Url of the shared object
#
def delete_shared_object(shared_object_url)
# split up the shared object url
uri = URI.parse(shared_object_url)
path = uri.path
response = shared_request(
:expects => 204,
:method => 'DELETE',
:path => path
)
response
end
end
class Mock # :nodoc:all
def delete_shared_object(shared_object_url)
response = Excon::Response.new
response.status = 204
response
end
end
end
end
end

Просмотреть файл

@ -10,18 +10,21 @@ module Fog
# * object<~String> - Name of object to look for
#
def get_object(container, object, &block)
params = {}
if block_given?
params[:response_block] = Proc.new
response = request(
:response_block => block,
:expects => 200,
:method => 'GET',
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
)
else
response = request({
:block => block,
:expects => 200,
:method => 'GET',
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
}, false, &block)
end
response = request(params.merge!({
:block => block,
:expects => 200,
:method => 'GET',
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
}), false)
response
end

Просмотреть файл

@ -0,0 +1,31 @@
module Fog
module Storage
class HP
class Real
# Generate a temporary url for an object
#
# ==== Parameters
# * container<~String> - Name of container
# * object<~String> - Name of object
# * expires<~Integer> - Time the temporary url expire in secs.
# * method<~String> - Allowed HTTP method GET, PUT, HEAD only
def get_object_temp_url(container, object, expires, method)
generate_object_temp_url(container, object, expires, method)
end
end
class Mock # :nodoc:all
def get_object_temp_url(container, object, expires, method)
@hp_storage_uri = "https://swift-cluster.example.com:443/v1/account"
generate_object_temp_url(container, object, expires, method)
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,75 @@
module Fog
module Storage
class HP
class Real
# Get details for a shared container
#
# ==== Parameters
# * shared_container_url<~String> - Url of the shared container
# * 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-Container-Object-Count'<~String> - Count of objects in container
# * 'X-Container-Bytes-Used'<~String> - Bytes used
# * 'X-Trans-Id'<~String> - Trans Id
# * body<~Array>:
# * 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_shared_container(shared_container_url, options = {})
options = options.reject {|key, value| value.nil?}
# split up the shared container url
uri = URI.parse(shared_container_url)
path = uri.path
response = shared_request(
:expects => 200,
:method => 'GET',
:path => path,
:query => {'format' => 'json'}.merge!(options)
)
response
end
end
class Mock # :nodoc:all
def get_shared_container(shared_container_url, options = {})
response = Excon::Response.new
data = {
'name' => Fog::Mock.random_letters(10),
'hash' => Fog::HP::Mock.etag,
'bytes' => 11,
'content_type' => "text/plain",
'last_modified' => Time.now
}
response.status = 200
response.body = [data]
response.headers = {
'X-Container-Object-Count' => 1,
'X-Container-Bytes-Used' => 11,
'Accept-Ranges' => 'bytes',
'Content-Type' => "application/json",
'Content-Length' => 11,
'X-Trans-Id' => "tx#{Fog::Mock.random_hex(32)}"
}
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,67 @@
module Fog
module Storage
class HP
class Real
# Get details for a shared object
#
# ==== Parameters
# * shared_object_url<~String> - Url of the shared object
#
def get_shared_object(shared_object_url, &block)
# split up the shared object url
uri = URI.parse(shared_object_url)
path = uri.path
if block_given?
response = shared_request(
:response_block => block,
:expects => 200,
:method => 'GET',
:path => path
)
else
response = shared_request({
:block => block,
:expects => 200,
:method => 'GET',
:path => path
}, false, &block)
end
response
end
end
class Mock # :nodoc:all
def get_shared_object(shared_object_url, &block)
response = Excon::Response.new
response.status = 200
response.headers = {
'Last-Modified' => Date.today.rfc822,
'Etag' => Fog::HP::Mock.etag,
'Accept-Ranges' => 'bytes',
'Content-Type' => "text/plain",
'Content-Length' => 11,
'X-Trans-Id' => "tx#{Fog::Mock.random_hex(32)}"
}
unless block_given?
response.body = "This is a sample text.\n"
else
data = StringIO.new("This is a sample text.\n")
remaining = data.length
while remaining > 0
chunk = data.read([remaining, Excon::CHUNK_SIZE].min)
block.call(chunk)
remaining -= Excon::CHUNK_SIZE
end
end
response
end
end
end
end
end

Просмотреть файл

@ -30,6 +30,7 @@ module Fog
def head_container(container_name)
response = get_container(container_name)
response.body = nil
response.status = 204
response
end

Просмотреть файл

@ -25,6 +25,7 @@ module Fog
def head_object(container_name, object_name, options = {})
response = get_object(container_name, object_name, options)
response.body = nil
response.status = 200
response
end

Просмотреть файл

@ -0,0 +1,45 @@
module Fog
module Storage
class HP
class Real
# List number of objects and total bytes stored for a shared container
#
# ==== Parameters
# * shared_container_url<~String> - Url of the shared container
#
# ==== Returns
# * response<~Excon::Response>:
# * headers<~Hash>:
# * 'X-Container-Object-Count'<~String> - Count of containers
# * 'X-Container-Bytes-Used'<~String> - Bytes used
def head_shared_container(shared_container_url)
# split up the shared container url
uri = URI.parse(shared_container_url)
path = uri.path
response = shared_request(
:expects => 204,
:method => 'HEAD',
:path => path,
:query => {'format' => 'json'}
)
response
end
end
class Mock # :nodoc:all
def head_shared_container(shared_container_url)
response = get_shared_container(shared_container_url)
response.body = nil
response.status = 204
response
end
end
end
end
end

Просмотреть файл

@ -0,0 +1,39 @@
module Fog
module Storage
class HP
class Real
# Get headers for shared object
#
# ==== Parameters
# * * shared_object_url<~String> - Url of the shared object
#
def head_shared_object(shared_object_url)
# split up the shared object url
uri = URI.parse(shared_object_url)
path = uri.path
response = shared_request({
:expects => 200,
:method => 'HEAD',
:path => path
}, false)
response
end
end
class Mock # :nodoc:all
def head_shared_object(shared_object_url)
response = get_shared_object(shared_object_url)
response.body = nil
response.status = 200
response
end
end
end
end
end

Просмотреть файл

@ -22,16 +22,16 @@ module Fog
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)
read_h = options['X-Container-Read'] || ''
write_h = options['X-Container-Write'] || ''
unless options
read_acl, write_acl = self.class.header_to_perm_acl(read_h, write_h)
self.data[:acls][:container][container_name] = {:read_acl => read_acl, :write_acl => write_acl}
end
response = Excon::Response.new
container = {
:objects => {},
:objects => {}
}
if self.data[:containers][container_name]
response.status = 202

Просмотреть файл

@ -8,9 +8,20 @@ module Fog
# ==== Parameters
# * container<~String> - Name for container, should be < 256 bytes and must not contain '/'
#
def put_object(container, object, data, options = {})
def put_object(container, object, data, options = {}, &block)
data = Fog::Storage.parse_data(data)
headers = data[:headers].merge!(options)
if block_given?
headers['Transfer-Encoding'] = 'chunked'
headers.delete('Content-Length')
return request(
:request_block => block,
:expects => 201,
:headers => headers,
:method => 'PUT',
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
)
end
if headers.has_key?('Transfer-Encoding')
headers.delete('Content-Length')
end

Просмотреть файл

@ -0,0 +1,85 @@
module Fog
module Storage
class HP
class Real
# Create a new object in a shared container
#
# ==== Parameters
# * shared_container_url<~String> - Shared url for the container
# * object<~String> - Name of the object
# * options<~Hash> - header options
#
def put_shared_object(shared_container_url, object_name, data, options = {}, &block)
# split up the shared object url
uri = URI.parse(shared_container_url)
path = uri.path
data = Fog::Storage.parse_data(data)
headers = data[:headers].merge!(options)
if block_given?
headers['Transfer-Encoding'] = 'chunked'
headers.delete('Content-Length')
return shared_request(
:request_block => block,
:expects => 201,
:headers => headers,
:method => 'PUT',
:path => "#{path}/#{Fog::HP.escape(object_name)}"
)
end
if headers.has_key?('Transfer-Encoding')
headers.delete('Content-Length')
end
response = shared_request(
:body => data[:body],
:expects => 201,
:headers => headers,
:method => 'PUT',
:path => "#{path}/#{Fog::HP.escape(object_name)}"
)
response
end
end
class Mock # :nodoc:all
def put_shared_object(shared_container_url, object_name, data, options = {}, &block)
response = Excon::Response.new
data = Fog::Storage.parse_data(data)
unless data[:body].is_a?(String)
data[:body] = data[:body].read
end
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
response.headers = {
'Content-Length' => object['Content-Length'],
'Content-Type' => object['Content-Type'],
'ETag' => object['ETag'],
'Date' => object['Date']
}
response
end
end
end
end
end

Просмотреть файл

@ -5,28 +5,42 @@ 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
requires :hp_secret_key, :hp_tenant_id, :hp_avl_zone
recognizes :hp_auth_uri, :hp_cdn_ssl, :hp_cdn_uri
recognizes :persistent, :connection_options
recognizes :hp_use_upass_auth_style, :hp_auth_version, :user_agent
recognizes :hp_access_key, :hp_account_id # :hp_account_id is deprecated use hp_access_key instead
secrets :hp_secret_key
model_path 'fog/hp/models/storage'
model :directory
collection :directories
model :shared_directory
collection :shared_directories
model :file
collection :files
model :shared_file
collection :shared_files
request_path 'fog/hp/requests/storage'
request :delete_container
request :delete_object
request :delete_shared_object
request :get_container
request :get_containers
request :get_object
request :get_object_temp_url
request :get_shared_container
request :get_shared_object
request :head_container
request :head_containers
request :head_object
request :head_shared_container
request :head_shared_object
request :put_container
request :put_object
request :put_shared_object
module Utils
@ -34,11 +48,12 @@ module Fog
unless @hp_cdn_uri.nil?
@cdn ||= Fog::CDN.new(
:provider => 'HP',
:hp_account_id => @hp_account_id,
:hp_access_key => @hp_access_key,
:hp_secret_key => @hp_secret_key,
:hp_auth_uri => @hp_auth_uri,
:hp_cdn_uri => @hp_cdn_uri,
:hp_tenant_id => @hp_tenant_id,
:hp_avl_zone => @hp_avl_zone,
:connection_options => @connection_options
)
if @cdn.enabled?
@ -53,35 +68,118 @@ module Fog
"#{@scheme}://#{@host}:#{@port}#{@path}"
end
def acl_to_header(acl)
def public_url(container=nil, object=nil)
public_url = nil
unless container.nil?
if object.nil?
# return container public url
public_url = "#{url}/#{Fog::HP.escape(container)}"
else
# return object public url
public_url = "#{url}/#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
end
end
public_url
end
def perm_to_acl(perm, users=[])
read_perm_acl = []
write_perm_acl = []
valid_public_perms = ['pr', 'pw', 'prw']
valid_account_perms = ['r', 'w', 'rw']
valid_perms = valid_public_perms + valid_account_perms
unless valid_perms.include?(perm)
raise ArgumentError.new("permission must be one of [#{valid_perms.join(', ')}]")
end
# tackle the public access differently
if valid_public_perms.include?(perm)
case perm
when "pr"
read_perm_acl = [".r:*",".rlistings"]
when "pw"
write_perm_acl = ["*"]
when "prw"
read_perm_acl = [".r:*",".rlistings"]
write_perm_acl = ["*"]
end
elsif valid_account_perms.include?(perm)
# tackle the user access differently
unless (users.nil? || users.empty?)
# return the correct acls
tenant_id = "*" # this might change later
acl_array = users.map { |u| "#{tenant_id}:#{u}" }
#acl_string = acl_array.join(',')
case perm
when "r"
read_perm_acl = acl_array
when "w"
write_perm_acl = acl_array
when "rw"
read_perm_acl = acl_array
write_perm_acl = acl_array
end
end
end
return read_perm_acl, write_perm_acl
end
def perm_acl_to_header(read_perm_acl, write_perm_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'] = "*"
if read_perm_acl.nil? && write_perm_acl.nil?
header = {'X-Container-Read' => "", 'X-Container-Write' => ""}
elsif !read_perm_acl.nil? && write_perm_acl.nil?
header = {'X-Container-Read' => "#{read_perm_acl.join(',')}", 'X-Container-Write' => ""}
elsif read_perm_acl.nil? && !write_perm_acl.nil?
header = {'X-Container-Read' => "", 'X-Container-Write' => "#{write_perm_acl.join(',')}"}
elsif !read_perm_acl.nil? && !write_perm_acl.nil?
header = {'X-Container-Read' => "#{read_perm_acl.join(',')}", 'X-Container-Write' => "#{write_perm_acl.join(',')}"}
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
def header_to_perm_acl(read_header=nil, write_header=nil)
read_h, write_h = nil
read_h = read_header.split(',') unless read_header.nil?
write_h = write_header.split(',') unless write_header.nil?
return read_h, write_h
end
def generate_object_temp_url(container, object, expires_secs, method)
return unless (container && object && expires_secs && method)
# POST not allowed
allowed_methods = %w{GET PUT HEAD}
unless allowed_methods.include?(method)
raise ArgumentError.new("Invalid method '#{method}' specified. Valid methods are: #{allowed_methods.join(', ')}")
end
expires = (Time.now + expires_secs.to_i).to_i
# split up the storage uri
uri = URI.parse(@hp_storage_uri)
host = uri.host
path = uri.path
port = uri.port
scheme = uri.scheme
# do not encode before signature generation, encode after
sig_path = "#{path}/#{container}/#{object}"
encoded_path = "#{path}/#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
string_to_sign = "#{method}\n#{expires}\n#{sig_path}"
# Only works with 1.9+ Not compatible with 1.8.7
#signed_string = Digest::HMAC.hexdigest(string_to_sign, @hp_secret_key, Digest::SHA1)
# Compatible with 1.8.7 onwards
hmac = OpenSSL::HMAC.new(@hp_secret_key, OpenSSL::Digest::SHA1.new)
signed_string = hmac.update(string_to_sign).hexdigest
signature = @hp_tenant_id.to_s + ":" + @hp_access_key.to_s + ":" + signed_string
signature = Fog::HP.escape(signature)
# generate the temp url using the signature and expiry
temp_url = "#{scheme}://#{host}:#{port}#{encoded_path}?temp_url_sig=#{signature}&temp_url_expires=#{expires}"
end
end
class Mock
@ -108,16 +206,25 @@ module Fog
def initialize(options={})
require 'mime/types'
# deprecate hp_account_id
if options[:hp_account_id]
Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
@hp_access_key = options.delete(:hp_account_id)
end
@hp_access_key = options[:hp_access_key]
unless @hp_access_key
raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
end
@hp_secret_key = options[:hp_secret_key]
@hp_account_id = options[:hp_account_id]
@hp_tenant_id = options[:hp_tenant_id]
end
def data
self.class.data[@hp_account_id]
self.class.data[@hp_access_key]
end
def reset_data
self.class.data.delete(@hp_account_id)
self.class.data.delete(@hp_access_key)
end
end
@ -128,16 +235,25 @@ module Fog
def initialize(options={})
require 'mime/types'
# deprecate hp_account_id
if options[:hp_account_id]
Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
options[:hp_access_key] = options.delete(:hp_account_id)
end
@hp_access_key = options[:hp_access_key]
unless @hp_access_key
raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
end
@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"
### Pass the service name for object storage to the authentication call
options[:hp_service_type] = "Object Storage"
@hp_tenant_id = options[:hp_tenant_id]
@hp_avl_zone = options[:hp_avl_zone]
### Make the authentication call
if (auth_version == :v2)
@ -157,12 +273,11 @@ module Fog
@auth_token = credentials[:auth_token]
uri = URI.parse(@hp_storage_uri)
@host = options[:hp_servicenet] == true ? "snet-#{uri.host}" : uri.host
@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
@ -195,6 +310,33 @@ module Fog
response
end
# this request is used only for get_shared_container and get_shared_object calls
def shared_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 => "#{params[:path]}",
}), &block)
rescue Excon::Errors::HTTPStatusError => error
raise case error
when Excon::Errors::NotFound
Fog::Storage::HP::NotFound.slurp(error)
when Excon::Errors::Forbidden
Fog::HP::Errors::Forbidden.slurp(error)
else
error
end
end
if !response.body.empty? && parse_json && response.headers['Content-Type'] =~ %r{application/json}
response.body = Fog::JSON.decode(response.body)
end
response
end
end
end
end

Просмотреть файл

@ -30,4 +30,4 @@ require 'fog/vmfusion'
require 'fog/vsphere'
require 'fog/voxel'
require 'fog/xenserver'
require 'fog/zerigo'
require 'fog/zerigo'

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,6 @@
Shindo.tests('Fog::Connection', 'core') do
tests('user_agent').returns("fog/#{Fog::VERSION}") do
conn = Fog::Connection.new("http://www.testserviceurl.com", false, {})
conn.instance_variable_get(:@excon).connection[:headers]['User-Agent']
end
end

Просмотреть файл

@ -39,9 +39,10 @@ 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_access_key => 'hp_access_key',
:hp_secret_key => 'hp_secret_key',
:hp_tenant_id => 'hp_tenant_id',
:hp_avl_zone => 'hp_avl_zone',
:ibm_username => 'ibm_username',
:ibm_password => 'ibm_password',
:joyent_username => "joyentuser",

Просмотреть файл

@ -0,0 +1,23 @@
Shindo.tests("HP::BlockStorage | bootable volumes", ['hp', 'block_storage', 'volumes']) do
@base_image_id = ENV["BASE_IMAGE_ID"] || 1242
model_tests(HP[:block_storage].bootable_volumes, {:name => "fogbvoltests", :description => "fogbvoltests-desc", :size => 10, :image_id => @base_image_id}, true)
tests("new volume") do
@volume = HP[:block_storage].bootable_volumes.create(:name => "testbvol", :size => 10, :image_id => @base_image_id)
@volume.wait_for { ready? } unless Fog.mocking?
test("get(#{@volume.id})") do
HP[:block_storage].bootable_volumes.get(@volume.id) != nil?
end
test("has_attachments?") do
@volume.has_attachments? == false
end
after do
@volume.destroy
end
end
end

Просмотреть файл

@ -0,0 +1,23 @@
Shindo.tests("HP::BlockStorage | snapshots", ['hp', 'block_storage', 'snapshots']) do
@volume = HP[:block_storage].volumes.create(:name => "testsnapvol", :size => 1)
@volume.wait_for { ready? } unless Fog.mocking?
model_tests(HP[:block_storage].snapshots, {:name => "fogsnaptests", :description => "fogsnaptests-desc", :volume_id => @volume.id}, true)
tests("new snapshot") do
@snapshot = HP[:block_storage].snapshots.create(:name => "testvol", :volume_id => @volume.id)
@snapshot.wait_for { ready? } unless Fog.mocking?
test("get(#{@snapshot.id})") do
HP[:block_storage].snapshots.get(@snapshot.id) != nil?
end
after do
@snapshot.destroy
end
end
@volume.destroy
end

Просмотреть файл

@ -0,0 +1,21 @@
Shindo.tests("HP::BlockStorage | volumes", ['hp', 'block_storage', 'volumes']) do
model_tests(HP[:block_storage].volumes, {:name => "fogvoltests", :description => "fogvoltests-desc", :size => 1}, true)
tests("new volume") do
@volume = HP[:block_storage].volumes.create(:name => "testvol", :size => 1)
@volume.wait_for { ready? } unless Fog.mocking?
test("get(#{@volume.id})") do
HP[:block_storage].volumes.get(@volume.id) != nil?
end
test("has_attachments?") do
@volume.has_attachments? == false
end
after do
@volume.destroy
end
end
end

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests("Fog::Compute[:hp] | address", ["hp"]) do
Shindo.tests("Fog::Compute[:hp] | address", ['hp']) do
@base_image_id = ENV["BASE_IMAGE_ID"] || 1242

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,60 @@
Shindo.tests("Fog::Compute[:hp] | metadata for images", ['hp']) do
@base_image_id = ENV["BASE_IMAGE_ID"] || 1242
@server = Fog::Compute[:hp].servers.create(:name => "fogsermdtests", :flavor_id => 100, :image_id => @base_image_id)
@server.wait_for { ready? }
response = @server.create_image("fogimgmetadatatests", :metadata => {'Meta1' => 'MetaValue1', 'Meta2' => 'MetaValue2'})
unless Fog.mocking?
sleep(10)
end
new_image_id = response.headers["Location"].split("/")[5]
@image = Fog::Compute[:hp].images.get(new_image_id)
tests('success') do
tests("#all").succeeds do
@image.metadata.all
end
tests("#get('Meta1')").succeeds do
pending if Fog.mocking?
@image.metadata.get('Meta1')
end
tests("#update({'Meta3' => 'MetaValue3'})").succeeds do
@data = @image.metadata.update({'Meta3' => 'MetaValue3'})
test("metadata has updated correctly") do
@image.metadata.get('Meta3').value == "MetaValue3"
end
end
tests("#set({'Meta4' => 'MetaValue4'})").succeeds do
@data = @image.metadata.set({'Meta4' => 'MetaValue4'})
test("metadata has set correctly") do
@image.metadata.get('Meta4').value == "MetaValue4"
end
end
tests("#save").succeeds do
m = @image.metadata.new(:key => 'Meta5', :value => 'MetaValue5')
@data = m.save
test("metadata has saved correctly") do
@image.metadata.get('Meta5').value == "MetaValue5"
end
end
tests("#destroy('Meta5')").succeeds do
@image.metadata.destroy('Meta5')
test("metadata has been destroyed") do
@image.metadata.get('Meta5') == nil
end
end
end
unless Fog.mocking?
@image.destroy
end
@server.destroy
end

Просмотреть файл

@ -0,0 +1,54 @@
Shindo.tests("Fog::Compute[:hp] | metadata for servers", ['hp']) do
@base_image_id = ENV["BASE_IMAGE_ID"] || 1242
@server = Fog::Compute[:hp].servers.create(:name => "fogsermetadatatests", :flavor_id => 100, :image_id => @base_image_id, :metadata => {'Meta1' => 'MetaValue1', 'Meta2' => 'MetaValue2'})
@server.wait_for { ready? }
tests('success') do
tests("#all").succeeds do
@server.metadata.all
end
tests("#get('Meta1')").succeeds do
@data = @server.metadata.get('Meta1')
test("metadata gets correct value") do
@data.value == "MetaValue1"
end
end
tests("#update({'Meta3' => 'MetaValue3'})").succeeds do
@data = @server.metadata.update({'Meta3' => 'MetaValue3'})
test("metadata has updated correctly") do
@server.metadata.get('Meta3').value == "MetaValue3"
end
end
tests("#set({'Meta4' => 'MetaValue4'})").succeeds do
@data = @server.metadata.set({'Meta4' => 'MetaValue4'})
test("metadata has set correctly") do
@server.metadata.get('Meta4').value == "MetaValue4"
end
end
tests("#save").succeeds do
m = @server.metadata.new(:key => 'Meta5', :value => 'MetaValue5')
@data = m.save
test("metadata has saved correctly") do
@server.metadata.get('Meta5').value == "MetaValue5"
end
end
tests("#destroy('Meta5')").succeeds do
@data = @server.metadata.destroy('Meta5')
test("metadata has been destroyed") do
@server.metadata.get('Meta5') == nil
end
end
end
@server.destroy
end

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,23 @@
Shindo.tests("Fog::Storage[:hp] | directories", ['hp', 'storage']) do
collection_tests(Fog::Storage[:hp].directories, {:key => "fogdirtests"}, true)
tests('success') do
tests("#create('fogdirtests')").succeeds do
Fog::Storage[:hp].directories.create(:key => 'fogdirtests')
end
tests("#head('fogdirtests')").succeeds do
Fog::Storage[:hp].directories.head('fogdirtests')
end
tests("#get('fogdirtests')").succeeds do
@directory = Fog::Storage[:hp].directories.get('fogdirtests')
end
@directory.destroy
end
end

Просмотреть файл

@ -0,0 +1,62 @@
Shindo.tests("Fog::Storage[:hp] | directory", ['hp', 'storage']) do
model_tests(Fog::Storage[:hp].directories, {:key => "fogdirtests"}, true) do
tests('success') do
tests("#grant('pr')").succeeds do
@instance.grant('pr')
tests("public?").returns(true) do
@instance.public?
end
end
tests("#revoke('pr')").succeeds do
@instance.revoke('pr')
tests("public?").returns(false) do
@instance.public?
end
end
@instance.files.create(:key => 'sample.txt', :body => lorem_file)
tests("#files").succeeds do
@instance.files
end
@instance.files.get('sample.txt').destroy
tests("#cdn_enable=(true)").succeeds do
pending if Fog.mocking?
@instance.cdn_enable=(true)
tests("cdn_enabled?").returns(true) do
pending if Fog.mocking?
@instance.cdn_enable?
end
end
tests("#cdn_public_url").succeeds do
pending if Fog.mocking?
@instance.cdn_public_url
end
tests("#cdn_public_ssl_url").succeeds do
pending if Fog.mocking?
@instance.cdn_public_ssl_url
end
end
tests('failure') do
tests("#grant('invalid-acl')").raises(ArgumentError) do
@instance.grant('invalid-acl')
end
tests("#revoke('invalid-acl')").raises(ArgumentError) do
@instance.revoke('invalid-acl')
end
end
end
end

Просмотреть файл

@ -0,0 +1,44 @@
Shindo.tests("Fog::Storage[:hp] | directory", ['hp', 'storage']) do
file_attributes = {
:key => 'fog_file_tests',
:body => lorem_file,
:public => true
}
directory_attributes = {
:key => 'fogfilestests'
}
@directory = Fog::Storage[:hp].directories.create(directory_attributes)
model_tests(@directory.files, file_attributes, true) do
@file = @directory.files.get('fog_file_tests')
tests('success') do
tests("#directory").returns(@directory.key) do
@file.directory.key
end
tests("#cdn_public_url").succeeds do
pending if Fog.mocking?
@file.cdn_public_url
end
tests("#cdn_public_ssl_url").succeeds do
pending if Fog.mocking?
@file.cdn_public_ssl_url
end
tests("#temp_signed_url(60, 'GET')").succeeds do
@file.temp_signed_url(60, 'GET')
end
end
end
@directory.destroy
end

Просмотреть файл

@ -0,0 +1,38 @@
Shindo.tests("Fog::Storage[:hp] | files", ['hp', 'storage']) do
file_attributes = {
:key => 'fog_files_tests',
:body => lorem_file
}
directory_attributes = {
:key => 'fogfilestests'
}
collection_tests(Fog::Storage[:hp].directories.create(directory_attributes).files, file_attributes, true)
@directory = Fog::Storage[:hp].directories.create(directory_attributes)
@file = @directory.files.create(file_attributes)
tests('success') do
tests("#get_url('#{@directory.key}')").succeeds do
@directory.files.get_url(@directory.key)
end
tests("#get_cdn_url('#{@directory.key}')").succeeds do
pending if Fog.mocking?
@directory.files.get_cdn_url(@directory.key)
end
tests("#get_cdn_ssl_url('#{@directory.key}')").succeeds do
pending if Fog.mocking?
@directory.files.get_cdn_ssl_url(@directory.key)
end
end
@file.destroy
@directory.destroy
end

Просмотреть файл

@ -0,0 +1,78 @@
Shindo.tests("HP::BlockStorage | bootable volume requests", ['hp', 'block_storage', 'volumes']) do
@volume_format = {
'status' => String,
'displayDescription' => Fog::Nullable::String,
'availabilityZone' => String,
'displayName' => Fog::Nullable::String,
'attachments' => [Fog::Nullable::Hash],
'volumeType' => Fog::Nullable::String,
'snapshotId' => Fog::Nullable::String,
'size' => Integer,
'id' => Integer,
'createdAt' => String,
'metadata' => Fog::Nullable::Hash
}
@boot_volume_format = {
'status' => String,
'displayDescription' => Fog::Nullable::String,
'availabilityZone' => String,
'displayName' => Fog::Nullable::String,
'attachments' => [Fog::Nullable::Hash],
'volumeType' => Fog::Nullable::String,
'snapshotId' => Fog::Nullable::String,
'source_image_id' => Fog::Nullable::String,
'size' => Integer,
'id' => Integer,
'createdAt' => String,
'metadata' => Fog::Nullable::Hash
}
@volume_attach_format = {
"volumeId" => Integer,
"id" => Integer
}
tests('success') do
@volume_id = nil
@volume_name = "fogbvolumetests"
@volume_desc = @volume_name + " desc"
@base_image_id = ENV["BASE_IMAGE_ID"] || 1242
tests("#create_volume(#{@volume_name}, #{@volume_desc}, 10, {'imageRef' => '#{@base_image_id}'})").formats(@volume_format) do
data = HP[:block_storage].create_volume(@volume_name, @volume_desc, 10, {'imageRef' => "#{@base_image_id}"}).body['volume']
@volume_id = data['id']
data
end
HP[:block_storage].volumes.get(@volume_id).wait_for { ready? }
tests("#get_bootable_volume_details(#{@volume_id})").formats(@boot_volume_format) do
HP[:block_storage].get_bootable_volume_details(@volume_id).body['volume']
end
tests("#list_bootable_volumes").formats({'volumes' => [@boot_volume_format]}) do
HP[:block_storage].list_bootable_volumes.body
end
HP[:block_storage].volumes.get(@volume_id).wait_for { ready? }
tests("#delete_volume(#{@volume_id})").succeeds do
HP[:block_storage].delete_volume(@volume_id)
end
end
tests('failure') do
tests("#get_bootable_volume_details(0)").raises(Fog::HP::BlockStorage::NotFound) do
HP[:block_storage].get_bootable_volume_details(0)
end
tests("#delete_volume(0)").raises(Fog::HP::BlockStorage::NotFound) do
HP[:block_storage].delete_volume(0)
end
end
end

Просмотреть файл

@ -0,0 +1,56 @@
Shindo.tests('HP::BlockStorage | snapshot requests', ['hp', 'block_storage', 'snapshots']) do
@snapshot_format = {
'status' => String,
'displayDescription' => Fog::Nullable::String,
'displayName' => Fog::Nullable::String,
'volumeId' => Integer,
'size' => Integer,
'id' => Integer,
'createdAt' => String
}
tests('success') do
@snapshot_id = nil
@snapshot_name = "fogsnapshottests"
@snapshot_desc = @snapshot_name + " desc"
@volume = HP[:block_storage].volumes.create(:name => 'fogvolforsnap', :size => 1)
@volume.wait_for { ready? }
tests("#create_snapshot(#{@snapshot_name}, #{@snapshot_desc}, #{@volume.id})").formats(@snapshot_format) do
data = HP[:block_storage].create_snapshot(@snapshot_name, @snapshot_desc, @volume.id).body['snapshot']
@snapshot_id = data['id']
data
end
tests("#get_snapshot_details(#{@snapshot_id})").formats(@snapshot_format) do
HP[:block_storage].get_snapshot_details(@snapshot_id).body['snapshot']
end
tests('#list_snapshots').formats({'snapshots' => [@snapshot_format]}) do
HP[:block_storage].list_snapshots.body
end
tests("#delete_snapshot(#{@snapshot_id})").succeeds do
HP[:block_storage].delete_snapshot(@snapshot_id)
end
end
tests('failure') do
tests('#get_snapshot_details(0)').raises(Fog::HP::BlockStorage::NotFound) do
HP[:block_storage].get_snapshot_details(0)
end
tests("#delete_snapshot(0)").raises(Fog::HP::BlockStorage::NotFound) do
HP[:block_storage].delete_snapshot(0)
end
end
@volume.destroy
end

Просмотреть файл

@ -0,0 +1,94 @@
Shindo.tests("HP::BlockStorage | volume requests", ['hp', 'block_storage', 'volumes']) do
@volume_format = {
'status' => String,
'displayDescription' => Fog::Nullable::String,
'availabilityZone' => String,
'displayName' => Fog::Nullable::String,
'attachments' => [Fog::Nullable::Hash],
'volumeType' => Fog::Nullable::String,
'snapshotId' => Fog::Nullable::String,
'size' => Integer,
'id' => Integer,
'createdAt' => String,
'metadata' => Fog::Nullable::Hash
}
@volume_attach_format = {
"volumeId" => Integer,
"id" => Integer
}
tests('success') do
@volume_id = nil
@volume_name = "fogvolumetests"
@volume_desc = @volume_name + " desc"
@base_image_id = ENV["BASE_IMAGE_ID"] || 1242
@server = Fog::Compute[:hp].servers.create(:name => 'fogvoltests', :flavor_id => 100, :image_id => @base_image_id)
@server.wait_for { ready? }
tests("#create_volume(#{@volume_name}, #{@volume_desc}, 1)").formats(@volume_format) do
data = HP[:block_storage].create_volume(@volume_name, @volume_desc, 1).body['volume']
@volume_id = data['id']
data
end
HP[:block_storage].volumes.get(@volume_id).wait_for { ready? }
tests("#get_volume_details(#{@volume_id})").formats(@volume_format) do
HP[:block_storage].get_volume_details(@volume_id).body['volume']
end
tests('#list_volumes').formats({'volumes' => [@volume_format]}) do
HP[:block_storage].list_volumes.body
end
HP[:block_storage].volumes.get(@volume_id).wait_for { ready? }
tests("#attach_volume(#{@server.id}, #{@volume_id}, '/dev/sdg')").formats(@volume_attach_format) do
Fog::Compute[:hp].attach_volume(@server.id, @volume_id, "/dev/sdg").body['volumeAttachment']
end
HP[:block_storage].volumes.get(@volume_id).wait_for { in_use? } unless Fog.mocking?
tests("#detach_volume(#{@server.id}, #{@volume_id})").succeeds do
Fog::Compute[:hp].detach_volume(@server.id, @volume_id)
end
HP[:block_storage].volumes.get(@volume_id).wait_for { ready? }
tests("#delete_volume(#{@volume_id})").succeeds do
HP[:block_storage].delete_volume(@volume_id)
end
end
tests('failure') do
tests('#get_volume_details(0)').raises(Fog::HP::BlockStorage::NotFound) do
HP[:block_storage].get_volume_details(0)
end
tests("#attach_volume(0, 0, '/dev/sdg')").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].attach_volume(0, 0, "/dev/sdg")
end
tests("#attach_volume(#{@server.id}, 0, '/dev/sdg')").raises(Fog::HP::BlockStorage::NotFound) do
pending if Fog.mocking?
Fog::Compute[:hp].attach_volume(@server.id, 0, "/dev/sdg")
end
tests("#detach_volume(0, 0)").raises(Fog::Compute::HP::NotFound) do
Fog::Compute[:hp].detach_volume(0, 0)
end
tests("#detach_volume(#{@server.id}, 0)").raises(Fog::HP::BlockStorage::NotFound) do
pending if Fog.mocking?
Fog::Compute[:hp].detach_volume(@server.id, 0)
end
tests("#delete_volume(0)").raises(Fog::HP::BlockStorage::NotFound) do
HP[:block_storage].delete_volume(0)
end
end
@server.destroy
end

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests('Fog::CDN[:hp] | container requests', ["hp"]) do
Shindo.tests("Fog::CDN[:hp] | container requests", ['hp']) do
@cdn_containers_format = [{
'x-cdn-ssl-uri' => String,

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests('Fog::Compute[:hp] | address requests', ["hp"]) do
Shindo.tests("Fog::Compute[:hp] | address requests", ['hp', 'address']) do
@floating_ips_format = {
'instance_id' => Fog::Nullable::Integer,
@ -30,12 +30,11 @@ Shindo.tests('Fog::Compute[:hp] | address requests', ["hp"]) do
@server.wait_for { ready? }
tests("#associate_address('#{@server.id}', '#{@ip_address}')").succeeds do
result = 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']
Fog::Compute[:hp].associate_address(@server.id, @ip_address)
tests("#get_address").returns(@ip_address, "server has associated ip address") do
@server.reload
@server.addresses['private'][1]['addr']
end
result
end
tests("#disassociate_address('#{@server.id}', '#{@ip_address}')").succeeds do

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests('Fog::Compute[:hp] | flavor requests', ["hp"]) do
Shindo.tests("Fog::Compute[:hp] | flavor requests", ['hp']) do
@flavor_format = {
'rxtx_quota' => Integer,

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests('Fog::Compute[:hp] | image requests', ["hp"]) do
Shindo.tests("Fog::Compute[:hp] | image requests", ['hp']) do
@image_format = {
'id' => String,

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests('Fog::Compute[:hp] | key pair requests', ["hp"]) do
Shindo.tests("Fog::Compute[:hp] | key pair requests", ['hp']) do
tests('success') do

Просмотреть файл

@ -0,0 +1,70 @@
Shindo.tests("Fog::Compute[:hp] | metadata requests", ['hp']) do
@metadata_format = {
'metadata' => Fog::Nullable::Hash
}
@metaitem_format = {
'meta' => Fog::Nullable::Hash
}
@base_image_id = ENV["BASE_IMAGE_ID"] || 1242
tests('success') do
@server_name = "fogmetadatatest"
@server = Fog::Compute[:hp].servers.create(:name => @server_name, :flavor_id => 100, :image_id => @base_image_id, :metadata => {'Meta1' => 'MetaValue1', 'Meta2' => 'MetaValue2'} )
@server.wait_for { ready? }
tests("#list_metadata('servers', #{@server.id})").formats(@metadata_format) do
metadata = Fog::Compute[:hp].list_metadata('servers', @server.id).body
test ("metadata exists") do
metadata['metadata']['Meta1'] == "MetaValue1"
end
metadata
end
tests("#set_metadata('servers', #{@server.id}, {'MetaNew3' => 'MetaNewValue3'})").formats(@metadata_format) do
data = Fog::Compute[:hp].set_metadata('servers', @server.id, {'MetaNew3' => 'MetaNewValue3'}).body
test ("metadata set correctly") do
metadata = Fog::Compute[:hp].list_metadata('servers', @server.id).body
metadata['metadata']['MetaNew3'] == "MetaNewValue3"
end
data
end
tests("#update_metadata('servers', #{@server.id}, {'MetaUpd4' => 'MetaUpdValue4'})").formats(@metadata_format) do
data = Fog::Compute[:hp].update_metadata('servers', @server.id, {'MetaUpd4' => 'MetaUpdValue4'}).body
test ("metadata updated correctly") do
metadata = Fog::Compute[:hp].list_metadata('servers', @server.id).body
metadata['metadata']['MetaUpd4'] == "MetaUpdValue4"
end
data
end
tests("#get_meta('servers', #{@server.id}, 'MetaNew3')").formats(@metaitem_format) do
mitem = Fog::Compute[:hp].get_meta('servers', @server.id, 'MetaNew3').body
test ("metadata item exists") do
mitem['meta']['MetaNew3'] == "MetaNewValue3"
end
mitem
end
tests("#update_meta('servers', #{@server.id}, 'MetaNew3', 'MetaUpdValue3')").formats(@metaitem_format) do
mitem = Fog::Compute[:hp].update_meta('servers', @server.id, 'MetaNew3', 'MetaUpdValue3').body
test ("metadata item updated correctly") do
mitem['meta']['MetaNew3'] == "MetaUpdValue3"
end
mitem
end
tests("#delete_meta('servers', #{@server.id}, 'MetaNew3')").succeeds do
data = Fog::Compute[:hp].delete_meta('servers', @server.id, 'MetaNew3').body
test ("metadata item deleted correctly") do
metadata = Fog::Compute[:hp].list_metadata('servers', @server.id).body
metadata['metadata'].fetch('MetaNew3', nil) == nil
end
data
end
@server.destroy
end
end

Просмотреть файл

@ -0,0 +1,66 @@
Shindo.tests("Fog::Compute[:hp] | persistent server requests", ['hp', 'compute']) do
@server_format = {
'addresses' => Fog::Nullable::Hash,
'flavor' => Hash,
'id' => Integer,
'links' => [Hash],
'hostId' => String,
'metadata' => Fog::Nullable::Hash,
'name' => String,
'accessIPv4' => Fog::Nullable::String,
'accessIPv6' => Fog::Nullable::String,
'progress' => Fog::Nullable::Integer,
'status' => String,
'created' => String,
'updated' => String,
'user_id' => String,
'tenant_id' => String,
'uuid' => String,
'config_drive' => Fog::Nullable::String,
'security_groups' => [Hash],
'key_name' => Fog::Nullable::String
}
@volume = HP[:block_storage].volumes.create(:name => 'fogvoltests', :description => 'fog vol test desc', :size => 1)
@volume.wait_for { ready? }
tests('success') do
@server_id = nil
@server_name = "fogpersservertests"
@block_device_mapping = [{ 'volume_size' => '',
'volume_id' => "#{@volume.id}",
'delete_on_termination' => '0',
'device_name' => 'vda'
}]
tests("#create_persistent_server(#{@server_name}, 100, #{@block_device_mapping})").formats(@server_format.merge('adminPass' => String)) do
data = Fog::Compute[:hp].create_persistent_server(@server_name, 100, @block_device_mapping).body['server']
@server_id = data['id']
data
end
Fog::Compute[:hp].servers.get(@server_id).wait_for { ready? }
tests("#get_server_details(#{@server_id})").formats(@server_format) do
Fog::Compute[:hp].get_server_details(@server_id).body['server']
end
tests("#delete_server(#{@server_id})").succeeds do
Fog::Compute[:hp].delete_server(@server_id)
end
end
tests('failure') do
tests("#create_persistent_server(#{@server_name}, 100, nil)").raises(Excon::Errors::BadRequest) do
Fog::Compute[:hp].create_persistent_server(@server_name, 100, nil)
end
end
HP[:block_storage].delete_volume(@volume.id)
end

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests('Fog::Compute[:hp] | security group requests', ["hp"]) do
Shindo.tests("Fog::Compute[:hp] | security group requests", ['hp']) do
@security_group_rule_format = {
'from_port' => Integer,

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests('Fog::Compute[:hp] | security group requests', ["hp"]) do
Shindo.tests("Fog::Compute[:hp] | security group requests", ['hp']) do
@security_groups_format = {
'security_groups' => [{

Просмотреть файл

@ -1,4 +1,4 @@
Shindo.tests('Fog::Compute[:hp] | address requests', ["hp"]) do
Shindo.tests("Fog::Compute[:hp] | address requests", ['hp']) do
@base_image_id = ENV["BASE_IMAGE_ID"] || 1242

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше