diff --git a/README.md b/README.md index 981157154..e8ccfd9b4 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Collections share basic CRUD type operations, such as: As an example, we'll try initializing and persisting a Rackspace Cloud server: ```ruby -require 'fog/rackspace' +require 'fog' compute = Fog::Compute.new( :provider => 'Rackspace', diff --git a/lib/fog.rb b/lib/fog.rb index d68c5af20..06ffeac5f 100644 --- a/lib/fog.rb +++ b/lib/fog.rb @@ -44,6 +44,7 @@ require 'fog/linode' require 'fog/local' require 'fog/bare_metal_cloud' require 'fog/ninefold' +require 'fog/rackspace' require 'fog/rage4' require 'fog/riakcs' require 'fog/openstack' diff --git a/lib/fog/bin.rb b/lib/fog/bin.rb index 2e175ed04..156ffc32e 100644 --- a/lib/fog/bin.rb +++ b/lib/fog/bin.rb @@ -76,6 +76,7 @@ require 'fog/bin/linode' require 'fog/bin/local' require 'fog/bin/bare_metal_cloud' require 'fog/bin/ninefold' +require 'fog/bin/rackspace' require 'fog/bin/rage4' require 'fog/bin/riakcs' require 'fog/bin/openstack' diff --git a/lib/fog/bin/rackspace.rb b/lib/fog/bin/rackspace.rb new file mode 100644 index 000000000..99fb9f4c0 --- /dev/null +++ b/lib/fog/bin/rackspace.rb @@ -0,0 +1,81 @@ +class Rackspace < Fog::Bin + class << self + def class_for(key) + case key + when :auto_scale + Fog::Rackspace::AutoScale + when :block_storage + Fog::Rackspace::BlockStorage + when :cdn + Fog::CDN::Rackspace + when :compute + Fog::Compute::Rackspace + when :compute_v2 + Fog::Compute::RackspaceV2 + when :storage + Fog::Storage::Rackspace + when :load_balancers + Fog::Rackspace::LoadBalancers + when :dns + Fog::DNS::Rackspace + when :identity + Fog::Rackspace::Identity + when :databases + Fog::Rackspace::Databases + when :monitoring + Fog::Rackspace::Monitoring + when :queues + Fog::Rackspace::Queues + when :networking + Fog::Rackspace::Networking + else + raise ArgumentError, "Unrecognized service: #{key}" + end + end + + def [](service) + @@connections ||= Hash.new do |hash, key| + hash[key] = case key + when :auto_scale + Fog::Rackspace::AutoScale.new + when :cdn + Fog::Logger.warning("Rackspace[:cdn] is not recommended, use CDN[:rackspace] for portability") + Fog::CDN.new(:provider => 'Rackspace') + when :compute + Fog::Logger.warning("Rackspace[:compute] is not recommended, use Compute[:rackspace] for portability") + Fog::Compute.new(:provider => 'Rackspace') + when :compute_v2 + Fog::Logger.warning("Rackspace[:compute] is not recommended, use Compute[:rackspace] for portability") + Fog::Compute.new(:provider => 'Rackspace', :version => 'v2') + when :dns + Fog::DNS.new(:provider => 'Rackspace') + when :load_balancers + Fog::Rackspace::LoadBalancers.new + when :storage + Fog::Logger.warning("Rackspace[:storage] is not recommended, use Storage[:rackspace] for portability") + Fog::Storage.new(:provider => 'Rackspace') + when :identity + Fog::Logger.warning("Rackspace[:identity] is not recommended, use Identity[:rackspace] for portability") + Fog::Identity.new(:provider => 'Rackspace') + when :databases + Fog::Rackspace::Databases.new + when :block_storage + Fog::Rackspace::BlockStorage.new + when :monitoring + Fog::Rackspace::Monitoring.new + when :queues + Fog::Rackspace::Queues.new + when :networking + Fog::Rackspace::Networking.new + else + raise ArgumentError, "Unrecognized service: #{key.inspect}" + end + end + @@connections[service] + end + + def services + Fog::Rackspace.services + end + end +end diff --git a/lib/fog/rackspace.rb b/lib/fog/rackspace.rb new file mode 100644 index 000000000..e1b4e602b --- /dev/null +++ b/lib/fog/rackspace.rb @@ -0,0 +1,13 @@ +require 'fog/rackspace/auto_scale' +require 'fog/rackspace/block_storage' +require 'fog/rackspace/cdn' +require 'fog/rackspace/compute' +require 'fog/rackspace/compute_v2' +require 'fog/rackspace/databases' +require 'fog/rackspace/dns' +require 'fog/rackspace/identity' +require 'fog/rackspace/load_balancers' +require 'fog/rackspace/monitoring' +require 'fog/rackspace/queues' +require 'fog/rackspace/storage' +require 'fog/rackspace/networking' diff --git a/lib/fog/rackspace/auto_scale.rb b/lib/fog/rackspace/auto_scale.rb new file mode 100644 index 000000000..a5f1e466a --- /dev/null +++ b/lib/fog/rackspace/auto_scale.rb @@ -0,0 +1,134 @@ +require 'fog/rackspace/core' + +module Fog + module Rackspace + class AutoScale < Fog::Service + include Fog::Rackspace::Errors + + class ServiceError < Fog::Rackspace::Errors::ServiceError; end + class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end + + class BadRequest < Fog::Rackspace::Errors::BadRequest + attr_reader :validation_errors + + def self.slurp(error, service=nil) + if error && error.response + status_code = error.response.status + if error.response.body + body = Fog::JSON.decode(error.response.body) + message = "#{body['type']} - #{body['message']}" + details = error.response.body['details'] + end + end + + new_error = new(message) + new_error.set_backtrace(error.backtrace) + new_error.instance_variable_set(:@validation_errors, details) + new_error.instance_variable_set(:@status_code, status_code) + new_error.set_transaction_id(error, service) + new_error + end + end + + requires :rackspace_username, :rackspace_api_key + recognizes :rackspace_auth_url + recognizes :rackspace_region + recognizes :rackspace_auto_scale_url + + model_path 'fog/rackspace/models/auto_scale' + model :group + collection :groups + model :group_config + model :launch_config + + model :policy + collection :policies + + model :webhook + collection :webhooks + + request_path 'fog/rackspace/requests/auto_scale' + request :list_groups + request :create_group + request :get_group + request :delete_group + request :get_group_state + request :pause_group_state + request :resume_group_state + + request :get_group_config + request :update_group_config + request :get_launch_config + request :update_launch_config + + request :list_policies + request :create_policy + request :get_policy + request :update_policy + request :delete_policy + request :execute_policy + + request :execute_anonymous_webhook + + request :get_webhook + request :list_webhooks + request :create_webhook + request :update_webhook + request :delete_webhook + + class Mock < Fog::Rackspace::Service + def initialize(options) + @rackspace_api_key = options[:rackspace_api_key] + end + + def request(params) + Fog::Mock.not_implemented + end + end + + class Real < Fog::Rackspace::Service + def initialize(options = {}) + @options = options + @options[:connection_options] ||= {} + @options[:persistent] ||= false + + authenticate + + @connection = Fog::Core::Connection.new(endpoint_uri.to_s, @options[:persistent], @options[:connection_options]) + end + + def request(params, parse_json = true, &block) + super(params, parse_json, &block) + rescue Excon::Errors::NotFound => error + raise NotFound.slurp(error, self) + rescue Excon::Errors::BadRequest => error + raise BadRequest.slurp(error, self) + rescue Excon::Errors::InternalServerError => error + raise InternalServerError.slurp(error, self) + rescue Excon::Errors::HTTPStatusError => error + raise ServiceError.slurp(error, self) + end + + def endpoint_uri(service_endpoint_url=nil) + @uri = super(@options[:rackspace_auto_scale_url], :rackspace_auto_scale_url) + end + + def authenticate(options={}) + super(select_options([:rackspace_username, :rackspace_api_key, :rackspace_auth_url, :connection_options])) + end + + def service_name + :autoscale + end + + def request_id_header + "x-response-id" + end + + def region + @options[:rackspace_region] + end + end + end + end +end diff --git a/lib/fog/rackspace/block_storage.rb b/lib/fog/rackspace/block_storage.rb new file mode 100644 index 000000000..974940b3a --- /dev/null +++ b/lib/fog/rackspace/block_storage.rb @@ -0,0 +1,175 @@ +require 'fog/rackspace/core' + +module Fog + module Rackspace + class BlockStorage < Fog::Service + include Fog::Rackspace::Errors + + class IdentifierTaken < Fog::Errors::Error; end + class ServiceError < Fog::Rackspace::Errors::ServiceError; end + class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end + class BadRequest < Fog::Rackspace::Errors::BadRequest; end + + DFW_ENDPOINT = 'https://dfw.blockstorage.api.rackspacecloud.com/v1' + LON_ENDPOINT = 'https://lon.blockstorage.api.rackspacecloud.com/v1' + ORD_ENDPOINT = 'https://ord.blockstorage.api.rackspacecloud.com/v1' + + requires :rackspace_api_key, :rackspace_username + recognizes :rackspace_auth_url + recognizes :rackspace_endpoint + recognizes :rackspace_region + recognizes :rackspace_block_storage_url + + model_path 'fog/rackspace/models/block_storage' + model :volume + collection :volumes + + model :volume_type + collection :volume_types + + model :snapshot + collection :snapshots + + request_path 'fog/rackspace/requests/block_storage' + request :create_volume + request :delete_volume + request :get_volume + request :list_volumes + + request :get_volume_type + request :list_volume_types + + request :create_snapshot + request :delete_snapshot + request :get_snapshot + request :list_snapshots + + class Mock < Fog::Rackspace::Service + include Fog::Rackspace::MockData + + def initialize(options = {}) + @rackspace_api_key = options[:rackspace_api_key] + end + + def request(params) + Fog::Mock.not_implemented + end + + def response(params={}) + body = params[:body] || {} + status = params[:status] || 200 + headers = params[:headers] || {} + + response = Excon::Response.new(:body => body, :headers => headers, :status => status) + if params.key?(:expects) && ![*params[:expects]].include?(response.status) + raise(Excon::Errors.status_error(params, response)) + else response + end + end + end + + class Real < Fog::Rackspace::Service + def initialize(options = {}) + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + @rackspace_auth_url = options[:rackspace_auth_url] + @rackspace_must_reauthenticate = false + @connection_options = options[:connection_options] || {} + setup_custom_endpoint(options) + + authenticate + + deprecation_warnings(options) + + @persistent = options[:persistent] || false + @connection = Fog::Core::Connection.new(endpoint_uri.to_s, @persistent, @connection_options) + end + + def request(params, parse_json = true) + super + rescue Excon::Errors::NotFound => error + raise NotFound.slurp(error, self) + rescue Excon::Errors::BadRequest => error + raise BadRequest.slurp(error, self) + rescue Excon::Errors::InternalServerError => error + raise InternalServerError.slurp(error, self) + rescue Excon::Errors::HTTPStatusError => error + raise ServiceError.slurp(error, self) + end + + def authenticate(options={}) + super({ + :rackspace_api_key => @rackspace_api_key, + :rackspace_username => @rackspace_username, + :rackspace_auth_url => @rackspace_auth_url, + :connection_options => @connection_options + }) + end + + def service_name + :cloudBlockStorage + end + + def region + @rackspace_region + end + + def request_id_header + "X-Compute-Request-Id" + end + + def endpoint_uri(service_endpoint_url=nil) + @uri = super(@rackspace_endpoint || service_endpoint_url, :rackspace_block_storage_url) + end + + private + + def setup_custom_endpoint(options) + @rackspace_endpoint = Fog::Rackspace.normalize_url(options[:rackspace_block_storage_url] || options[:rackspace_endpoint]) + + if v2_authentication? + case @rackspace_endpoint + when DFW_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :dfw + when ORD_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :ord + when LON_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :lon + else + @rackspace_region = options[:rackspace_region] + end + else + #if we are using auth1 and the endpoint is not set, default to DFW_ENDPOINT for historical reasons + @rackspace_endpoint ||= DFW_ENDPOINT + end + end + + def deprecation_warnings(options) + Fog::Logger.deprecation("The :rackspace_endpoint option is deprecated. Please use :rackspace_block_storage_url for custom endpoints") if options[:rackspace_endpoint] + + if [DFW_ENDPOINT, ORD_ENDPOINT, LON_ENDPOINT].include?(@rackspace_endpoint) && v2_authentication? + regions = @identity_service.service_catalog.display_service_regions(service_name) + Fog::Logger.deprecation("Please specify region using :rackspace_region rather than :rackspace_endpoint. Valid region for :rackspace_region are #{regions}.") + end + end + + def append_tenant_v1(credentials) + account_id = credentials['X-Server-Management-Url'].match(/.*\/([\d]+)$/)[1] + + endpoint = @rackspace_endpoint || credentials['X-Server-Management-Url'] || DFW_ENDPOINT + @uri = URI.parse(endpoint) + @uri.path = "#{@uri.path}/#{account_id}" + end + + def authenticate_v1(options) + credentials = Fog::Rackspace.authenticate(options, @connection_options) + append_tenant_v1 credentials + @auth_token = credentials['X-Auth-Token'] + end + end + end + end +end diff --git a/lib/fog/rackspace/cdn.rb b/lib/fog/rackspace/cdn.rb new file mode 100644 index 000000000..a5a89a0bf --- /dev/null +++ b/lib/fog/rackspace/cdn.rb @@ -0,0 +1,198 @@ +require 'fog/rackspace/core' + +module Fog + module CDN + class Rackspace < Fog::Service + requires :rackspace_api_key, :rackspace_username + recognizes :rackspace_auth_url, :persistent, :rackspace_cdn_ssl, :rackspace_region, :rackspace_cdn_url + + request_path 'fog/rackspace/requests/cdn' + request :get_containers + request :head_container + request :post_container + request :put_container + request :delete_object + + module Base + URI_HEADERS = { + "X-Cdn-Ios-Uri" => :ios_uri, + "X-Cdn-Uri" => :uri, + "X-Cdn-Streaming-Uri" => :streaming_uri, + "X-Cdn-Ssl-Uri" => :ssl_uri + }.freeze + + def apply_options(options) + # api_key and username missing from instance variable sets + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + + @connection_options = options[:connection_options] || {} + @rackspace_auth_url = options[:rackspace_auth_url] + @rackspace_cdn_url = options[:rackspace_cdn_url] + @rackspace_region = options[:rackspace_region] + end + + def service_name + :cloudFilesCDN + end + + def region + @rackspace_region + end + + def request_id_header + "X-Trans-Id" + end + + # Returns true if CDN service is enabled + # @return [Boolean] + def enabled? + @enabled + end + + def endpoint_uri(service_endpoint_url=nil) + @uri = super(@rackspace_cdn_url || service_endpoint_url, :rackspace_cdn_url) + end + + # Publish container to CDN + # @param [Fog::Storage::Rackspace::Directory] container directory to publish + # @param [Boolean] publish If true directory is published. If false directory is unpublished. + # @return [Hash] hash containing urls for published container + # @raise [Fog::Storage::Rackspace::NotFound] - HTTP 404 + # @raise [Fog::Storage::Rackspace::BadRequest] - HTTP 400 + # @raise [Fog::Storage::Rackspace::InternalServerError] - HTTP 500 + # @raise [Fog::Storage::Rackspace::ServiceError] + def publish_container(container, publish = true) + enabled = publish ? 'True' : 'False' + response = put_container(container.key, 'X-Cdn-Enabled' => enabled) + return {} unless publish + urls_from_headers(response.headers) + end + + # Returns hash of urls for container + # @param [Fog::Storage::Rackspace::Directory] container to retrieve urls for + # @return [Hash] hash containing urls for published container + # @raise [Fog::Storage::Rackspace::BadRequest] - HTTP 400 + # @raise [Fog::Storage::Rackspace::InternalServerError] - HTTP 500 + # @raise [Fog::Storage::Rackspace::ServiceError] + # @note If unable to find container or container is not published this method will return an empty hash. + def urls(container) + begin + response = head_container(container.key) + return {} unless response.headers['X-Cdn-Enabled'] == 'True' + urls_from_headers response.headers + rescue Fog::Service::NotFound + {} + end + end + + private + + def urls_from_headers(headers) + h = {} + URI_HEADERS.keys.each do | header | + key = URI_HEADERS[header] + h[key] = headers[header] + end + h + end + end + + class Mock < Fog::Rackspace::Service + include Base + + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = {} + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + apply_options(options) + authenticate(options) + @enabled = !! endpoint_uri + end + + def data + self.class.data[@rackspace_username] + end + + def purge(object) + return true if object.is_a? Fog::Storage::Rackspace::File + raise Fog::Errors::NotImplemented.new("#{object.class} does not support CDN purging") if object + end + + def reset_data + self.class.data.delete(@rackspace_username) + end + end + + class Real < Fog::Rackspace::Service + include Base + + def initialize(options={}) + apply_options(options) + authenticate(options) + @enabled = false + @persistent = options[:persistent] || false + + if endpoint_uri + @connection = Fog::Core::Connection.new(endpoint_uri.to_s, @persistent, @connection_options) + @enabled = true + end + end + + # Resets CDN connection + def reload + @cdn_connection.reset + end + + # Purges File + # @param [Fog::Storage::Rackspace::File] file to be purged from the CDN + # @raise [Fog::Errors::NotImplemented] returned when non file parameters are specified + def purge(file) + unless file.is_a? Fog::Storage::Rackspace::File + raise Fog::Errors::NotImplemented.new("#{object.class} does not support CDN purging") if object + end + + delete_object file.directory.key, file.key + true + end + + def request(params, parse_json = true) + super + rescue Excon::Errors::NotFound => error + raise Fog::Storage::Rackspace::NotFound.slurp(error, self) + rescue Excon::Errors::BadRequest => error + raise Fog::Storage::Rackspace::BadRequest.slurp(error, self) + rescue Excon::Errors::InternalServerError => error + raise Fog::Storage::Rackspace::InternalServerError.slurp(error, self) + rescue Excon::Errors::HTTPStatusError => error + raise Fog::Storage::Rackspace::ServiceError.slurp(error, self) + end + + private + + def authenticate_v1(options) + credentials = Fog::Rackspace.authenticate(options, @connection_options) + endpoint_uri credentials['X-CDN-Management-Url'] + @auth_token = credentials['X-Auth-Token'] + end + + # Fix for invalid auth_token, likely after 24 hours. + def authenticate(options={}) + super({ + :rackspace_api_key => @rackspace_api_key, + :rackspace_username => @rackspace_username, + :rackspace_auth_url => @rackspace_auth_url, + :connection_options => @connection_options + }) + end + end + end + end +end diff --git a/lib/fog/rackspace/compute.rb b/lib/fog/rackspace/compute.rb new file mode 100644 index 000000000..ee92ccdc6 --- /dev/null +++ b/lib/fog/rackspace/compute.rb @@ -0,0 +1,256 @@ +require 'fog/rackspace/core' + +module Fog + module Compute + class Rackspace < Fog::Service + include Fog::Rackspace::Errors + + class ServiceError < Fog::Rackspace::Errors::ServiceError; end + class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end + class BadRequest < Fog::Rackspace::Errors::BadRequest; end + + requires :rackspace_api_key, :rackspace_username + recognizes :rackspace_auth_url, :rackspace_servicenet, :persistent + recognizes :rackspace_auth_token, :rackspace_management_url, :rackspace_compute_v1_url, :rackspace_region + + model_path 'fog/rackspace/models/compute' + model :flavor + collection :flavors + model :image + collection :images + model :server + collection :servers + + request_path 'fog/rackspace/requests/compute' + request :confirm_resized_server + request :create_image + request :create_server + request :delete_image + request :delete_server + request :get_flavor_details + request :get_image_details + request :get_server_details + request :list_addresses + request :list_private_addresses + request :list_public_addresses + request :list_flavors + request :list_flavors_detail + request :list_images + request :list_images_detail + request :list_servers + request :list_servers_detail + request :reboot_server + request :revert_resized_server + request :resize_server + request :server_action + request :update_server + + class Mock < Fog::Rackspace::Service + def self.data + @data ||= Hash.new do |hash, key| + hash[key] = { + :last_modified => { + :images => {}, + :servers => {} + }, + :servers => {}, + :images => { + 112 => + {'id' => 112, + 'status' => "ACTIVE", + 'updated' => "2011-04-21T10:24:01-05:00", + 'name' => "Ubuntu 10.04 LTS"}, + 100 => + {'id' => 100, + 'status' => "ACTIVE", + 'updated' => "2011-09-12T09:09:23-05:00", + 'name' => "Arch 2011.10"}, + 31 => + {'id' => 31, + 'status' => "ACTIVE", + 'updated' => "2010-01-26T12:07:44-06:00", + 'name' => "Windows Server 2008 SP2 x86"}, + 108 => + {'id' => 108, + 'status' => "ACTIVE", + 'updated' => "2011-11-01T08:32:30-05:00", + 'name' => "Gentoo 11.0"}, + 109 => + {'id' => 109, + 'status' => "ACTIVE", + 'updated' => "2011-11-03T06:28:56-05:00", + 'name' => "openSUSE 12"}, + 89 => + {'id' => 89, + 'status' => "ACTIVE", + 'updated' => "2011-10-04T08:39:34-05:00", + 'name' => "Windows Server 2008 R2 x64 - SQL2K8R2 Web"}, + 24 => + {'id' => 24, + 'status' => "ACTIVE", + 'updated' => "2010-01-26T12:07:04-06:00", + 'name' => "Windows Server 2008 SP2 x64"}, + 110 => + {'id' => 110, + 'status' => "ACTIVE", + 'updated' => "2011-08-17T05:11:30-05:00", + 'name' => "Red Hat Enterprise Linux 5.5"}, + 57 => + {'id' => 57, + 'status' => "ACTIVE", + 'updated' => "2010-09-17T07:16:25-05:00", + 'name' => "Windows Server 2008 SP2 x64 - MSSQL2K8R2"}, + 85 => + {'id' => 85, + 'status' => "ACTIVE", + 'updated' => "2010-01-26T12:07:17-06:00", + 'name' => "Windows Server 2008 R2 x64"}, + 111 => + {'id' => 111, + 'status' => "ACTIVE", + 'updated' => "2011-09-12T10:53:12-05:00", + 'name' => "Red Hat Enterprise Linux 6"}, + 120 => + {'id' => 120, + 'status' => "ACTIVE", + 'updated' => "2012-01-03T04:39:05-06:00", + 'name' => "Fedora 16"}, + 119 => + {'id' => 119, + 'status' => "ACTIVE", + 'updated' => "2011-11-03T08:55:15-05:00", + 'name' => "Ubuntu 11.10"}, + 116 => + {'id' => 116, + 'status' => "ACTIVE", + 'updated' => "2011-08-17T05:11:30-05:00", + 'name' => "Fedora 15"}, + 56 => + {'id' => 56, + 'status' => "ACTIVE", + 'updated' => "2010-09-17T07:12:56-05:00", + 'name' => "Windows Server 2008 SP2 x86 - MSSQL2K8R2"}, + 114 => + {'id' => 114, + 'status' => "ACTIVE", + 'updated' => "2011-08-17T05:11:30-05:00", + 'name' => "CentOS 5.6"}, + 86 => + {'id' => 86, + 'status' => "ACTIVE", + 'updated' => "2010-09-17T07:19:20-05:00", + 'name' => "Windows Server 2008 R2 x64 - MSSQL2K8R2"}, + 115 => + {'id' => 115, + 'status' => "ACTIVE", + 'updated' => "2011-08-17T05:11:30-05:00", + 'name' => "Ubuntu 11.04"}, + 103 => + {'id' => 103, + 'status' => "ACTIVE", + 'updated' => "2011-08-17T05:11:30-05:00", + 'name' => "Debian 5 (Lenny)"}, + 104 => + {'id' => 104, + 'status' => "ACTIVE", + 'updated' => "2011-08-17T05:11:30-05:00", + 'name' => "Debian 6 (Squeeze)"}, + 118 => + {'id' => 118, + 'status' => "ACTIVE", + 'updated' => "2011-08-17T05:11:30-05:00", + 'name' => "CentOS 6.0"} + } + } + end + end + + def self.reset + @data = nil + end + + def initialize(options={}) + @rackspace_username = options[:rackspace_username] + end + + def data + self.class.data[@rackspace_username] + end + + def reset_data + self.class.data.delete(@rackspace_username) + end + end + + class Real < Fog::Rackspace::Service + def initialize(options={}) + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + @rackspace_auth_url = options[:rackspace_auth_url] + @rackspace_servicenet = options[:rackspace_servicenet] + @rackspace_auth_token = options[:rackspace_auth_token] + @rackspace_endpoint = Fog::Rackspace.normalize_url(options[:rackspace_compute_v1_url] || options[:rackspace_management_url]) + @connection_options = options[:connection_options] || {} + authenticate + Excon.defaults[:ssl_verify_peer] = false if service_net? + @persistent = options[:persistent] || false + @connection = Fog::Core::Connection.new(endpoint_uri.to_s, @persistent, @connection_options) + end + + def reload + @connection.reset + end + + def request(params, parse_json = true) + super + rescue Excon::Errors::NotFound => error + raise NotFound.slurp(error, self) + rescue Excon::Errors::BadRequest => error + raise BadRequest.slurp(error, self) + rescue Excon::Errors::InternalServerError => error + raise InternalServerError.slurp(error, self) + rescue Excon::Errors::HTTPStatusError => error + raise ServiceError.slurp(error, self) + end + + def service_net? + @rackspace_servicenet == true + end + + def authenticate(options={}) + super({ + :rackspace_api_key => @rackspace_api_key, + :rackspace_username => @rackspace_username, + :rackspace_auth_url => @rackspace_auth_url, + :connection_options => @connection_options + }) + end + + def service_name + :cloudServers + end + + def region + @rackspace_region + end + + def endpoint_uri(service_endpoint_url=nil) + return @uri if @uri + super(@rackspace_endpoint || service_endpoint_url, :rackspace_compute_v1_url) + end + + private + + def deprecation_warnings(options) + Fog::Logger.deprecation("The :rackspace_management_url option is deprecated. Please use :rackspace_compute_v1_url for custom endpoints") if options[:rackspace_management_url] + end + + def authenticate_v1(options) + credentials = Fog::Rackspace.authenticate(options, @connection_options) + endpoint_uri credentials['X-Server-Management-Url'] + @auth_token = credentials['X-Auth-Token'] + end + end + end + end +end diff --git a/lib/fog/rackspace/compute_v2.rb b/lib/fog/rackspace/compute_v2.rb new file mode 100644 index 000000000..ca052c2f5 --- /dev/null +++ b/lib/fog/rackspace/compute_v2.rb @@ -0,0 +1,250 @@ +require 'fog/rackspace/core' + +module Fog + module Compute + class RackspaceV2 < Fog::Service + include Fog::Rackspace::Errors + + class ServiceError < Fog::Rackspace::Errors::ServiceError; end + class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end + class BadRequest < Fog::Rackspace::Errors::BadRequest; end + + class InvalidStateException < ::RuntimeError + attr_reader :desired_state + attr_reader :current_state + + def initialize(desired_state, current_state) + @desired_state = desired_state + @current_state = current_state + end + end + + class InvalidServerStateException < InvalidStateException + def to_s + "Server should have transitioned to '#{desired_state}' not '#{current_state}'" + end + end + + class InvalidImageStateException < InvalidStateException + def to_s + "Image should have transitioned to '#{desired_state}' not '#{current_state}'" + end + end + + DFW_ENDPOINT = 'https://dfw.servers.api.rackspacecloud.com/v2' + ORD_ENDPOINT = 'https://ord.servers.api.rackspacecloud.com/v2' + LON_ENDPOINT = 'https://lon.servers.api.rackspacecloud.com/v2' + + requires :rackspace_username, :rackspace_api_key + recognizes :rackspace_endpoint + recognizes :rackspace_auth_url + recognizes :rackspace_auth_token + recognizes :rackspace_region + recognizes :rackspace_compute_url + + model_path 'fog/rackspace/models/compute_v2' + + model :server + collection :servers + + model :flavor + collection :flavors + + model :image + collection :images + + model :attachment + collection :attachments + + model :network + collection :networks + + model :key_pair + collection :key_pairs + + model :virtual_interface + collection :virtual_interfaces + + request_path 'fog/rackspace/requests/compute_v2' + request :list_servers + request :get_server + request :create_server + request :update_server + request :delete_server + request :change_server_password + request :reboot_server + request :rebuild_server + request :resize_server + request :confirm_resize_server + request :revert_resize_server + request :rescue_server + request :unrescue_server + request :list_addresses + request :list_addresses_by_network + + request :create_image + request :list_images + request :list_images_detail + request :get_image + request :delete_image + + request :list_flavors + request :list_flavors_detail + request :get_flavor + + request :attach_volume + request :get_attachment + request :list_attachments + request :delete_attachment + + request :list_metadata + request :set_metadata + request :update_metadata + request :get_metadata_item + request :set_metadata_item + request :delete_metadata_item + + request :list_networks + request :get_network + request :create_network + request :delete_network + + request :list_keypairs + request :create_keypair + request :delete_keypair + request :get_keypair + + request :list_virtual_interfaces + request :create_virtual_interface + request :delete_virtual_interface + + class Mock < Fog::Rackspace::Service + include Fog::Rackspace::MockData + + def initialize(options) + @rackspace_api_key = options[:rackspace_api_key] + end + + def request(params) + Fog::Mock.not_implemented + end + + def response(params={}) + body = params[:body] || {} + status = params[:status] || 200 + headers = params[:headers] || {} + + response = Excon::Response.new(:body => body, :headers => headers, :status => status) + if params.key?(:expects) && ![*params[:expects]].include?(response.status) + raise(Excon::Errors.status_error(params, response)) + else response + end + end + end + + class Real < Fog::Rackspace::Service + def initialize(options = {}) + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + @rackspace_auth_url = options[:rackspace_auth_url] + setup_custom_endpoint(options) + @rackspace_must_reauthenticate = false + @connection_options = options[:connection_options] || {} + + authenticate + + deprecation_warnings(options) + + @persistent = options[:persistent] || false + @connection = Fog::Core::Connection.new(endpoint_uri.to_s, @persistent, @connection_options) + end + + def request(params, parse_json = true) + super + rescue Excon::Errors::NotFound => error + raise NotFound.slurp(error, self) + rescue Excon::Errors::BadRequest => error + raise BadRequest.slurp(error, self) + rescue Excon::Errors::InternalServerError => error + raise InternalServerError.slurp(error, self) + rescue Excon::Errors::HTTPStatusError => error + raise ServiceError.slurp(error, self) + end + + def authenticate(options={}) + super({ + :rackspace_api_key => @rackspace_api_key, + :rackspace_username => @rackspace_username, + :rackspace_auth_url => @rackspace_auth_url, + :connection_options => @connection_options + }) + end + + def service_name + :cloudServersOpenStack + end + + def request_id_header + "x-compute-request-id" + end + + def region + @rackspace_region + end + + def endpoint_uri(service_endpoint_url=nil) + @uri = super(@rackspace_endpoint || service_endpoint_url, :rackspace_compute_url) + end + + private + + def setup_custom_endpoint(options) + @rackspace_endpoint = Fog::Rackspace.normalize_url(options[:rackspace_compute_url] || options[:rackspace_endpoint]) + + if v2_authentication? + case @rackspace_endpoint + when DFW_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :dfw + when ORD_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :ord + when LON_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :lon + else + # we are actually using a custom endpoint + @rackspace_region = options[:rackspace_region] + end + else + #if we are using auth1 and the endpoint is not set, default to DFW_ENDPOINT for historical reasons + @rackspace_endpoint ||= DFW_ENDPOINT + end + end + + def deprecation_warnings(options) + Fog::Logger.deprecation("The :rackspace_endpoint option is deprecated. Please use :rackspace_compute_url for custom endpoints") if options[:rackspace_endpoint] + + if [DFW_ENDPOINT, ORD_ENDPOINT, LON_ENDPOINT].include?(@rackspace_endpoint) && v2_authentication? + regions = @identity_service.service_catalog.display_service_regions(service_name) + Fog::Logger.deprecation("Please specify region using :rackspace_region rather than :rackspace_endpoint. Valid regions for :rackspace_region are #{regions}.") + end + end + + def append_tenant_v1(credentials) + account_id = credentials['X-Server-Management-Url'].match(/.*\/([\d]+)$/)[1] + + endpoint = @rackspace_endpoint || credentials['X-Server-Management-Url'] || DFW_ENDPOINT + @uri = URI.parse(endpoint) + @uri.path = "#{@uri.path}/#{account_id}" + end + + def authenticate_v1(options) + credentials = Fog::Rackspace.authenticate(options, @connection_options) + append_tenant_v1 credentials + @auth_token = credentials['X-Auth-Token'] + end + end + end + end +end diff --git a/lib/fog/rackspace/core.rb b/lib/fog/rackspace/core.rb new file mode 100644 index 000000000..3b1830c3b --- /dev/null +++ b/lib/fog/rackspace/core.rb @@ -0,0 +1,147 @@ +require 'fog/core' +require 'fog/json' +require 'fog/rackspace/mock_data' +require 'fog/rackspace/service' +require 'fog/rackspace/errors' + +module Fog + module Rackspace + extend Fog::Provider + + US_AUTH_ENDPOINT = 'https://identity.api.rackspacecloud.com/v2.0' unless defined? US_AUTH_ENDPOINT + UK_AUTH_ENDPOINT = 'https://lon.identity.api.rackspacecloud.com/v2.0' unless defined? UK_AUTH_ENDPOINT + + module Errors + class ServiceError < Fog::Errors::Error + attr_reader :response_data, :status_code, :transaction_id + + def to_s + status = status_code ? "HTTP #{status_code}" : "HTTP " + "[#{status} | #{transaction_id}] #{super}" + end + + def self.slurp(error, service=nil) + data = nil + message = nil + status_code = nil + + if error.response + status_code = error.response.status + unless error.response.body.empty? + begin + data = Fog::JSON.decode(error.response.body) + message = extract_message(data) + rescue => e + Fog::Logger.warning("Received exception '#{e}' while decoding>> #{error.response.body}") + message = error.response.body + data = error.response.body + end + end + end + + new_error = super(error, message) + new_error.instance_variable_set(:@response_data, data) + new_error.instance_variable_set(:@status_code, status_code) + new_error.set_transaction_id(error, service) + new_error + end + + def set_transaction_id(error, service) + return unless service && service.respond_to?(:request_id_header) && error.response + @transaction_id = error.response.headers[service.request_id_header] + end + + def self.extract_message(data) + if data.is_a?(Hash) + message = data.values.first['message'] if data.values.first.is_a?(Hash) + message ||= data['message'] + end + message || data.inspect + end + end + + class InternalServerError < ServiceError; end + class Conflict < ServiceError; end + class ServiceUnavailable < ServiceError; end + class MethodNotAllowed < ServiceError; end + class BadRequest < ServiceError + attr_reader :validation_errors + + def to_s + "#{super} - #{validation_errors}" + end + + def self.slurp(error, service=nil) + new_error = super(error) + unless new_error.response_data.nil? or new_error.response_data['badRequest'].nil? + new_error.instance_variable_set(:@validation_errors, new_error.response_data['badRequest']['validationErrors']) + end + + status_code = error.response ? error.response.status : nil + new_error.instance_variable_set(:@status_code, status_code) + new_error.set_transaction_id(error, service) + new_error + end + end + end + + service(:auto_scale, 'AutoScale') + service(:block_storage, 'BlockStorage') + service(:cdn, 'CDN') + service(:compute, 'Compute') + service(:compute_v2, 'Compute v2') + service(:dns, 'DNS') + service(:storage, 'Storage') + service(:load_balancers, 'LoadBalancers') + service(:identity, 'Identity') + service(:databases, 'Databases') + service(:monitoring, 'Monitoring') + service(:queues, 'Queues') + service(:networking, 'Networking') + + def self.authenticate(options, connection_options = {}) + rackspace_auth_url = options[:rackspace_auth_url] + rackspace_auth_url ||= options[:rackspace_endpoint] == Fog::Compute::RackspaceV2::LON_ENDPOINT ? UK_AUTH_ENDPOINT : US_AUTH_ENDPOINT + url = rackspace_auth_url.match(/^https?:/) ? \ + rackspace_auth_url : 'https://' + rackspace_auth_url + uri = URI.parse(url) + connection = Fog::Core::Connection.new(url, false, connection_options) + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + response = connection.request({ + :expects => [200, 204], + :headers => { + 'X-Auth-Key' => @rackspace_api_key, + 'X-Auth-User' => @rackspace_username + }, + :method => 'GET', + :path => (uri.path and not uri.path.empty?) ? uri.path : 'v1.0' + }) + response.headers.reject do |key, value| + !['X-Server-Management-Url', 'X-Storage-Url', 'X-CDN-Management-Url', 'X-Auth-Token'].include?(key) + end + end + + def self.json_response?(response) + return false unless response && response.headers + response.get_header('Content-Type') =~ %r{application/json}i ? true : false + end + + def self.normalize_url(endpoint) + return nil unless endpoint + str = endpoint.chomp " " + str = str.chomp "/" + str.downcase + end + + # CGI.escape, but without special treatment on spaces + def self.escape(str,extra_exclude_chars = '') + # '-' is a special character inside a regex class so it must be first or last. + # Add extra excludes before the final '-' so it always remains trailing, otherwise + # an unwanted range is created by mistake. + str.gsub(/([^a-zA-Z0-9_.#{extra_exclude_chars}-]+)/) do + '%' + $1.unpack('H2' * $1.bytesize).join('%').upcase + end + end + end +end diff --git a/lib/fog/rackspace/databases.rb b/lib/fog/rackspace/databases.rb new file mode 100644 index 000000000..d78913b02 --- /dev/null +++ b/lib/fog/rackspace/databases.rb @@ -0,0 +1,164 @@ +require 'fog/rackspace/core' + +module Fog + module Rackspace + class Databases < Fog::Service + include Fog::Rackspace::Errors + + class ServiceError < Fog::Rackspace::Errors::ServiceError; end + class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end + class BadRequest < Fog::Rackspace::Errors::BadRequest; end + + DFW_ENDPOINT = 'https://dfw.databases.api.rackspacecloud.com/v1.0' + LON_ENDPOINT = 'https://lon.databases.api.rackspacecloud.com/v1.0' + ORD_ENDPOINT = 'https://ord.databases.api.rackspacecloud.com/v1.0' + + requires :rackspace_api_key, :rackspace_username + recognizes :rackspace_auth_url + recognizes :rackspace_auth_token + recognizes :rackspace_endpoint + recognizes :rackspace_region + recognizes :rackspace_database_url + + model_path 'fog/rackspace/models/databases' + model :flavor + collection :flavors + model :instance + collection :instances + model :database + collection :databases + model :user + collection :users + + request_path 'fog/rackspace/requests/databases' + request :list_flavors + request :get_flavor + + request :list_instances + request :get_instance + request :create_instance + request :delete_instance + request :check_root_user + request :enable_root_user + request :restart_instance + request :resize_instance + request :resize_instance_volume + + request :list_databases + request :create_database + request :delete_database + + request :list_users + request :create_user + request :delete_user + request :grant_user_access + request :revoke_user_access + + class Mock < Fog::Rackspace::Service + def request(params) + Fog::Mock.not_implemented + end + end + + class Real < Fog::Rackspace::Service + def service_name + :cloudDatabases + end + + def region + @rackspace_region + end + + def initialize(options = {}) + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + @rackspace_auth_url = options[:rackspace_auth_url] + @rackspace_must_reauthenticate = false + @connection_options = options[:connection_options] || {} + setup_custom_endpoint(options) + + authenticate + + deprecation_warnings(options) + + @persistent = options[:persistent] || false + @connection = Fog::Core::Connection.new(endpoint_uri.to_s, @persistent, @connection_options) + end + + def request(params, parse_json = true) + super + rescue Excon::Errors::NotFound => error + raise NotFound.slurp(error, self) + rescue Excon::Errors::BadRequest => error + raise BadRequest.slurp(error, self) + rescue Excon::Errors::InternalServerError => error + raise InternalServerError.slurp(error, self) + rescue Excon::Errors::HTTPStatusError => error + raise ServiceError.slurp(error, self) + end + + def endpoint_uri(service_endpoint_url=nil) + @uri = super(@rackspace_endpoint || service_endpoint_url, :rackspace_database_url) + end + + def authenticate(options={}) + super({ + :rackspace_api_key => @rackspace_api_key, + :rackspace_username => @rackspace_username, + :rackspace_auth_url => @rackspace_auth_url, + :connection_options => @connection_options + }) + end + + private + + def setup_custom_endpoint(options) + @rackspace_endpoint = Fog::Rackspace.normalize_url(options[:rackspace_database_url] || options[:rackspace_endpoint]) + + if v2_authentication? + case @rackspace_endpoint + when DFW_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :dfw + when ORD_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :ord + when LON_ENDPOINT + @rackspace_endpoint = nil + @rackspace_region = :lon + else + # we are actually using a custom endpoint + @rackspace_region = options[:rackspace_region] + end + else + #if we are using auth1 and the endpoint is not set, default to DFW_ENDPOINT for historical reasons + @rackspace_endpoint ||= DFW_ENDPOINT + end + end + + def deprecation_warnings(options) + Fog::Logger.deprecation("The :rackspace_endpoint option is deprecated. Please use :rackspace_database_url for custom endpoints") if options[:rackspace_endpoint] + + if [DFW_ENDPOINT, ORD_ENDPOINT, LON_ENDPOINT].include?(@rackspace_endpoint) && v2_authentication? + regions = @identity_service.service_catalog.display_service_regions(service_name) + Fog::Logger.deprecation("Please specify region using :rackspace_region rather than :rackspace_endpoint. Valid region for :rackspace_region are #{regions}.") + end + end + + def append_tenant_v1(credentials) + account_id = credentials['X-Server-Management-Url'].match(/.*\/([\d]+)$/)[1] + + endpoint = @rackspace_endpoint || credentials['X-Server-Management-Url'] || DFW_ENDPOINT + @uri = URI.parse(endpoint) + @uri.path = "#{@uri.path}/#{account_id}" + end + + def authenticate_v1(options) + credentials = Fog::Rackspace.authenticate(options, @connection_options) + append_tenant_v1 credentials + @auth_token = credentials['X-Auth-Token'] + end + end + end + end +end diff --git a/lib/fog/rackspace/dns.rb b/lib/fog/rackspace/dns.rb new file mode 100644 index 000000000..10e6eb249 --- /dev/null +++ b/lib/fog/rackspace/dns.rb @@ -0,0 +1,172 @@ +require 'fog/rackspace/core' + +module Fog + module DNS + class Rackspace < Fog::Service + include Fog::Rackspace::Errors + + class ServiceError < Fog::Rackspace::Errors::ServiceError; end + class InternalServerError < Fog::Rackspace::Errors::InternalServerError; end + class BadRequest < Fog::Rackspace::Errors::BadRequest; end + class Conflict < Fog::Rackspace::Errors::Conflict; end + class ServiceUnavailable < Fog::Rackspace::Errors::ServiceUnavailable; end + + class CallbackError < Fog::Errors::Error + attr_reader :response, :message, :details + def initialize(response) + @response = response + @message = response.body['error']['message'] + @details = response.body['error']['details'] + end + end + + US_ENDPOINT = 'https://dns.api.rackspacecloud.com/v1.0' + UK_ENDPOINT = 'https://lon.dns.api.rackspacecloud.com/v1.0' + + requires :rackspace_api_key, :rackspace_username + recognizes :rackspace_auth_url, :rackspace_auth_token, :rackspace_dns_endpoint, :rackspace_dns_url, :rackspace_region + + model_path 'fog/rackspace/models/dns' + model :record + collection :records + model :zone + collection :zones + + request_path 'fog/rackspace/requests/dns' + #TODO - Import/Export, modify multiple domains, modify multiple records + request :callback + request :list_domains + request :list_domain_details + request :modify_domain + request :create_domains + request :remove_domain + request :remove_domains + request :list_subdomains + request :list_records + request :list_record_details + request :modify_record + request :remove_record + request :remove_records + request :add_records + + class Mock < Fog::Rackspace::Service + def initialize(options={}) + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + @rackspace_auth_url = options[:rackspace_auth_url] + @connection_options = options[:connection_options] || {} + end + + def self.data + @data ||= { + } + end + + def self.reset + @data = nil + end + + def data + self.class.data + end + + def reset_data + self.class.reset + end + end + + class Real < Fog::Rackspace::Service + def service_name + :cloudDNS + end + + def region + #Note: DNS does not currently support multiple regions + @rackspace_region + end + + def initialize(options={}) + @rackspace_api_key = options[:rackspace_api_key] + @rackspace_username = options[:rackspace_username] + @rackspace_auth_url = options[:rackspace_auth_url] + @connection_options = options[:connection_options] || {} + @rackspace_endpoint = Fog::Rackspace.normalize_url(options[:rackspace_dns_url] || options[:rackspace_dns_endpoint]) + @rackspace_region = options[:rackspace_region] + + authenticate + + deprecation_warnings(options) + + @persistent = options[:persistent] || false + @connection = Fog::Core::Connection.new(endpoint_uri.to_s, @persistent, @connection_options) + end + + def endpoint_uri(service_endpoint_url=nil) + @uri = super(@rackspace_endpoint || service_endpoint_url, :rackspace_dns_url) + end + + private + + def request(params, parse_json = true) + super + rescue Excon::Errors::NotFound => error + raise NotFound.slurp(error, self) + rescue Excon::Errors::BadRequest => error + raise BadRequest.slurp(error, self) + rescue Excon::Errors::InternalServerError => error + raise InternalServerError.slurp(error, self) + rescue Excon::Errors::ServiceUnavailable => error + raise ServiceUnavailable.slurp(error, self) + rescue Excon::Errors::Conflict => error + raise Conflict.slurp(error, self) + rescue Excon::Errors::HTTPStatusError => error + raise ServiceError.slurp(error, self) + end + + def array_to_query_string(arr) + return "" unless arr + query_array = arr.map do | k, v | + val_str = v.is_a?(Array) ? v.join(",") : v.to_s + "#{k}=#{val_str}" + end + + query_array.join('&') + end + + def validate_path_fragment(name, fragment) + if fragment.nil? or fragment.to_s.empty? + raise ArgumentError.new("#{name} cannot be null or empty") + end + end + + private + + def deprecation_warnings(options) + Fog::Logger.deprecation("The :rackspace_dns_endpoint option is deprecated. Please use :rackspace_dns_url for custom endpoints") if options[:rackspace_dns_endpoint] + end + + def setup_endpoint(credentials) + account_id = credentials['X-Server-Management-Url'].match(/.*\/([\d]+)$/)[1] + + @uri = URI.parse(@rackspace_endpoint || US_ENDPOINT) + @uri.path = "#{@uri.path}/#{account_id}" + end + + def authenticate_v1(options) + credentials = Fog::Rackspace.authenticate(options, @connection_options) + setup_endpoint credentials + @auth_token = credentials['X-Auth-Token'] + end + + def authenticate(options={}) + super({ + :rackspace_api_key => @rackspace_api_key, + :rackspace_username => @rackspace_username, + :rackspace_auth_url => @rackspace_auth_url, + :connection_options => @connection_options + }) + end + end + end + end +end diff --git a/lib/fog/rackspace/docs/auto_scale.md b/lib/fog/rackspace/docs/auto_scale.md new file mode 100644 index 000000000..f8a18e6b4 --- /dev/null +++ b/lib/fog/rackspace/docs/auto_scale.md @@ -0,0 +1,503 @@ +#Auto Scale (AutoScale) + +This document explains how to get started using Auto Scale with Fog. It assumes you have read the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +## Basic Concepts + +Auto Scale is a service that enables you to scale your application by adding or removing servers based on monitoring events, a schedule, or arbitrary webhooks. + +Auto Scale functions by linking three services: + +* Monitoring (such as Monitoring as a Service) +* Auto Scale +* Servers and Load Balancers + + +## Workflow + +A scaling group is monitored by Rackspace Cloud Monitoring. When Monitoring triggers an alarm for high utilization within the Autoscaling group, a webhook is triggered. The webhook calls the Auto Scale service, which consults a policy in accordance with the webhook. The policy determines how many additional Cloud Servers should be added or removed in accordance with the alarm. + +Alarms may trigger scaling up or scaling down. Scale-down events always remove the oldest server in the group. + +Cooldowns allow you to ensure that you don't scale up or down too fast. When a scaling policy runs, both the scaling policy cooldown and the group cooldown start. Any additional requests to the group are discarded while the group cooldown is active. Any additional requests to the specific policy are discarded when the policy cooldown is active. + +It is important to remember that Auto Scale does not configure anything within a server. This means that all images should be self-provisioning. It is up to you to make sure that your services are configured to function properly when the server is started. We recommend using something like Chef, Salt, or Puppet. + + +## Starting irb console + +Start by executing the following command: + + irb + +Once `irb` has launched you need to require the Fog library. + +If using Ruby 1.8.x execute: + + require 'rubygems' + require 'fog' + +If using Ruby 1.9.x execute: + + require 'fog' + +## Create Service + +Next, create a connection to Auto Scale: + +Using a US-based account: + + service = Fog::Rackspace::AutoScale.new ( + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_region => :ord, + :connection_options => {} # Optional + ) + +Using a UK-based account: + + service = Fog::Rackspace::AutoScale.new ( + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT, + :rackspace_region => :lon, + :connection_options => {} # Optional + ) + +To learn more about obtaining cloud credentials refer to the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +By default `Fog::Rackspace::AutoScale` will authenticate against the US authentication endpoint. You can specify alternative authentication endpoints using the key `:rackspace_auth_url`. Please refer to [Alternate Authentication Endpoints](http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Endpoints-d1e180.html) for a list of alternative Rackspace authentication endpoints. + +Alternative regions are specified using the key `:rackspace_region `. A list of regions available for Auto Scale can be found by executing the following: + + identity_service = Fog::Identity.new({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT # Not specified for US Cloud + }) + + identity_service.service_catalog.display_service_regions :autoscale + +Rackspace Private Cloud installations can skip specifying a region and directly specify their custom service endpoints using the key `:rackspace_auto_scale_url`. + + +**Note**: A`Fog::Rackspace::AutoScale` instance is needed for the desired region. + +### Optional Connection Parameters + +Fog supports passing additional connection parameters to its underlying HTTP library (Excon) using the `:connection_options` parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:connect_timeoutConnection timeout (default: 60 seconds)
:read_timeoutRead timeout for connection (default: 60 seconds)
:write_timeoutWrite timeout for connection (default: 60 seconds)
:proxyProxy for HTTP and HTTPS connections
:ssl_ca_pathPath to SSL certificate authorities
:ssl_ca_fileSSL certificate authority file
:ssl_verify_peerSSL verify peer (default: true)
+ + +## Fog Abstractions + +Fog provides both a **model** and **request** abstraction. The request abstraction provides the most efficient interface and the model abstraction wraps the request abstraction to provide a convenient `ActiveModel`-like interface. + +### Request Layer + +The request abstraction maps directly to the [Auto Scale API](http://docs.rackspace.com//cas/api/v1.0/autoscale-devguide/content/API_Operations.html). It provides the most efficient interface to the Rackspace Open Cloud. + +To see a list of requests supported by the service: + + service.requests + +This returns: + + :list_groups, :create_group, :get_group, :delete_group, :get_group_state, :pause_group_state, :resume_group_state, :get_group_config, :update_group_config, :get_launch_config, :update_launch_config, :list_policies, :create_policy, :get_policy, :update_policy, :delete_policy, :execute_policy, :execute_anonymous_webhook, :get_webhook, :list_webhooks, :create_webhook, :update_webhook, :delete_webhook + + +#### Example Request + +To request a list of Auto Scale groups: + + response = service.list_groups + +This returns in the following `Excon::Response`: + + #{"groups_links"=>[], "groups"=>[{"paused"=>false, "desiredCapacity"=>0, "links"=>[{"href"=>"https://ord.autoscale.api.rackspacecloud.com/v1.0/555/groups/b45e6107-26ca-4a93-869d-46bf20005df3/", "rel"=>"self"}], "active"=>[], "pendingCapacity"=>0, "activeCapacity"=>0, "id"=>"b45e6107-26ca-4a93-869d-46bf20005df3", "name"=>"fog-scailing-group"}]}, :headers=>{"Content-Type"=>"application/json", "Via"=>"1.1 Repose (Repose/2.8.2)", "x-response-id"=>"4c2a8f70-a7da-479a-bf69-6882b5b6346e", "Date"=>"Fri, 27 Sep 2013 15:38:10 GMT", "Transfer-Encoding"=>"chunked", "Server"=>"Jetty(8.0.y.z-SNAPSHOT)"}, :status=>200, :remote_ip=>"162.209.41.103"}, @body="{\"groups_links\": [], \"groups\": [{\"paused\": false, \"desiredCapacity\": 0, \"links\": [{\"href\": \"https://ord.autoscale.api.rackspacecloud.com/v1.0/555/groups/b45e6107-26ca-4a93-869d-46bf20005df3/\", \"rel\": \"self\"}], \"active\": [], \"pendingCapacity\": 0, \"activeCapacity\": 0, \"id\": \"b45e6107-26ca-4a93-869d-46bf20005df3\", \"name\": \"fog-scailing-group\"}]}", @headers={"Content-Type"=>"application/json", "Via"=>"1.1 Repose (Repose/2.8.2)", "x-response-id"=>"4c2a8f70-a7da-479a-bf69-6882b5b6346e", "Date"=>"Fri, 27 Sep 2013 15:38:10 GMT", "Transfer-Encoding"=>"chunked", "Server"=>"Jetty(8.0.y.z-SNAPSHOT)"}, @status=200, @remote_ip="162.209.41.103"> + +To view the status of the response: + + response.status + +**Note**: Fog is aware of valid HTTP response statuses for each request type. If an unexpected HTTP response status occurs, Fog will raise an exception. + +To view response body: + + response.body + +returns: + + {"groups_links"=>[], "groups"=>[{"paused"=>false, "desiredCapacity"=>0, "links"=>[{"href"=>"https://ord.autoscale.api.rackspacecloud.com/v1.0/555/groups/b45e6107-26ca-4a93-869d-46bf20005df3/", "rel"=>"self"}], "active"=>[], "pendingCapacity"=>0, "activeCapacity"=>0, "id"=>"b45e6107-26ca-4a93-869d-46bf20005df3", "name"=>"fog-scailing-group"}]} + + +To learn more about Auto Scale request methods refer to [rdoc](http://rubydoc.info/gems/fog/Fog/Rackspace/AutoScale/Real). To learn more about Excon refer to [Excon GitHub repo](https://github.com/geemus/excon). + +### Model Layer + +Fog models behave in a manner similar to `ActiveModel`. Models will generally respond to `create`, `save`, `persisted?`, `destroy`, `reload` and `attributes` methods. Additionally, fog will automatically create attribute accessors. + +Here is a summary of common model methods: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
create + Accepts hash of attributes and creates object.
+ Note: creation is a non-blocking call and you will be required to wait for a valid state before using resulting object. +
saveSaves object.
+ Note: not all objects support updating object.
persisted?Returns true if the object has been persisted.
destroy + Destroys object.
+ Note: this is a non-blocking call and object deletion might not be instantaneous. +
reloadUpdates object with latest state from service.
ready?Returns true if object is in a ready state and able to perform actions. This method will raise an exception if object is in an error state.
attributesReturns a hash containing the list of model attributes and values.
identity + Returns the identity of the object.
+ Note: This might not always be equal to object.id. +
wait_forThis method periodically reloads model and then yields to specified block until block returns true or a timeout occurs.
+ +The remainder of this document details the model abstraction. + +## The Scaling Group + +* The **Scaling Group** is the basic unit of automatic scaling. It determines the minimum and maximum number of servers that exist at any time for the group, the cooldown period between scaling events, the configuration for each new server, the load balancer to add these servers to (optional), and any policies that are used for this group. + +### List Scaling Groups + +To retrieve the list of your scaling groups: + + service.groups + +This returns a collection of `Fog::Rackspace::AutoScale::Group` objects: + + "https://ord.autoscale.api.rackspacecloud.com/v1.0/555/groups/b45e6107-26ca-4a93-869d-46bf20005df3/", "rel"=>"self"}] + > + ] + > + +To view the [launch configuration](#launch-configurations) for a group execute the following: + + groups = service.groups + group = group.first + group.launch_config + +This returns a `Fog::Rackspace::AutoScale::LaunchConfig`: + + "https://ord.autoscale.api.rackspacecloud.com/v1.0/5555/groups/b45e6107-26ca-4a93-869d-46bf20005df3/", "rel"=>"self"}] + >, + type="launch_server", + args={"loadBalancers"=>[{"port"=>8080, "loadBalancerId"=>9099}], "server"=>{"name"=>"autoscale_server", "imageRef"=>"0d589460-f177-4b0f-81c1-8ab8903ac7d8", "flavorRef"=>"2", "OS-DCF =>diskConfig"=>"AUTO", "metadata"=>{"build_config"=>"core", "meta_key_1"=>"meta_value_1", "meta_key_2"=>"meta_value_2"}, "networks"=>[{"uuid"=>"11111111-1111-1111-1111-111111111111"}, {"uuid"=>"00000000-0000-0000-0000-000000000000"}], "personality"=>[{"path"=>"/root/.csivh", "contents"=>"VGhpcyBpcyBhIHRlc3QgZmlsZS4="}]}} + > + +### Getting the Current State of a Scaling Group + +It is sometimes helpful to determine what the current state of a scaling group is in terms of whether it is scaling up, scaling down, or stable. + +To see your group's current state execute the following: + + group.state + +This returns the following: + + {"paused"=>false, "desiredCapacity"=>0, "links"=>[{"href"=>"https://ord.autoscale.api.rackspacecloud.com/v1.0/555/groups/b45e6107-26ca-4a93-869d-46bf20005df3/", "rel"=>"self"}], "active"=>[], "pendingCapacity"=>0, "activeCapacity"=>0, "id"=>"b45e6107-26ca-4a93-869d-46bf20005df3", "name"=>"fog-scailing-group"} + +The `active` key holds a list of the IDs of the servers created as part of this scaling group. The `paused` key shows whether or not the scaling group's response to alarms is active or not. There are 3 'capacity'-related keys: `activeCapacity`, `desiredCapacity`, and `pendingCapacity`: + +Key | Represents +---- | ---- +**activeCapacity** | The number of active servers that are part of this scaling group +**desiredCapacity** | The target number of servers for this scaling group, based on the combination of configuration settings and monitoring alarm responses +**pendingCapacity** | The number of servers which are in the process of being created (when positive) or destroyed (when negative). + +### Pausing a Scaling Group's Policies + +To pause a scaling group's execution: + + group.pause + +There is a corresponding `resume` method to resume execution: + + group.resume + +### Creating a Scaling Group + +There are many options available to you when creating a scaling group. In order to ease the burden, a builder is provided. + +To create a scaling group with the builder you first include the builder in your script: + + require 'fog/rackspace/models/auto_scale/group_builder' + +And then use the builder as follows: + + INTERNET = '00000000-0000-0000-0000-000000000000' + SERVICE_NET = '11111111-1111-1111-1111-111111111111' + + attributes = { + :server_name => "testgroup", + :image => my_image, + :flavor => 3, + :networks => [INTERNET, SERVICE_NET], + :personality => [ + { + "path" => "/root/.csivh", + "contents" => "VGhpcyBpcyBhIHRlc3QgZmlsZS4=" + } + ], + :max_entities => 3, + :min_entities => 2, + :cooldown => 600, + :name => "MyScalingGroup", + :metadata => { "created_by" => "autoscale sample script" }, + :load_balancers => { + :port => 80, + :loadBalancerId => 1234 + } + :launch_config_type => :launch_server + } + + group = Fog::Rackspace::AutoScale::GroupBuilder.build(service, attributes) + group.save + +This creates the scaling group with the name `MyScalingGroup`, and returns a `Fog::Rackspace::AutoScale::Group` object representing the new group. Since the `:min_entities` is 2, it immediately creates 2 servers for the group, based on the image whose ID is in the variable `my_image`. When they are created, they are then added to the load balancer whose ID is `1234`, and receive requests on port 80. + +Note that the `:server_name` parameter represents a base string to which Autoscale prepends a 10-character prefix to create a unique name for each server. The prefix always begins with 'as' and is followed by 8 random hex digits and a dash (-). For example, if you set the server_name to 'testgroup', and the scaling group creates 3 servers, their names would look like these: + + as5defddd4-testgroup + as92e512fe-testgroup + asedcf7587-testgroup + +**Note**: You will see need to add policies to trigger auto scaling operations. See [Policies Section](#policies) for more information. + +#### Parameters +Parameter | Required | Default | Notes +---- | ---- | ---- | ---- +**:name** | yes | | +**:cooldown** | yes | | Period in seconds after a scaling event in which further events are ignored +**:min_entities** | yes | | +**:max_entities** | yes | | +**:launch_config_type** | yes | | Only option currently is`:launch_server` +**:flavor** | yes | | Flavor to use for each server that is launched. This can be a `Fog::Compute::RackspaceV2::Flavor` or an ID. +**:server_name** | yes | | The base name for servers created by Autoscale. +**:image** | yes | | This can be a `Fog::Compute::RackspaceV2::Image` or an id. This is the image that all new servers are created from. +**:disk_config** | no | MANUAL | Determines if the server's disk is partitioned to the full size of the flavor ('AUTO') or just to the size of the image ('MANUAL'). +**:server_metadata** | no | | Arbitrary key-value pairs you want to associate with your servers. +**:personality** | no | | Small text files that are created on the new servers. _Personality_ is discussed in the [Rackspace Cloud Servers documentation](http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Personality-d1e2543.html) +**:networks** | no | | Any array of networks to which you want to attach new servers. See the [Create Servers documentation](http://docs.rackspace.com/servers/api/v2/cs-devguide/content/CreateServers.html) for standard network IDs. +**:load_balancers** | no | | Either a hash of {:port, :loadBalancerId} or a `Fog::Rackspace::LoadBalancers::LoadBalancer` object. + +### Updating a Scaling Configuration Group + +A group's scaling configuration can be updated via the `Fog::Rackspace::AutoScale::GroupConfig` object. You can retrieve this object by executing the following: + + group_config = group.group_config + +Available options on `group_config` include `:max_entities`, `:name`, `:cooldown`, `:min_entities`, `:metadata`. To update a scaling group, pass one or more of these as keyword arguments. For example, to change the cooldown period to 2 minutes and increase the maximum entities to 16, you call: + + group_config.cooldown = 120 + group_config.max_entities = 16 + group_config.save + +**Note**: If you pass any metadata values in this call, it must be the full set of metadata for the scaling group, since the underlying API call **overwrites** any existing metadata. + +### Deleting a Scaling Group + +To remove a scaling group, call its `destroy` method: + + group.destroy + +Note: you cannot delete a scaling group that has active servers in it. You must first delete the servers by setting the `min_entities` and `max_entities` to zero: + + group_config = group.group_config + group_config.min_entities = 0 + group_config.max_entities = 0 + group_config.save + +Once the servers are deleted you can then delete the scaling group. + +## Launch Configurations + +Each scaling group has an associated **launch configuration**. This determines the properties of servers that are created in response to a scaling event. + +The `:server_name` represents a base string to which Autoscale prepends a 10-character prefix. The prefix always begins with 'as' and is followed by 8 random hex digits and a dash (-). For example, if you set the `server_name` to 'testgroup', and the scaling group creates 3 servers, their names would look like these: + + as5defddd4-testgroup + as92e512fe-testgroup + asedcf7587-testgroup + +To retrieve the launch config: + + launch_config = group.launch_config + +The launch configuration contains two attributes `:type` and `:args`. The only launch type currently available for Auto Scale is `:launch_server`. The `args` attribute contains a hash with the launch server configuration options as follows: + + {"server"=>{ + "name"=>"autoscale_server", + "imageRef"=>"66448837-1a58-4bd2-a647-9f3272f36263", + "flavorRef"=>"2", + "networks"=>[{"uuid"=>"00000000-0000-0000-0000-000000000000"}, {"uuid"=>"11111111-1111-1111-1111-111111111111"}], + "personality"=>[{"path"=>"/root/.csivh", "contents"=>"VGhpcyBpcyBhIHRlc3QgZmlsZS4="}], + "OS-DCF =>diskConfig"=>"MANUAL", + "metadata"=>{}}} + +Changes to the args attribute can be saved by executing the `save` method on the `launch_config`. For example if you wanted to change the disk configuration to `AUTO`, you would do the following: + + launch_config.args["server"]["OS-DCF =>diskConfig"] = "AUTO" + launch_config.save + +**Note**: If you pass any metadata values in this call, it must be the full set of metadata for the launch configuration, since the underlying API call **overwrites** any existing metadata. + +## Policies + +When an alarm is triggered in Cloud Monitoring, it calls the webhook associated with a particular policy. The policy is designed to update the scaling group to increase or decrease the number of servers in response to the particular alarm. + +To list the policies for a given scaling group use the following: + + policies = group.policies + +### Creating a Policy + +To add a policy to a scaling group use the following: + + group.policies.create :name => 'Scale by one server', :cooldown => 360, :type => 'webhook', :change => 1 + +#### Parameters +Parameter | Required | Default | Notes +---- | ---- | ---- | ---- +**:name** | yes | | +**:type** | yes | | This can be "webhook", "schedule" or "cloud monitoring" +**:cooldown** | yes | | Period in seconds after a policy execution in which further events are ignored. This is separate from the overall cooldown for the scaling group. +**:change** | no | | Can be positive or negative, which makes this a scale-up or scale-down policy, respectively. If this value is specified you can not specify `:change_percent`. +**:change_percent** | no | | The percentage change to the autoscale group's number of units. If this value is specified you can not specify `:change`. +**:args** | no | | This is used to specify schedule parameters. Please refer to [Policy documentation](http://docs-internal-staging.rackspace.com/cas/api/v1.0/autoscale-devguide/content/POST_createPolicies_v1.0__tenantId__groups__groupId__policies_Policies.html) for more information. + +### Updating a Policy + +You may update a policy at any time, passing in any or all of the above parameters to change that value. For example, to change the cooldown to 60 seconds, and the number of servers to remove to 3, call: + + policy.cooldown = 60 + policy.change = 3 + policy.save + +### Executing a Policy + +You don't need to wait for an alarm to be triggered in Cloud Monitoring in order to execute a particular policy. If desired, you may do so manually by calling the policy's `execute` method: + + policy.execute + +### Deleting a Policy + +To remove a policy, call its `destroy` method: + + policy.destroy + +## Webhooks + +When an alarm is triggered in Cloud Monitoring, it calls the associated webhook, which in turn causes the policy for that webhook to be executed. + +To list the webhooks for a given policy: + + webhooks = policy.webhooks + + +### Creating a Webhook + +To add a webhook to a policy: + + webhook = policy.webhooks.create :name => 'my-webhook' + + +The `:name` parameter is required; the `:metadata` parameter is optional. You can retrieve the webhook by executing: + + webhook.execution_url + +### Updating a Webhook + +You may update a webhook at any time to change either its name or its metadata: + + webhook.name = 'webhook1' + webhook.metadata = { + :owner => 'webteam' + } + webhook.save + +**Note**: If you pass any metadata values in this call, it must be the full set of metadata for the Webhook, since the underlying API call **overwrites** any existing metadata. + +### Deleting a webhook + +When you wish to remove a webhook, call its `destroy` method: + + webhook.destroy diff --git a/lib/fog/rackspace/docs/block_storage.md b/lib/fog/rackspace/docs/block_storage.md new file mode 100644 index 000000000..897a3ea28 --- /dev/null +++ b/lib/fog/rackspace/docs/block_storage.md @@ -0,0 +1,417 @@ +#Cloud Block Storage (BlockStorage) + +This document explains how to get started using Cloud Block Storage with Fog. It assumes you have read the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +## Starting irb console +Start by executing the following command: + + irb + +Once `irb` has launched you need to require the Fog library. + +If using Ruby 1.8.x execute: + + require 'rubygems' + require 'fog' + +If using Ruby 1.9.x execute: + + require 'fog' + +## Create Service + +Next, create a connection to Cloud Block Storage: + +Using a US-based account: + + service = Fog::Rackspace::BlockStorage.new({ + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_region => :ord, # Defaults to :dfw + :connection_options => {} # Optional + }) + +Using a UK-based account: + + service = Fog::Rackspace::BlockStorage.new({ + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT, + :rackspace_region => :lon, + :connection_options => {} # Optional + }) + +To learn more about obtaining cloud credentials refer to the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +By default `Fog::Rackspace::BlockStorage` will authenticate against the US authentication endpoint and connect to the DFW region. You can specify alternative authentication endpoints using the key `:rackspace_auth_url`. Please refer to [Alternate Authentication Endpoints](http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Endpoints-d1e180.html) for a list of alternative Rackspace authentication endpoints. + +Alternative regions are specified using the key `:rackspace_region `. A list of regions available for Cloud Block Storage can be found by executing the following: + + identity_service = Fog::Identity({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT # Not specified for US Cloud + }) + + identity_service.service_catalog.display_service_regions :cloudBlockStorage + +Rackspace Private Cloud installations can skip specifying a region and directly specify their custom service endpoints using the key `:rackspace_block_storage_url`. + +**Note**: A`Fog::Rackspace::BlockStorage` instance is needed for the desired region. + +### Optional Connection Parameters + +Fog supports passing additional connection parameters to its underlying HTTP library (Excon) using the `:connection_options` parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:connect_timeoutConnection timeout (default: 60 seconds)
:read_timeoutRead timeout for connection (default: 60 seconds)
:write_timeoutWrite timeout for connection (default: 60 seconds)
:proxyProxy for HTTP and HTTPS connections
:ssl_ca_pathPath to SSL certificate authorities
:ssl_ca_fileSSL certificate authority file
:ssl_verify_peerSSL verify peer (default: true)
+ + +## Fog Abstractions + +Fog provides both a **model** and **request** abstraction. The request abstraction provides the most efficient interface and the model abstraction wraps the request abstraction to provide a convenient `ActiveModel` like interface. + +### Request Layer + +The request abstraction maps directly to the [Cloud Block Storage API](http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/overview.html). It provides the most efficient interface to the Rackspace Open Cloud. + +To see a list of requests supported by the service: + + service.requests + +This returns: + + :create_volume, :delete_volume, :get_volume, :list_volumes, :get_volume_type, :list_volume_types, :create_snapshot, :delete_snapshot, :get_snapshot, :list_snapshots + + +#### Example Request + +To request a list of volume types: + + response = service.list_volume_types + +This returns in the following `Excon::Response`: + + "Mon, 18 Mar 2013 20:26:03 GMT", "Content-Length"=>"109", "Content-Type"=>"application/json", "X-Compute-Request-Id"=>"req-9c2093d4-8a41-4d8b-a069-114470d1a0dd"}, @data={:status=>200, :headers=>{"Date"=>"Mon, 18 Mar 2013 20:26:03 GMT", "Content-Length"=>"109", "Content-Type"=>"application/json", "X-Compute-Request-Id"=>"req-9c2093d4-8a41-4d8b-a069-114470d1a0dd"}, :remote_ip=>"72.32.164.210", :body=>{"volume_types"=>[{"name"=>"SATA", "id"=>1, "extra_specs"=>{}}, {"name"=>"SSD", "id"=>2, "extra_specs"=>{}}]}}> + +To view the status of the response: + + response.status + +**Note**: Fog is aware of valid HTTP response statuses for each request type. If an unexpected HTTP response status occurs, Fog will raise an exception. + +To view response body: + + response.body + +This will return: + + {"volume_types"=>[{"name"=>"SATA", "id"=>1, "extra_specs"=>{}}, {"name"=>"SSD", "id"=>2, "extra_specs"=>{}}]} + + +To learn more about Cloud Block Storage request methods refer to [rdoc](http://rubydoc.info/gems/fog/Fog/Rackspace/BlockStorage/Real). To learn more about Excon refer to [Excon GitHub repo](https://github.com/geemus/excon). + +### Model Layer + +Fog models behave in a manner similar to `ActiveModel`. Models will generally respond to `create`, `save`, `persisted?`, `destroy`, `reload` and `attributes` methods. Additionally, fog will automatically create attribute accessors. + +Here is a summary of common model methods: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
create + Accepts hash of attributes and creates object.
+ Note: creation is a non-blocking call and you will be required to wait for a valid state before using resulting object. +
saveSaves object.
+ Note: not all objects support updating object.
persisted?Returns true if the object has been persisted.
destroy + Destroys object.
+ Note: this is a non-blocking call and object deletion might not be instantaneous. +
reloadUpdates object with latest state from service.
ready?Returns true if object is in a ready state and able to perform actions. This method will raise an exception if object is in an error state.
attributesReturns a hash containing the list of model attributes and values.
identity + Returns the identity of the object.
+ Note: This might not always be equal to object.id. +
wait_forThis method periodically reloads model and then yields to specified block until block returns true or a timeout occurs.
+ +The remainder of this document details the model abstraction. + + +## List Volume Types + +To retrieve a list of volume types: + + service.volume_types + +This returns a collection of `Fog::Rackspace::BlockStorage::VolumeType` models: + + , + + ] + > + +## List Volumes + +To retrieve a list of volumes: + + service.volumes + +This returns a collection of `Fog::Rackspace::BlockStorage::Volume` models: + + , + + ] + > + +## Get Volume + +To retrieve an individual volume: + + service.volume.get "fog-example" + +This returns a `Fog::Rackspace::BlockStorage::Volume`: + + + +## Create Volume + +To create a volume: + + volume = service.volumes.create(:size => 100, :display_name => 'fog-ssd', :volume_type => 'SSD') + +This will return a `Fog::Rackspace::BlockStorage::Volume`: + + + +**Note**: The `:size` parameter is the only required parameter and is in gigabytes. Volumes must be a minimum of 100 GB. + +### Additional Parameters + +The `create` method also supports the following key values: + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:display_nameThe name of the volume.
:display_descriptionA description of the volume.
:snapshot_idThe optional snapshot from which to create a volume.
:volume_typeThe type of volume to create. Refer to List Volume Types section for valid types. SATA is the default volume type.
+ +## Attach Volume + +Please refer to the [Attach Volume](compute_v2.md#attach-volume) section in the [Next Generation Cloud Serversâ„¢ (compute_v2)](compute_v2.md) documentation. + +## Detach Volume + +Please refer to the [Detach Volume](compute_v2.md#detach-volume) section in the [Next Generation Cloud Serversâ„¢ (compute_v2)](compute_v2.md) documentation. + + +## Delete Volume + +To delete a volume: + + volume.destroy + +**Note**: You cannot delete a volume until all of its dependent snapshots have been deleted. + +## List Snapshots + +To retrieve a list of snapshots: + + service.snapshots + +To retrieve a list of snapshots for a given volume: + + volume.snapshots + +## Create Snapshot + +A snapshot is a point-in-time copy of a volume. Each subsequent snapshot will be the difference between the previous snapshot and the current volume. + +To create a snapshot of a given volume: + + volume.create_snapshot :display_name => 'initial-snapshot' + +**Note**: All writes to the volume should be flushed before creating the snapshot, either by unmounting any file systems on the volume or by detaching the volume. + +### Additional Parameters + +The `create_snapshot` method also supports the following key values: + + + + + + + + + + + + + + + + + + +
KeyDescription
:display_nameThe name of the snapshot.
:display_descriptionA description of the snapshot.
:forceIf set to true, snapshot will be taken even if volume is still mounted.
+ + + +## Delete Snapshot + +To delete a snapshot: + + snapshot.destroy + +## Examples + +Example code using Cloud Block Storage can be found [here](https://github.com/fog/fog/tree/master/lib/fog/rackspace/examples). + +## Additional Resources + +* [fog.io](http://fog.io/) +* [Fog rdoc](http://rubydoc.info/gems/fog/) +* [Fog Github repo](https://github.com/fog/fog) +* [Fog Github Issues](https://github.com/fog/fog/issues) +* [Excon Github repo](https://github.com/geemus/excon) +* [Cloud Block Storage API](http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/index.html) + +## Support and Feedback + +Your feedback is appreciated! If you have specific issues with the **fog** SDK, you should file an [issue via Github](https://github.com/fog/fog/issues). + +For general feedback and support requests, send an email to: . diff --git a/lib/fog/rackspace/docs/compute_v2.md b/lib/fog/rackspace/docs/compute_v2.md new file mode 100644 index 000000000..c71519282 --- /dev/null +++ b/lib/fog/rackspace/docs/compute_v2.md @@ -0,0 +1,719 @@ +#Next Generation Cloud Serversâ„¢ (compute_v2) + +This document explains how to get started using Next Generation Cloud Servers with Fog. It assumes you have read the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +**Note**: Fog also provides an interface to First Gen Cloud Serversâ„¢ (compute). The compute interface is deprecated and should only be used if you need to interact with our first generation cloud. Fog determines the appropriate interface based on the `:version` parameter. See [Create Service](#create-service) section for more information. + +## Starting irb console + +Start by executing the following command: + + irb + +Once `irb` has launched you need to require the Fog library. + +If using Ruby 1.8.x execute: + + require 'rubygems' + require 'fog' + +If using Ruby 1.9.x execute: + + require 'fog' + +## Create Service + +Next, create a connection to the Next Gen Cloud Servers: + +Using a US-based account: + + service = Fog::Compute.new({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :version => :v2, # Use Next Gen Cloud Servers + :rackspace_region => :ord, # Defaults to :dfw + :connection_options => {} # Optional + }) + +Using a UK-based account: + + service = Fog::Compute.new({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :version => :v2, # Use Next Gen Cloud Servers + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT, + :rackspace_region => :lon, + :connection_options => {} # Optional + }) + +To learn more about obtaining cloud credentials refer to the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +By default `Fog::Compute` will authenticate against the US authentication endpoint and connect to the DFW region. You can specify alternative authentication endpoints using the key `:rackspace_auth_url`. Please refer to [Alternate Authentication Endpoints](http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Endpoints-d1e180.html) for a list of alternative Rackspace authentication endpoints. + +Alternative regions are specified using the key `:rackspace_region `. A list of regions available for Cloud Servers can be found by executing the following: + + identity_service = Fog::Identity({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT # Not specified for US Cloud + }) + + identity_service.service_catalog.display_service_regions :cloudServersOpenStack + +Rackspace Private Cloud installations can skip specifying a region and directly specify their custom service endpoints using the key `:rackspace_compute_url`. + +**Note**: A`Fog::Compute` instance is needed for the desired region. + +### Optional Connection Parameters + +Fog supports passing additional connection parameters to its underlying HTTP library (Excon) using the `:connection_options` parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:connect_timeoutConnection timeout (default: 60 seconds)
:read_timeoutRead timeout for connection (default: 60 seconds)
:write_timeoutWrite timeout for connection (default: 60 seconds)
:proxyProxy for HTTP and HTTPS connections
:ssl_ca_pathPath to SSL certificate authorities
:ssl_ca_fileSSL certificate authority file
:ssl_verify_peerSSL verify peer (default: true)
+ + +## Fog Abstractions + +Fog provides both a **model** and **request** abstraction. The request abstraction provides the most efficient interface and the model abstraction wraps the request abstraction to provide a convenient `ActiveModel` like interface. + +### Request Layer + +The request abstraction maps directly to the [Next Gen Cloud Servers API](http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ch_preface.html). It provides the most efficient interface to the Rackspace Open Cloud. + +To see a list of requests supported by the service: + + service.requests + +This returns: + + :list_servers, :get_server, :create_server, :update_server, :delete_server, :change_server_password, :reboot_server, :rebuild_server, :resize_server, :confirm_resize_server, :revert_resize_server, :list_images, :get_image, :list_flavors, :get_flavor, :attach_volume, :get_attachment, :list_attachments, :delete_attachment + + +#### Example Request + +To request a list of flavors: + + response = service.list_flavors + +This returns in the following `Excon::Response`: + + [{"id"=>"2", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/2", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/2", "rel"=>"bookmark"}], "name"=>"512MB Standard Instance"}, {"id"=>"3", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/3", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/3", "rel"=>"bookmark"}], "name"=>"1GB Standard Instance"}, {"id"=>"4", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/4", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/4", "rel"=>"bookmark"}], "name"=>"2GB Standard Instance"}, {"id"=>"5", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/5", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/5", "rel"=>"bookmark"}], "name"=>"4GB Standard Instance"}, {"id"=>"6", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/6", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/6", "rel"=>"bookmark"}], "name"=>"8GB Standard Instance"}, {"id"=>"7", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/7", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/7", "rel"=>"bookmark"}], "name"=>"15GB Standard Instance"}, {"id"=>"8", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/8", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/8", "rel"=>"bookmark"}], "name"=>"30GB Standard Instance"}]}, @headers={"Date"=>"Mon, 21 Jan 2013 16:14:45 GMT", "Content-Length"=>"1697", "Content-Type"=>"application/json", "X-Compute-Request-Id"=>"req-0a1e8532-19b3-4993-8b48-cf2d9efe078c", "Server"=>"Jetty(8.0.y.z-SNAPSHOT)"}, @status=200> + +To view the status of the response: + + response.status + +**Note**: Fog is aware of valid HTTP response statuses for each request type. If an unexpected HTTP response status occurs, Fog will raise an exception. + +To view response body: + + response.body + +This will return: + + {"flavors"=>[{"id"=>"2", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/2", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/2", "rel"=>"bookmark"}], "name"=>"512MB Standard Instance"}, {"id"=>"3", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/3", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/3", "rel"=>"bookmark"}], "name"=>"1GB Standard Instance"}, {"id"=>"4", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/4", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/4", "rel"=>"bookmark"}], "name"=>"2GB Standard Instance"}, {"id"=>"5", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/5", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/5", "rel"=>"bookmark"}], "name"=>"4GB Standard Instance"}, {"id"=>"6", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/6", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/6", "rel"=>"bookmark"}], "name"=>"8GB Standard Instance"}, {"id"=>"7", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/7", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/7", "rel"=>"bookmark"}], "name"=>"15GB Standard Instance"}, {"id"=>"8", "links"=>[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/flavors/8", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/flavors/8", "rel"=>"bookmark"}], "name"=>"30GB Standard Instance"}]} + + +To learn more about Compute request methods refer to [rdoc](http://rubydoc.info/gems/fog/Fog/Compute/Rackspace/Real). To learn more about Excon refer to [Excon GitHub repo](https://github.com/geemus/excon). + +### Model Layer + +Fog models behave in a manner similar to `ActiveModel`. Models will generally respond to `create`, `save`, `persisted?`, `destroy`, `reload` and `attributes` methods. Additionally, fog will automatically create attribute accessors. + +Here is a summary of common model methods: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
create + Accepts hash of attributes and creates object.
+ Note: creation is a non-blocking call and you will be required to wait for a valid state before using resulting object. +
saveSaves object.
+ Note: not all objects support updating object.
persisted?Returns true if the object has been persisted.
destroy + Destroys object.
+ Note: this is a non-blocking call and object deletion might not be instantaneous. +
reloadUpdates object with latest state from service.
ready?Returns true if object is in a ready state and able to perform actions. This method will raise an exception if object is in an error state.
attributesReturns a hash containing the list of model attributes and values.
identity + Returns the identity of the object.
+ Note: This might not always be equal to object.id. +
wait_forThis method periodically reloads model and then yields to specified block until block returns true or a timeout occurs.
+ +The remainder of this document details the model abstraction. + +## List Images + +To retrieve a list of available images: + + service.images + +This returns a collection of `Fog::Compute::RackspaceV2::Image` models: + + "https://ord.servers.api.rackspacecloud.com/v2/772045/images/8a3a9f96-b997-46fd-b7a8-a9e740796ffd", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/images/8a3a9f96-b997-46fd-b7a8-a9e740796ffd", "rel"=>"bookmark"}, {"href"=>"https://ord.images.api.rackspacecloud.com/772045/images/8a3a9f96-b997-46fd-b7a8-a9e740796ffd", "type"=>"application/vnd.openstack.image", "rel"=>"alternate"}] + >, + "https://ord.servers.api.rackspacecloud.com/v2/772045/images/992ba82c-083b-4eed-9c26-c54473686466", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/images/992ba82c-083b-4eed-9c26-c54473686466", "rel"=>"bookmark"}, {"href"=>"https://ord.images.api.rackspacecloud.com/772045/images/992ba82c-083b-4eed-9c26-c54473686466", "type"=>"application/vnd.openstack.image", "rel"=>"alternate"}] + >, + … + +## Get Image + +To retrieve individual image: + + service.images.get "8a3a9f96-b997-46fd-b7a8-a9e740796ffd" + +This returns an `Fog::Compute::RackspaceV2::Image` instance: + + "ubuntu", "com.rackspace__1__visible_core"=>"1", "com.rackspace__1__build_rackconnect"=>"1", "auto_disk_config"=>"True", "com.rackspace__1__options"=>"0", "image_type"=>"base", "org.openstack__1__os_version"=>"12.10", "os_version"=>"12.10", "rax_options"=>"0", "com.rackspace__1__visible_rackconnect"=>"1", "org.openstack__1__os_distro"=>"org.ubuntu", "com.rackspace__1__visible_managed"=>"1", "com.rackspace__1__build_core"=>"1", "arch"=>"x86-64", "os_type"=>"linux", "org.openstack__1__architecture"=>"x64", "com.rackspace__1__build_managed"=>"1"}, + disk_config="AUTO", + links=[{"href"=>"https://ord.servers.api.rackspacecloud.com/v2/772045/images/8a3a9f96-b997-46fd-b7a8-a9e740796ffd", "rel"=>"self"}, {"href"=>"https://ord.servers.api.rackspacecloud.com/772045/images/8a3a9f96-b997-46fd-b7a8-a9e740796ffd", "rel"=>"bookmark"}, {"href"=>"https://ord.images.api.rackspacecloud.com/772045/images/8a3a9f96-b997-46fd-b7a8-a9e740796ffd", "type"=>"application/vnd.openstack.image", "rel"=>"alternate"}] + > + +## List Flavors + +To retrieve a list of available flavors: + + service.flavors + +This returns a collection of `Fog::Compute::RackspaceV2::Flavor` models: + + "https://dfw.servers.api.rackspacecloud.com/v2/772045/flavors/2", "rel"=>"self"}, {"href"=>"https://dfw.servers.api.rackspacecloud.com/772045/flavors/2", "rel"=>"bookmark"}] + >, + "https://dfw.servers.api.rackspacecloud.com/v2/772045/flavors/3", "rel"=>"self"}, {"href"=>"https://dfw.servers.api.rackspacecloud.com/772045/flavors/3", "rel"=>"bookmark"}] + >, + … + + +## Get Flavor + +To retrieve individual flavor: + + service.flavor.get 2 + +This returns a `Fog::Compute::RackspaceV2::Flavor` instance: + + "https://dfw.servers.api.rackspacecloud.com/v2/772045/flavors/2", "rel"=>"self"}, {"href"=>"https://dfw.servers.api.rackspacecloud.com/772045/flavors/2", "rel"=>"bookmark"}] + > + + +## List Servers + +To retrieve a list of available servers: + + service.servers + +This returns a collection of `Fog::Compute::RackspaceV2::Servers` models: + + "https://dfw.servers.api.rackspacecloud.com/v2/772045/servers/6a273531-8ee4-4bef-ad1a-baca963f8bbb", "rel"=>"self"}, {"href"=>"https://dfw.servers.api.rackspacecloud.com/772045/servers/6a273531-8ee4-4bef-ad1a-baca963f8bbb", "rel"=>"bookmark"}], + metadata={}, + personality=nil, + ipv4_address="198.101.255.186", + ipv6_address="2001:4800:780e:0510:0fe1:75e8:ff04:c4a0", + disk_config="AUTO", + bandwidth=[], + addresses={"public"=>[{"version"=>4, "addr"=>"198.101.255.186"}, {"version"=>6, "addr"=>"2001:4800:780e:0510:0fe1:75e8:ff04:c4a0"}], "private"=>[{"version"=>4, "addr"=>"10.180.22.165"}]}, + flavor_id="2", + image_id="33e21646-43ed-407e-9dbf-7c7873fccd9a" + >, + … + +## Get Server + +To return an individual server: + + service.servers.get "6a273531-8ee4-4bef-ad1a-baca963f8bbb" + +This returns a `Fog::Compute::RackspaceV2::Server` instance: + + "https://dfw.servers.api.rackspacecloud.com/v2/772045/servers/6a273531-8ee4-4bef-ad1a-baca963f8bbb", "rel"=>"self"}, {"href"=>"https://dfw.servers.api.rackspacecloud.com/772045/servers/6a273531-8ee4-4bef-ad1a-baca963f8bbb", "rel"=>"bookmark"}], + metadata={}, + personality=nil, + ipv4_address="198.101.255.186", + ipv6_address="2001:4800:780e:0510:0fe1:75e8:ff04:c4a0", + disk_config="AUTO", + bandwidth=[], + addresses={"public"=>[{"version"=>4, "addr"=>"198.101.255.186"}, {"version"=>6, "addr"=>"2001:4800:780e:0510:0fe1:75e8:ff04:c4a0"}], "private"=>[{"version"=>4, "addr"=>"10.180.22.165"}]}, + flavor_id="2", + image_id="33e21646-43ed-407e-9dbf-7c7873fccd9a" + >, + ... + +## Create Server + +If you are interested in creating a server utilizing ssh key authenication, you are recommended to use [bootstrap](#bootstrap) method. + +To create a server: + + flavor = service.flavors.first + image = service.images.first + server = service.servers.create(:name => 'fog-doc', :flavor_id => flavor.id, :image_id => image.id) + +**Note**: The `:name`, `:flavor_id`, and `image_id` attributes are required for server creation. + +This will return a `Fog::Compute::RackspaceV2::Server` instance: + + "https://dfw.servers.api.rackspacecloud.com/v2/772045/servers/8ff308a6-e04a-4602-b991-ed526ab3b6be", "rel"=>"self"}, {"href"=>"https://dfw.servers.api.rackspacecloud.com/772045/servers/8ff308a6-e04a-4602-b991-ed526ab3b6be", "rel"=>"bookmark"}], + metadata=nil, + personality=nil, + ipv4_address=nil, + ipv6_address=nil, + disk_config="AUTO", + bandwidth=nil, + addresses=nil, + flavor_id=2, + image_id="3afe97b2-26dc-49c5-a2cc-a2fc8d80c001" + > + +Notice that your server contains several `nil` attributes. To see the latest status, reload the instance as follows: + + server.reload + +You can see that the server is currently 17% built: + + Fog::Compute::RackspaceV2::Server + id="8ff308a6-e04a-4602-b991-ed526ab3b6be", + name="fog-server", + created="2013-01-18T16:15:41Z", + updated="2013-01-18T16:16:14Z", + host_id="775837108e45aa3f2a58527c9c3b6160838078e83148f07906c933ca", + state="BUILD", + progress=17, + user_id="296063", + tenant_id="772045", + links=[{"href"=>"https://dfw.servers.api.rackspacecloud.com/v2/772045/servers/8ff308a6-e04a-4602-b991-ed526ab3b6be", "rel"=>"self"}, {"href"=>"https://dfw.servers.api.rackspacecloud.com/772045/servers/8ff308a6-e04a-4602-b991-ed526ab3b6be", "rel"=>"bookmark"}], + metadata={}, + personality=nil, + ipv4_address="", + ipv6_address="", + disk_config="AUTO", + bandwidth=[], + addresses={"public"=>[{"version"=>4, "addr"=>"198.61.209.78"}, {"version"=>6, "addr"=>"2001:4800:7810:0512:0fe1:75e8:ff04:94e4"}], "private"=>[{"version"=>4, "addr"=>"10.181.13.198"}]}, + flavor_id="2", + image_id="3afe97b2-26dc-49c5-a2cc-a2fc8d80c001" + > + +You will be unable to perform any actions to this server until it reaches an `ACTIVE` state. Since this is true for most server actions, Fog provides the convenience method `wait_for`. + +Fog can wait for the server to become ready as follows: + + server.wait_for { ready? } + +**Note**: The `Fog::Compute::RackspaceV2::Server` instance returned from the create method contains a `password` attribute. The `password` attribute will NOT be present in subsequent retrievals either through `service.servers` or `server.servers.get my_server_id`. + +### Additional Parameters + +The `create` method also supports the following key values: + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:disk_configThe disk configuration value (AUTO or MANUAL). Refer to Next Gen Server API documentation - Disk Configuration Extension.
:metadataHash containing server metadata.
:personalityArray of files to be injected onto the server. Please refer to the Fog personality API documentation for further information.
:config_driveWhether a read-only configuration drive is attached. Refer to Next Gen Server API documentation - Config Drive Extension.
+ +## Bootstrap + +In addition to the `create` method, Fog provides a `bootstrap` method which creates a server and then performs the following actions via ssh: + +1. Create `ROOT_USER/.ssh/authorized_keys` file using the ssh key specified in `:public_key_path`. +2. Lock password for root user using `passwd -l root`. +3. Create `ROOT_USER/attributes.json` file with the contents of `server.attributes`. +4. Create `ROOT_USER/metadata.json` file with the contents of `server.metadata`. + +**Note**: Unlike the `create` method, `bootstrap` is blocking method call. If non-blocking behavior is desired, developers should use the `:personality` parameter on the `create` method. + +The following example demonstrates bootstraping a server: + + service.servers.bootstrap :name => 'bootstrap-server', + :flavor_id => service.flavors.first.id, + :image_id => service.images.find {|img| img.name =~ /Ubuntu/}.id, + :public_key_path => '~/.ssh/fog_rsa.pub', + :private_key_path => '~/.ssh/fog_rsa' + +**Note**: The `:name`, `:flavor_id`, `:image_id`, `:public_key_path`, `:private_key_path` are required for the `bootstrap` method. + +The `bootstrap` method uses the same additional parameters as the `create` method. Refer to the [Additional Parameters](#additional-parameters) section for more information. + +## SSH + +Once a server has been created and set up for ssh key authentication, fog can execute remote commands as follows: + + result = server.ssh ['pwd'] + +This will return the following: + + [#] + +**Note**: SSH key authentication can be set up using `bootstrap` method or by using the `:personality` attribute on the `:create` method. See [Bootstrap](#bootstrap) or [Create Server](#create-server) for more information. + +## Update Server + +Next Gen Cloud Servers support updating the following attributes `name`, `access_ipv4_address`, and `access_ipv6_address`. + +To update these attributes: + + server.name = "batman" + server.access_ipv4_address = "10.0.0.1" + server.access_ipv6_address = "fdbb:1717:4533:7c89:0:0:0:1" + server.save + +Additional information about server access addresses can be found [here](http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Primary_Addresses-d1e2558.html). + +**Note**: Updating the server name does not change the host name. Names are not guaranteed to be unique. + +## Delete Server + +To delete a server: + + server.destroy + +**Note**: The server is not immediately destroyed, but it does occur shortly there after. + +## Metadata + +You can access metadata as an attribute on both `Fog::Compute::RackspaceV2::Server` and `Fog::Compute::RackspaceV2::Metadata::Image`. You can specify metadata during creation of a server or an image. Please refer to [Create Server](#create-server) or [Create Image](#create-image) sections for more information. + +This example demonstrates how to iterate through a server's metadata: + + server.metadata.each {|metadatum| puts "#{metadatum.key}: #{metadatum.value}" } + +You can update and retrieve metadata in a manner similar to a hash: + + server.metadata["os_type"] + + server.metadata["installed_ruby"] = "MRI 1.9.3" + +Metadata also responds to `save` and `reload` as follows: + + server.metadata.save + + server.metadata.reload + + +## Change Admin Password + +To change the administrator password: + + server.change_admin_password "superSecure" + +## Reboot + +To perform a soft reboot: + + server.reboot + +To perform a hard reboot: + + server.reboot 'HARD' + +## Rebuild + +Rebuild removes all data on the server and replaces it with the specified image. The id and all IP addresses remain the same. + +To rebuild a server: + + image = service.images.first + server.rebuild image.id + +Additionally, the `rebuild` method will take a second parameter containing a hash with the following values: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:nameName of Server
:flavorRefFlavor id
:accessIPv4IPv4 access address
:accessIPv6IPv6 access address
:metadataHash containing server metadata
:personalityFile path and contents. Refer to Next Gen Server API documentation - Server Personality.
:disk_configThe disk configuration value (AUTO or MANUAL). Refer to Next Gen Server API documentation - Disk Configuration Extension.
+ +## Resize + +Resizing a server allows you to change the resources dedicated to the server. + +To resize a server: + + flavor_id = service.flavor[2].id + server.resize flavor_id #flavor_id should be your desired flavor + +During the resize process the server will have a state of `RESIZE`. Once a server has completed resizing it will be in a `VERIFY_RESIZE` state. + +You can use Fog's `wait_for` method to wait for this state as follows: + + server.wait_for { ready?('VERIFY_RESIZE', ['ACTIVE', 'ERROR']) } + + +In this case, `wait_for` is waiting for the server to become `VERIFY_READY` and will raise an exception if we enter an `ACTIVE` or `ERROR` state. + +Once a server enters the `VERIFY_RESIZE` we will need to call `confirm_resize` to confirm the server was properly resized or `revert_resize` to rollback to the old size/flavor. + +**Note:** A server will automatically confirm resize after 24 hours. + +To confirm resize: + + server.confirm_resize + +To revert to previous size/flavor: + + server.revert_resize + + +## Create Image + +To create an image of your server: + + image = server.create_image "back-image-#{server.name}", :metadata => { :environment => 'development' } + +You can use the second parameter to specify image metadata. This is an optional parameter. + +During the imaging process, the image state will be `SAVING`. The image is ready for use when when state `ACTIVE` is reached. Fog can use `wait_for` to wait for an active state as follows: + + image.wait_for { ready? } + +## List Attached Volumes +To list Cloud Block Volumes attached to server: + + server.attachments + +## Attach Volume +To attach volume using the volume id: + + server.attach_volume "0e7a706c-340d-48b3-802d-192850387f93" + +If the volume id is unknown you can look it up using the Cloud Block Storage service. Start by creating a `cbs_service` similar to our Compute Service: + + cbs_service = Fog::Rackspace::BlockStorage.new({ + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API # Your Rackspace API key + }) + + volume = cbs_service.volumes.first + server.attach_volume volume, "/dev/xvdb" # name of device on server is optional + +The `attach_volume` method accepts a volume id `String` or `Fog::Rackspace::BlockStorage::Volume` instance. This example also demonstrates passing in the optional device name. Valid device names are `/dev/xvd[a-p]`. + +## Detach Volume +To detach a volume: + + server.attachments.first.detach + +## Examples + +Example code using Next Gen Cloud Servers can be found [here](https://github.com/fog/fog/tree/master/lib/fog/rackspace/examples). + +## Additional Resources + +* [fog.io](http://fog.io/) +* [Fog rdoc](http://rubydoc.info/gems/fog/) +* [Fog Github repo](https://github.com/fog/fog) +* [Fog Github Issues](https://github.com/fog/fog/issues) +* [Excon Github repo](https://github.com/geemus/excon) +* [Next Gen Cloud Servers API](http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ch_preface.html) + +## Support and Feedback + +Your feedback is appreciated! If you have specific issues with the **fog** SDK, you should file an [issue via Github](https://github.com/fog/fog/issues). + +For general feedback and support requests, send an email to: . + diff --git a/lib/fog/rackspace/docs/getting_started.md b/lib/fog/rackspace/docs/getting_started.md new file mode 100644 index 000000000..d76a0b8ae --- /dev/null +++ b/lib/fog/rackspace/docs/getting_started.md @@ -0,0 +1,88 @@ +# Getting Started with Fog and the Rackspace Cloud + +This document explains how to get started using Fog with the [Rackspace Cloud](http://www.rackspace.com/cloud/). + +## Requirements + +### Ruby + +Fog officially supports Ruby 2.1.1, 2.1.0, 2.0.0, 1.9.3, 1.9.2, and 1.8.7 (also known as Matz Ruby Interpreter or MRI). While not officially supported, fog has been known to work with Rubinus and JRuby. + +Ruby 1.9.3 is suggested for new projects. For information on installing Ruby please refer to the [Ruby download page](http://www.ruby-lang.org/en/downloads/). + +### RubyGems + +RubyGems is required to access the Fog gem. For information on installing RubyGems, please refer to [RubyGems download page](http://rubygems.org/pages/download). + +### Bundler (optional) + +Bundler helps manage gem dependencies and is recommended for new projects. For more information about bundler, please refer to the [bundler documentation](http://gembundler.com/). + +## Credentials + +To obtain credentials for the US Rackspace Cloud, please sign up for an account at [US Rackspace Open Cloud](https://cart.rackspace.com/cloud/). Once an account is created, you can login to the [Cloud Control Panel (US)](https://mycloud.rackspace.com/), find your credentials by clicking on your username in the top right corner, and then select API keys. + +Likewise, you can create an account on our UK Rackspace Open Cloud by signing up at [UK Rackspace Open Cloud](https://buyonline.rackspace.co.uk/cloud/userinfo?type=normal) and then logging into [Cloud Control Panel (UK)](https://mycloud.rackspace.co.uk/). + +You will use the credentials when you explore fog services in the [Next Steps](#next-steps) section. + +## Installation + +To install Fog via RubyGems run the following command: + + $ gem install fog + +To install Fog via Bundler add `gem 'fog'` to your `Gemfile`. This is a sample `Gemfile` to install Fog: + + source 'https://rubygems.org' + + gem 'fog' + +After creating your `Gemfile` execute the following command to install the libraries: + + bundle install + +## Next Steps + +Now that you have installed Fog and obtained your credentials, you are ready to begin exploring the capabilities of the Rackspace Open Cloud and Fog using `irb`. + +Start by executing the following command: + + irb + +Once `irb` has launched you will need to require the Fog library. + +If using Ruby 1.8.x execute the following command: + + require 'rubygems' + require 'fog' + +If using Ruby 1.9.x execute the following command: + + require 'fog' + +You should now be able to execute the following command to see a list of services Fog provides for the Rackspace Open Cloud: + + Fog::Rackspace.services + +These services can be explored in further depth in the following documents: + +* [Next Generation Cloud Serversâ„¢ (compute_v2)](compute_v2.md) +* [Cloud Filesâ„¢ (storage)](storage.md) +* [Cloud Block Storage (block_storage)](block_storage.md) +* [Auto Scale (auto_scale)](auto_scale.md) +* [Queues](queues.md) + +**Note**: The compute service provides an interface to the First Geneneration Cloud Serversâ„¢ (compute). This service is deprecated. Users are encouraged to use Next Geneneration Cloud Serversâ„¢ (compute_v2). + +## Additional Resources +* [fog.io](http://fog.io) +* [Fog rdoc](http://rubydoc.info/gems/fog) +* [Fog Github repo](https://github.com/fog/fog) +* [Release Notes](https://github.com/fog/fog/blob/master/changelog.txt) +* [developer.rackspace.com](http://developer.rackspace.com/) + +## Support and Feedback +Your feedback is appreciated! If you have specific issues with the **fog** SDK, you should file an [issue via Github](https://github.com/fog/fog/issues). + +For general feedback and support requests, send an email to: . diff --git a/lib/fog/rackspace/docs/networking.md b/lib/fog/rackspace/docs/networking.md new file mode 100644 index 000000000..2af77d673 --- /dev/null +++ b/lib/fog/rackspace/docs/networking.md @@ -0,0 +1,315 @@ +#Networking (neutron) + +This document explains how to get started using Networking with Fog. It assumes you have read the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +## Starting irb console + +Start by executing the following command: + + irb + +Once `irb` has launched you need to require the Fog library. + +If using Ruby 1.8.x execute: + + require 'rubygems' + require 'fog' + +If using Ruby 1.9.x execute: + + require 'fog' + +## Create Service + +Next, create a connection to Rackspace's Networking API: + +Using a US-based account: + + service = Fog::Rackspace::Networking.new({ + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_region => :ord, # Defaults to :dfw + }) + +Using a UK-based account: + + service = Fog::Compute.new({ + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT, + :rackspace_region => :lon, + }) + +To learn more about obtaining cloud credentials refer to the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +By default `Fog::Rackspace::Networking` will authenticate against the US authentication endpoint and connect to the DFW region. You can specify alternative authentication endpoints using the key `:rackspace_auth_url`. Please refer to [Alternate Authentication Endpoints](http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Endpoints-d1e180.html) for a list of alternative Rackspace authentication endpoints. + +Alternative regions are specified using the key `:rackspace_region `. A list of regions available for Cloud Servers can be found by executing the following: + + identity_service = Fog::Identity({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT # Not specified for US Cloud + }) + + identity_service.service_catalog.display_service_regions :cloudServersOpenStack + +### Optional Connection Parameters + +Fog supports passing additional connection parameters to its underlying HTTP library (Excon) using the `:connection_options` parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:connect_timeoutConnection timeout (default: 60 seconds)
:read_timeoutRead timeout for connection (default: 60 seconds)
:write_timeoutWrite timeout for connection (default: 60 seconds)
:proxyProxy for HTTP and HTTPS connections
:ssl_ca_pathPath to SSL certificate authorities
:ssl_ca_fileSSL certificate authority file
:ssl_verify_peerSSL verify peer (default: true)
+ + +## Fog Abstractions + +Fog provides both a **model** and **request** abstraction. The request abstraction provides the most efficient interface and the model abstraction wraps the request abstraction to provide a convenient `ActiveModel` like interface. + +### Request Layer + +The request abstraction maps directly to the [Networking API](http://docs.rackspace.com/networks/api/v2/cn-gettingstarted/content/ch_overview.html). It provides the most efficient interface to the Rackspace Networking + +To see a list of requests supported by the service: + + service.requests + +This returns: + + [:list_networks, :get_network, :create_network, :delete_network, :list_virtual_interfaces, :create_virtual_interface, :delete_virtual_interface] + +#### Example Request + +To request a list of flavors: + + response = service.list_networks + +This returns in the following `Excon::Response`: + + {"networks"=>[{"cidr"=>"192.168.0.0/24", "id"=>"08df79ae-b714-425c-ba25-91b0a8a78b9e", "label"=>"something"}, {"cidr"=>"192.168.0.0/24", "id"=>"eb3ed4b8-21d4-478e-9ae4-a35c0cc0437c", "label"=>"something"}, {"id"=>"00000000-0000-0000-0000-000000000000", "label"=>"public"}, {"id"=>"11111111-1111-1111-1111-111111111111", "label"=>"private"}]}, :headers=>{"Content-Type"=>"application/json", "Via"=>"1.1 Repose (Repose/2.12)", "Content-Length"=>"341", "Date"=>"Thu, 23 Oct 2014 20:53:41 GMT", "x-compute-request-id"=>"req-d34ab53c-45ed-433f-8a9d-b3341896b7e5", "Server"=>"Jetty(8.0.y.z-SNAPSHOT)"}, :status=>200, :remote_ip=>"162.209.116.128", :local_port=>60153, :local_address=>"192.168.1.65"}, @body="{\"networks\": [{\"cidr\": \"192.168.0.0/24\", \"id\": \"08df79ae-b714-425c-ba25-91b0a8a78b9e\", \"label\": \"something\"}, {\"cidr\": \"192.168.0.0/24\", \"id\": \"eb3ed4b8-21d4-478e-9ae4-a35c0cc0437c\", \"label\": \"something\"}, {\"id\": \"00000000-0000-0000-0000-000000000000\", \"label\": \"public\"}, {\"id\": \"11111111-1111-1111-1111-111111111111\", \"label\": \"private\"}]}", @headers={"Content-Type"=>"application/json", "Via"=>"1.1 Repose (Repose/2.12)", "Content-Length"=>"341", "Date"=>"Thu, 23 Oct 2014 20:53:41 GMT", "x-compute-request-id"=>"req-d34ab53c-45ed-433f-8a9d-b3341896b7e5", "Server"=>"Jetty(8.0.y.z-SNAPSHOT)"}, @status=200, @remote_ip="162.209.116.128", @local_port=60153, @local_address="192.168.1.65"> + +To view the status of the response: + + response.status + +**Note**: Fog is aware of valid HTTP response statuses for each request type. If an unexpected HTTP response status occurs, Fog will raise an exception. + +To view response body: + + response.body + +This will return: + + {"networks"=>[{"cidr"=>"192.168.0.0/24", "id"=>"08df79ae-b714-425c-ba25-91b0a8a78b9e", "label"=>"something"}, {"cidr"=>"192.168.0.0/24", "id"=>"eb3ed4b8-21d4-478e-9ae4-a35c0cc0437c", "label"=>"something"}, {"id"=>"00000000-0000-0000-0000-000000000000", "label"=>"public"}, {"id"=>"11111111-1111-1111-1111-111111111111", "label"=>"private"}]} + +To learn more about Networking request methods refer to [rdoc](http://www.rubydoc.info/gems/fog/Fog/Rackspace/Networking/Real). To learn more about Excon refer to [Excon GitHub repo](https://github.com/geemus/excon). + +### Model Layer + +Fog models behave in a manner similar to `ActiveModel`. Models will generally respond to `create`, `save`, `persisted?`, `destroy`, `reload` and `attributes` methods. Additionally, fog will automatically create attribute accessors. + +Here is a summary of common model methods: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
create + Accepts hash of attributes and creates object.
+ Note: creation is a non-blocking call and you will be required to wait for a valid state before using resulting object. +
saveSaves object.
+ Note: not all objects support updating object.
persisted?Returns true if the object has been persisted.
destroy + Destroys object.
+ Note: this is a non-blocking call and object deletion might not be instantaneous. +
reloadUpdates object with latest state from service.
ready?Returns true if object is in a ready state and able to perform actions. This method will raise an exception if object is in an error state.
attributesReturns a hash containing the list of model attributes and values.
identity + Returns the identity of the object.
+ Note: This might not always be equal to object.id. +
wait_forThis method periodically reloads model and then yields to specified block until block returns true or a timeout occurs.
+ +The remainder of this document details the model abstraction. + +## List Networks + +To retrieve a list of available networks: + + service.networks + +This returns a collection of `Fog::Rackspace::Networking::Network` models: + + , + , + , + + ] + > + +## Create Network + +Create a network: + + service.networks.create(label: "new_network", cidr: "192.168.0.0/24") + + +## Get Network + +To retrieve individual network: + + service.networks.get "8a3a9f96-b997-46fd-b7a8-a9e740796ffd" + +This returns an `Fog::Rackspace::Networking::Network` instance: + + + +## Delete Network + +To delete a network: + + network.destroy + +**Note**: The network is not immediately destroyed, but it does occur shortly there after. + +## List Virtual Interfaces + +To retrieve a list of available virtual interfaces: + + service.virtual_interfaces.all(server: ) + +This returns a collection of `Fog::Rackspace::Networking::VirtualInterface` models: + + "11111111-1111-1111-1111-111111111111", "network_label"=>"private", "address"=>"10.176.12.249"}] + >, + "08df79ae-b714-425c-ba25-91b0a8a78b9e", "network_label"=>"new_network", "address"=>"192.168.0.1"}] + > + ] + > + +## Create Virtual Interface + +Create a virtual interface: + + service.virtual_interfaces.create(network: , server: ) + +## Delete Virtual Interface + +To delete a virtual interface: + + vis = service.virtual_interfaces.all(server: ) + vis.first.destroy + +**Note**: The virtual interface is not immediately destroyed, but it does occur shortly there after. + +## Examples + +Example code using Networking can be found [here](https://github.com/fog/fog/tree/master/lib/fog/rackspace/examples). + +## Additional Resources + +* [fog.io](http://fog.io/) +* [Fog rdoc](http://rubydoc.info/gems/fog/) +* [Fog Github repo](https://github.com/fog/fog) +* [Fog Github Issues](https://github.com/fog/fog/issues) +* [Excon Github repo](https://github.com/geemus/excon) +* [Rackspace Networking API](http://docs.rackspace.com/networking/api/v2/cs-devguide/content/ch_preface.html) + +## Support and Feedback + +Your feedback is appreciated! If you have specific issues with the **fog** SDK, you should file an [issue via Github](https://github.com/fog/fog/issues). + +For general feedback and support requests, send an email to: . + diff --git a/lib/fog/rackspace/docs/queues.md b/lib/fog/rackspace/docs/queues.md new file mode 100644 index 000000000..51bf37b75 --- /dev/null +++ b/lib/fog/rackspace/docs/queues.md @@ -0,0 +1,312 @@ +#Cloud Queues (queues) + +This document explains how to get started using queues with Fog. It assumes you have read the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +## Basic Concepts + +Cloud Queues is an open source, scalable, and highly available message and notifications service, based on the OpenStack Marconi project. Users of this service can create and manage a producer-consumer or a publisher-subscriber model. Unlimited queues and messages give users the flexibility they need to create powerful web applications in the cloud. + +It consists of a few basic components: queues, messages, claims, and statistics. In the producer-consumer model, users create queues in which producers, or servers, can post messages. Workers, or consumers, can then claim those messages and delete them after they complete the actions associated with the messages. A single claim can contain multiple messages, and administrators can query claims for status. + +In the publisher-subscriber model, messages are posted to a queue as in the producer-consumer model, but messages are never claimed. Instead, subscribers, or watchers, send GET requests to pull all messages that have been posted since their last request. In this model, a message remains in the queue, unclaimed, until the message's time to live (TTL) has expired. + +In both of these models, administrators can get queue statistics that display the most recent and oldest messages, the number of unclaimed messages, and more. + +## Starting irb console + +Start by executing the following command: + + irb + +Once `irb` has launched you need to require the Fog library as follows: + + require 'fog' + +## Create Service + +Next, create a connection to queue service: + +Using a US-based account: + + service = Fog::Rackspace::Queues( + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_region => :ord, # Your desired region + :rackspace_queues_client_id => CLIENT_ID, # Your client ID + :connection_options => {} # Optional connection options + ) + +Using a UK-based account: + + service = Fog::Rackspace::Queues( + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT, + :rackspace_region => :lon, # Your desired region + :rackspace_queues_client_id => CLIENT_ID', # Your client ID + :connection_options => {} # Optional connection options + ) + +To learn more about obtaining cloud credentials refer to the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +### Authentication Endpoint + +By default `Fog::Rackspace::Queues` will authenticate against the US authentication endpoint. You can specify alternative authentication endpoints using the key `:rackspace_auth_url`. Please refer to [Alternate Authentication Endpoints](http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Endpoints-d1e180.html) for a list of alternative Rackspace authentication endpoints. + +### Regions + +Alternative regions are specified using the key `:rackspace_region `. A list of regions available for cloud queues can be found by executing the following: + + identity_service = Fog::Identity({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT # Not specified for US Cloud + }) + + identity_service.service_catalog.display_service_regions :queues + +### Private Cloud + +Rackspace Private Cloud installations can skip specifying a region and directly specify their custom service endpoints using the key `:rackspace_queues_url`. + +**Note**: A`Fog::Rackspace::Queues` instance is needed for the desired region. + +### Client ID + +The Rackspace Queue service requires that every client define a client id to help identify messages and claims specific to the client. This client id should take the form of a UUID and can be generated using fog as follows: + + Fog::UUID.uuid + +If the client id is omitted fog will generate one for you. + +### Optional Connection Parameters + +Fog supports passing additional connection parameters to its underlying HTTP library (Excon) using the `:connection_options` parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:connect_timeoutConnection timeout (default: 60 seconds)
:read_timeoutRead timeout for connection (default: 60 seconds)
:write_timeoutWrite timeout for connection (default: 60 seconds)
:proxyProxy for HTTP and HTTPS connections
:ssl_ca_pathPath to SSL certificate authorities
:ssl_ca_fileSSL certificate authority file
:ssl_verify_peerSSL verify peer (default: true)
+ + +## Fog Abstractions + +Fog provides both a **model** and **request** abstraction. The request abstraction provides the most efficient interface and the model abstraction wraps the request abstraction to provide a convenient `ActiveModel`-like interface. + +### Request Layer + +The request abstraction maps directly to the [Queue API](http://docs.rackspace.com/queues/api/v1.0/cq-devguide/content/overview.html). It provides the most efficient interface to the Rackspace Open Cloud. + +To see a list of requests supported by the service: + + service.requests + +This returns: + + :list_queues, :get_queue, :create_queue, :delete_queue, :get_queue_stats, :list_messages, :get_message, :create_message, :delete_message, :create_claim, :get_claim, :update_claim, :delete_claim + + +#### Example Request + +To request a list of queues: + + response = service.list_queues + +This returns in the following `Excon::Response`: + + #{"queues"=>[{"href"=>"/v1/queues/demo-queue", "name"=>"demo-queue"}], "links"=>[{"href"=>"/v1/queues?marker=demo-queue", "rel"=>"next"}]}, :headers=>{"Content-Length"=>"119", "Content-Type"=>"application/json; charset=utf-8", "Content-Location"=>"/v1/queues", "X-Project-ID"=>"5551212"}, :status=>200, :remote_ip=>"10.10.0.1"}, @body="{\"queues\": [{\"href\": \"/v1/queues/demo-queue\", \"name\": \"demo-queue\"}], \"links\": [{\"href\": \"/v1/queues?marker=demo-queue\", \"rel\": \"next\"}]}", @headers={"Content-Length"=>"119", "Content-Type"=>"application/json; charset=utf-8", "Content-Location"=>"/v1/queues", "X-Project-ID"=>"5551212"}, @status=200, @remote_ip="10.10.0.1"> + +To view the status of the response: + + response.status + +**Note**: Fog is aware of valid HTTP response statuses for each request type. If an unexpected HTTP response status occurs, Fog will raise an exception. + +To view response body: + + response.body + +This returns: + + {"queues"=>[{"href"=>"/v1/queues/demo-queue", "name"=>"demo-queue"}], "links"=>[{"href"=>"/v1/queues?marker=demo-queue", "rel"=>"next"}]} + + +To learn more about queue request methods refer to [rdoc](http://rubydoc.info/gems/fog/Fog/Rackspace/Queues/Real). To learn more about Excon refer to [Excon GitHub repo](https://github.com/geemus/excon). + +### Model Layer + +Fog models behave in a manner similar to `ActiveModel`. Models will generally respond to `create`, `save`, `persisted?`, `destroy`, `reload` and `attributes` methods. Additionally, fog will automatically create attribute accessors. + +Here is a summary of common model methods: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
create + Accepts hash of attributes and creates object.
+ Note: creation is a non-blocking call and you will be required to wait for a valid state before using resulting object. +
saveSaves object.
+ Note: not all objects support updating object.
persisted?Returns true if the object has been persisted.
destroy + Destroys object.
+ Note: this is a non-blocking call and object deletion might not be instantaneous. +
reloadUpdates object with latest state from service.
ready?Returns true if object is in a ready state and able to perform actions. This method will raise an exception if object is in an error state.
attributesReturns a hash containing the list of model attributes and values.
identity + Returns the identity of the object.
+ Note: This might not always be equal to object.id. +
wait_forThis method periodically reloads model and then yields to specified block until block returns true or a timeout occurs.
+ +The remainder of this document details the model abstraction. + +## Create Queue + +Queues require a unique name. If you try to create a queue with a name that already exists, fog will throw a `Fog::Rackspace::Queues::ServiceError` exception with a 204 status code. + +To create a queue named demo-queue + + begin + queue = service.queues.create :name => 'demo-queue' + rescue Fog::Rackspace::Queues::ServiceError => e + if e.status_code == 204 + # duplicate queue exists + end + end + +## Posting a Message to a Queue + +Messages can be any type of data, as long as they do not exceed 256 KB in length. Typical message bodies range from simple values, to a chunk of XML, or a list of JSON values. Fog handles the JSON-encoding required to post the message. + +You can post a message a message to your queue as follows: + + queue.messages.create :body => 'The laces were out!', :ttl => 360 + +You must supply both a body and a value for `ttl`. The value of `ttl` must be between 60 and 1209600 seconds (one minute to 14 days). + +## Listing Messages in a Queue + +To list messages: + + queue.messages + +You can change the behavior by setting the follow attributes on the messages collection: + +Parameter | Default | Effect +---- | ---- | ---- +**echo** | `true` | When `true`, your own messages are included. +**include_claimed** | `false` | By default, only unclaimed messages are returned. Pass this as `true` to get all messages, claimed or not. +**marker** | `nil` | Used for pagination. +**limit** | `10` | The maximum number of messages to return. Note that you may receive fewer than the specified limit if there aren't that many available messages in the queue. + +For example, to include claimed messages: + + queue.messages.include_claimed = true + queue.messages + +## Claiming Messages in a Queue + +Claiming messages is how workers processing a queue mark messages as being handled by that worker, avoiding having two workers process the same message. + +Messages can be claimed and processed as follows: + + claims = queue.claims.create :ttl => 300, :grace => 100, :limit => 10 + +The parameters for this call are described in the following table: + +Parameter | Default | Notes +---- | ---- | ---- +**ttl** | | The ttl attribute specifies how long the server waits before releasing the claim. The ttl value must be between 60 and 43200 seconds (12 hours). +**grace** | | The grace attribute specifies the message grace period in seconds. The value of the grace period must be between 60 and 43200 seconds (12 hours). To deal with workers that have stopped responding (for up to 1209600 seconds or 14 days, including claim lifetime), the server extends the lifetime of claimed messages to be at least as long as the lifetime of the claim itself, plus the specified grace period. If a claimed message would normally live longer than the grace period, its expiration is not adjusted. +**limit** | 10 | The number of messages to claim. The maximum number of messages you may claim at once is 20. + +If the claim is successful it will return a `Fog::Rackspace::Queues::Claims` object; if there are not any available messages it will return `false`. + +To iterate through the claimed messages: + + claim.messages.each do |message| + # process message here + message.destroy + end + +**Note:** You will want to call the `destroy` method on the message after processing to insure it is not processed more than once. + +## Renewing a Claim + +Once a claim has been made, if the TTL and grace period expire, the claim is automatically released and the messages are made available for others to claim. If you have a long-running process and want to ensure that this does not happen in the middle of the process, you should update the claim with one or both of a TTL or grace period. Updating resets the age of the claim, restarting the TTL for the claim. To update a claim, call: + + claim.ttl = 360 + claim.grace = 360 + claim.save + +## Refreshing a Claim + +If you have a `Fog::Rackspace::Queues::claims` object, keep in mind that it is not a live window into the status of the claim; rather, it is a snapshot of the claim at the time the object was created. To refresh it with the latest information, call its `reload` method. This refreshes all of its attributes with the most current status of the claim. + + +## Releasing a Claim + +If you have a claim on several messages and must abandon processing of those messages for any reason, you should release the claim so that those messages can be processed by other workers as soon as possible, instead of waiting for the claim's TTL to expire. When you release a claim, the claimed messages are immediately made available in the queue for other workers to claim. To release a claim, call: + + claim.destroy diff --git a/lib/fog/rackspace/docs/storage.md b/lib/fog/rackspace/docs/storage.md new file mode 100644 index 000000000..f78d396ec --- /dev/null +++ b/lib/fog/rackspace/docs/storage.md @@ -0,0 +1,557 @@ +#Cloud Filesâ„¢ (storage) + +This document explains how to get started using Cloud Files with Fog. It assumes you have read the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + + +## Starting irb console + +Start by executing the following command: + + irb + +Once `irb` has launched you need to require the Fog library. + +If using Ruby 1.8.x execute: + + require 'rubygems' + require 'fog' + +If using Ruby 1.9.x execute: + + require 'fog' + +## Create Service + +Next, create a connection to Cloud Files. + +Using a US-based account: + + service = Fog::Storage.new({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_region => :ord, # Defaults to :dfw + :connection_options => {} # Optional + }) + +Using a UK-based account: + + service = Fog::Storage.new({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT, + :rackspace_region => :lon, + :connection_options => {} # Optional + }) + +To learn more about obtaining cloud credentials refer to the [Getting Started with Fog and the Rackspace Open Cloud](getting_started.md) document. + +By default `Fog::Storage` will authenticate against the US authentication endpoint and connect to the DFW region. You can specify alternative authentication endpoints using the key `:rackspace_auth_url`. Please refer to [Alternate Authentication Endpoints](http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Endpoints-d1e180.html) for a list of alternative Rackspace authentication endpoints. + +Alternative regions are specified using the key `:rackspace_region `. A list of regions available for Cloud Files can be found by executing the following: + + identity_service = Fog::Identity({ + :provider => 'Rackspace', # Rackspace Fog provider + :rackspace_username => RACKSPACE_USER_NAME, # Your Rackspace Username + :rackspace_api_key => RACKSPACE_API, # Your Rackspace API key + :rackspace_auth_url => Fog::Rackspace::UK_AUTH_ENDPOINT # Not specified for US Cloud + }) + + identity_service.service_catalog.display_service_regions :cloudFiles + +Rackspace Private Cloud installations can skip specifying a region and directly specify their custom service endpoints using the keys `:rackspace_storage_url` and `:rackspace_cdn_url`. + +**Note**: A`Fog::Storage` instance is needed for the desired region. + +### Optional Service Parameters + +The Storage service supports the following additional parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:rackspace_servicenetIf set to true, the service will access Cloud Files using the internal Rackspace ServiceNet. This option should only be used for internal network connections.
:rackspace_cdn_sslIf set to true, the public_url method will return the SSL based URLs.
:persistentIf set to true, the service will use a persistent connection.
:rackspace_storage_urlThe endpoint for the Cloud Files service. By default, Fog::Storage will pick the appropriate endpoint for region. This option will typically only be used for Rackspace Private Cloud Access.
:rackspace_cdn_urlThe endpoint for the CDN service. By default, Fog::Storage pick the appropriate endpoint for region. This option will typically only be used for Rackspace Private Cloud Access.
+ + +### Optional Connection Parameters + +Fog supports passing additional connection parameters to its underlying HTTP library (Excon) using the `:connection_options` parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:connect_timeoutConnection timeout (default: 60 seconds)
:read_timeoutRead timeout for connection (default: 60 seconds)
:write_timeoutWrite timeout for connection (default: 60 seconds)
:proxyProxy for HTTP and HTTPS connections
:ssl_ca_pathPath to SSL certificate authorities
:ssl_ca_fileSSL certificate authority file
:ssl_verify_peerSSL verify peer (default: true)
:chunk_sizeThe chunk size in bytes used for block transfers. By default, Fog uses 1 MB chunks.
+ + +## Fog Abstractions + +Fog provides both a **model** and **request** abstraction. The request abstraction provides the most efficient interface and the model abstraction wraps the request abstraction to provide a convenient `ActiveModel` like interface. + +### Request Layer + +The request abstraction maps directly to the [Cloud Files API](http://docs.rackspace.com/files/api/v1/cf-devguide/content/Overview-d1e70.html). It provides the most efficient interface to the Rackspace Open Cloud. + +To see a list of requests supported by the storage service: + + service.requests + +This returns: + + :copy_object, :delete_container, :delete_object, :get_container, :get_containers, :get_object, :get_object_https_url, :head_container, :head_containers, :head_object, :put_container, :put_object, :put_object_manifest, :post_set_meta_temp_url_key + +To see a list of requests supported by the CDN service: + + service.cdn.requests + +This returns: + + :get_containers, :head_container, :post_container, :put_container, :delete_object + + +#### Example Request + +To request a view account details: + + response = service.head_containers + +This returns in the following `Excon::Response`: + + #"2563554", "Date"=>"Thu, 21 Feb 2013 21:57:02 GMT", "X-Account-Meta-Temp-Url-Key"=>"super_secret_key", "X-Timestamp"=>"1354552916.82056", "Content-Length"=>"0", "Content-Type"=>"application/json; charset=utf-8", "X-Trans-Id"=>"txe934924374a744c8a6c40dd8f29ab94a", "Accept-Ranges"=>"bytes", "X-Account-Container-Count"=>"7", "X-Account-Object-Count"=>"5"}, @status=204, @body=""> + +To view the status of the response: + + response.status + +**Note**: Fog is aware of the valid HTTP response statuses for each request type. If an unexpected HTTP response status occurs, Fog will raise an exception. + +To view response headers: + + response.headers + +This will return: + + {"X-Account-Bytes-Used"=>"2563554", "Date"=>"Thu, 21 Feb 2013 21:57:02 GMT", "X-Account-Meta-Temp-Url-Key"=>"super_secret_key", "X-Timestamp"=>"1354552916.82056", "Content-Length"=>"0", "Content-Type"=>"application/json; charset=utf-8", "X-Trans-Id"=>"txe934924374a744c8a6c40dd8f29ab94a", "Accept-Ranges"=>"bytes", "X-Account-Container-Count"=>"7", "X-Account-Object-Count"=>"5"} + + +To learn more about `Fog::Storage` request methods refer to [rdoc](http://rubydoc.info/gems/fog/Fog/Storage/Rackspace/Real). To learn more about Excon refer to [Excon GitHub repo](https://github.com/geemus/excon). + +### Model Layer + +Fog models behave in a manner similar to `ActiveModel`. Models will generally respond to `create`, `save`, `destroy`, `reload` and `attributes` methods. Additionally, fog will automatically create attribute accessors. + +Here is a summary of common model methods: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
create + Accepts hash of attributes and creates object.
+ Note: creation is a non-blocking call and you will be required to wait for a valid state before using resulting object. +
saveSaves object.
+ Note: not all objects support updating object.
destroy + Destroys object.
+ Note: this is a non-blocking call and object deletion might not be instantaneous. +
reloadUpdates object with latest state from service.
attributesReturns a hash containing the list of model attributes and values.
identity + Returns the identity of the object.
+ Note: This might not always be equal to object.id. +
+ +The remainder of this document details the model abstraction. + +**Note:** Fog refers to Rackspace Cloud containers as directories. + +## List Directories + +To retrieve a list of directories: + + service.directories + +This returns a collection of `Fog::Storage::Rackspace::Directory` models: + + , + , + ... + +## Get Directory + +To retrieve a specific directory: + + service.directories.get "blue" + +**Note** As a general rule, only use `get` when you want to iterate over the contents of a `Directory` + +This call is similar to... + + service.directories.new :key => "blue" + +... except the `get` method makes an HTTP call that returns metadata for up to the first 10,000 files. **This can be slow!** + +This returns a `Fog::Storage::Rackspace::Directory` instance: + + + +## Create Directory + +To create a directory: + + service.directories.create :key => 'backups' + +To create a directory utilizing CDN: + + service.directories.create :key => 'web-assets', :public => true + +### Additional Parameters + +The `create` method also supports the following key values: + + + + + + + + + + +
KeyDescription
:metadataHash containing directory metadata.
+ + +## Update Directory + +Cloud Files supports updating the `public` attribute to enable/disable CDN. + +To update this attribute: + + directory.public = false + directory.save + +## Delete Directory + +To delete a directory: + + directory.destroy + +**Note**: Directory must be empty before it can be deleted. + +## List Files + +To list files in a directory: + + directory.files + +**Note**: File contents is not downloaded until `body` attribute is called. + +## Upload Files + +To upload a file into a directory: + + file = directory.files.create :key => 'space.jpg', :body => File.open "space.jpg" + +**Note**: For files larger than 5 GB please refer to the [Upload Large Files](#upload_large_files) section. + +If you only need a `Directory` so that you can create a file (as above), you can accomplish this without +an HTTP call as below: + + dir = service.directories.new :key => "blue" + file = dir.files.new(...) + file.save + +This will **not** retrieve the metadata for files in the `Directory`. + +However, if the `Directory` does not already exist in Cloud Files, the `save` call will return with a 404. + +In this case, you will need to `save` the `Directory` first... + + dir.save + +... before you can... + + file.save + +### Additional Parameters + +The `create` method also supports the following key values: + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
:content_typeThe content type of the object. Cloud Files will attempt to auto detect this value if omitted.
:access_control_allow_originURLs can make Cross Origin Requests. Format is http://www.example.com. Separate URLs with a space. An asterisk (*) allows all. Please refer to CORS Container Headers for more information.
:originThe origin is the URI of the object's host.
:etagThe MD5 checksum of your object's data. If specified, Cloud Files will validate the integrity of the uploaded object.
:metadataHash containing file metadata.
+ +## Upload Large Files + +Cloud Files requires files larger than 5 GB to be uploaded into segments along with an accompanying manifest file. All of the segments must be uploaded to the same container. + + SEGMENT_LIMIT = 5368709119.0 # 5GB -1 + BUFFER_SIZE = 1024 * 1024 # 1MB + + File.open(file_name) do |f| + segment = 0 + until file.eof? + segment += 1 + offset = 0 + + # upload segment to cloud files + segment_suffix = segment.to_s.rjust(10, '0') + service.put_object("my_container", "large_file/#{segment_suffix}", nil) do + if offset <= SEGMENT_LIMIT - BUFFER_SIZE + buf = file.read(BUFFER_SIZE).to_s + offset += buf.size + buf + else + '' + end + end + end + end + + # write manifest file + service.put_object_manifest("my_container", "large_file", 'X-Object-Manifest' => "my_container/large_file/") + +Segmented files are downloaded like ordinary files. See [Download Files](#download-files) section for more information. + +## Download Files + +The most efficient way to download files from a private or public directory is as follows: + + File.open('downloaded-file.jpg', 'w') do | f | + directory.files.get("my_big_file.jpg") do | data, remaining, content_length | + f.syswrite data + end + end + +This will download and save the file in 1 MB chunks. The chunk size can be changed by passing the parameter `:chunk_size` into the `:connection_options` hash in the service constructor. + +**Note**: The `body` attribute of file will be empty if a file has been downloaded using this method. + +If a file object has already been loaded into memory, you can save it as follows: + + File.open('germany.jpg', 'w') {|f| f.write(file_object.body) } + +**Note**: This method is more memory intensive as the entire object is loaded into memory before saving the file as in the example above. + + +## Accessing Files Through CDN + +The CDN service offers several different URLs to access your files. + +The simplest is with the default container URL. This can be accessed as follows: + + file.public_url + +For a more user-friendly URL, you can create a CNAME DNS record pointing to the URL generated by the `public_url` method. Then set the CNAME on the `Directory` object using the attribute `cdn_cname`. Note, that the `cdn_cname` attribute does not persist and will need to be specified every time a directory object is retrieved. + +To access the file using SSL, you need to specify the option `:rackspace_cdn_ssl => true` when creating `Fog::Storage` service. This will cause the `public_url` method to return the SSL-secured URL. + +To stream content use the following: + + file.streaming_url + +To stream video for iOS devices without needing to convert your video use the following: + + file.ios_url + + +## Metadata + +You can access metadata as an attribute on both `Fog::Storage::Rackspace::Directory` and `Fog::Storage::Rackspace::File`. + +This example demonstrates how to iterate through a directory's metadata: + + directory.metadata.each_pair {|metadatum| puts "#{metadatum.key}: #{metadatum.value}" } + +You can update and retrieve metadata in a manner similar to a hash: + + directory.metadata[:thumbnails] + + file.metadata[:environment] = "development" + +Directory metadata is saved when the directory is saved and file metadata is set when the file is saved: + + directory.save + + file.save + +Metadata is reloaded when directory or file is reloaded: + + directory.reload + + file.reload + +## Copy File + +Cloud Files supports copying files. To copy files into a container named "trip" with a name of "europe.jpg" do the following: + + file.copy("trip", "europe.jpg") + +To move or rename a file, perform a copy operation and then delete the old file: + + file.copy("trip", "germany.jpg") + file.destroy + +## Delete File + +To delete a file: + + file.destroy + +## CDN Purge + +To immediately remove a file from the CDN network use the following: + + file.purge_from_cdn + +You may only purge up to 25 objects per day and thus this should only be used in situations where there could be serious personal, business, or security consequences if the object remained in the CDN. To purge a directory, please contact Rackspace support. + +**Note**: You may only **PURGE** up to 25 objects per day. Any attempt to purge more than this will result in a 498 status code error (Rate Limited). + +## Account Information + +To view Cloud Files usage execute the following: + + service.account + +This returns a `Fog::Storage::Rackspace::Account` instance: + + + +## Examples + +Example code using Cloud Files can be found [here](https://github.com/fog/fog/tree/master/lib/fog/rackspace/examples). + +## Additional Resources + +* [fog.io](http://fog.io/) +* [Fog rdoc](http://rubydoc.info/gems/fog/) +* [Fog Github repo](https://github.com/fog/fog) +* [Fog Github Issues](https://github.com/fog/fog/issues) +* [Excon Github repo](https://github.com/geemus/excon) +* [Cloud Files API](http://docs.rackspace.com/files/api/v1/cf-devguide/content/Overview-d1e70.html) + +## Support and Feedback + +Your feedback is appreciated! If you have specific issues with the **fog** SDK, you should file an [issue via Github](https://github.com/fog/fog/issues). + +For general feedback and support requests, send an email to: . diff --git a/lib/fog/rackspace/errors.rb b/lib/fog/rackspace/errors.rb new file mode 100644 index 000000000..73e0c1314 --- /dev/null +++ b/lib/fog/rackspace/errors.rb @@ -0,0 +1,33 @@ +module Fog + module Rackspace + module Errors + def self.included(mod) + mod.class_eval <<-'EOS', __FILE__, __LINE__ + class NotFound < Fog::Service::NotFound + attr_reader :region, :status_code, :transaction_id + + def to_s + status = status_code ? "HTTP #{status_code}" : "HTTP " + message = region ? "resource not found in #{region} region" : super + "[#{status} | #{transaction_id}] #{message}" + end + + def self.slurp(error, service=nil) + exception = NotFound.new + exception.instance_variable_set(:@region, service.region) if service && service.respond_to?(:region) + exception.instance_variable_set(:@status_code, error.response.status) rescue nil + exception.set_transaction_id(error, service) + exception + end + + def set_transaction_id(error, service) + return unless service && service.respond_to?(:request_id_header) && error.response + @transaction_id = error.response.headers[service.request_id_header] + end + + end + EOS + end + end + end +end diff --git a/lib/fog/rackspace/examples/README.md b/lib/fog/rackspace/examples/README.md new file mode 100644 index 000000000..9f84fc990 --- /dev/null +++ b/lib/fog/rackspace/examples/README.md @@ -0,0 +1,47 @@ +# Getting Started Examples + +## Download + +Examples using the Rackspace Open Cloud and Fog can be found in the [fog repository](https://github.com/fog/fog) under the directory `fog/lib/fog/rackspace/examples`. + +This repository can be downloaded via `git` by executing the following: + + git clone git://github.com/fog/fog.git + +Optionally you can download a zip by clicking on this [link](https://github.com/fog/fog/archive/master.zip). + +## Requirements + +Examples require the following: + +* Rackspace Open Cloud account +* Ruby 1.8.x or 1.9.x +* `fog` gem + +For more information please refer to the [Getting Started with Fog and the Rackspace Open Cloud](https://github.com/fog/fog/blob/master/lib/fog/rackspace/docs/getting_started.md) document. + +## Credentials + +Examples will prompt for Rackspace Open Cloud credentials. Prompts can be skipped by creating a `.fog` file in the user's home directory. This is an example of a `.fog` file for the Rackspace Open Cloud: + + default: + rackspace_username: RACKSPACE_USERNAME + rackspace_api_key: RACKSPACE_API_KEY + +**Note:** Replace capitalized values with the appropriate credential information. + +## Executing + +To execute scripts using `bundler`: + + bundle exec ruby