diff --git a/lib/fog/aws/models/cdn/distributions.rb b/lib/fog/aws/models/cdn/distributions.rb index d18e00a41..dd76c5726 100644 --- a/lib/fog/aws/models/cdn/distributions.rb +++ b/lib/fog/aws/models/cdn/distributions.rb @@ -23,7 +23,8 @@ module Fog service.get_distribution_list(options) end - alias :each_distribution_this_page :each + alias_method :each_distribution_this_page, :each + alias_method :each, :each_distribution end diff --git a/lib/fog/aws/models/cdn/distributions_helper.rb b/lib/fog/aws/models/cdn/distributions_helper.rb index 3d5d03380..76bb9a177 100644 --- a/lib/fog/aws/models/cdn/distributions_helper.rb +++ b/lib/fog/aws/models/cdn/distributions_helper.rb @@ -5,6 +5,7 @@ module Fog class AWS module DistributionsHelper + def all(options = {}) merge_attributes(options) data = list_distributions(options).body @@ -24,7 +25,7 @@ module Fog nil end - def each + def each_distribution if !block_given? self else diff --git a/lib/fog/aws/models/cdn/streaming_distributions.rb b/lib/fog/aws/models/cdn/streaming_distributions.rb index b084c102a..cc307f178 100644 --- a/lib/fog/aws/models/cdn/streaming_distributions.rb +++ b/lib/fog/aws/models/cdn/streaming_distributions.rb @@ -23,7 +23,8 @@ module Fog service.get_streaming_distribution_list(options) end - alias :each_distribution_this_page :each + alias_method :each_distribution_this_page, :each + alias_method :each, :each_distribution end diff --git a/lib/fog/aws/requests/iam/update_server_certificate.rb b/lib/fog/aws/requests/iam/update_server_certificate.rb index d7bc6e04e..0b6a9ec2f 100644 --- a/lib/fog/aws/requests/iam/update_server_certificate.rb +++ b/lib/fog/aws/requests/iam/update_server_certificate.rb @@ -32,6 +32,33 @@ module Fog end end + + class Mock + def update_server_certificate(server_certificate_name, options = {}) + new_server_certificate_name = options['NewServerCertificateName'] + if self.data[:server_certificates][new_server_certificate_name] + raise Fog::AWS::IAM::EntityAlreadyExists.new("The Server Certificate with name #{server_certificate_name} already exists.") + end + unless certificate = self.data[:server_certificates].delete(server_certificate_name) + raise Fog::AWS::IAM::NotFound.new("The Server Certificate with name #{server_certificate_name} cannot be found.") + end + + if new_server_certificate_name + certificate['ServerCertificateName'] = new_server_certificate_name + end + + if new_path = options['NewPath'] + certificate['Path'] = new_path + end + + self.data[:server_certificates][certificate['ServerCertificateName']] = certificate + + Excon::Response.new.tap do |response| + response.body = { 'RequestId' => Fog::AWS::Mock.request_id } + response.status = 200 + end + end + end end end end diff --git a/lib/fog/core/ssh.rb b/lib/fog/core/ssh.rb index 4945416fb..ec5d9ed74 100644 --- a/lib/fog/core/ssh.rb +++ b/lib/fog/core/ssh.rb @@ -46,7 +46,7 @@ module Fog raise ArgumentError.new(':key_data, :keys, :password or a loaded ssh-agent is required to initialize SSH') end - options[:timeout] = 30 + options[:timeout] ||= 30 if options[:key_data] || options[:keys] options[:keys_only] = true #Explicitly set these so net-ssh doesn't add the default keys diff --git a/lib/fog/hp.rb b/lib/fog/hp.rb index 8bd209a84..d90e2747a 100644 --- a/lib/fog/hp.rb +++ b/lib/fog/hp.rb @@ -5,7 +5,7 @@ module Fog # define a specific version for the HP Provider unless const_defined?(:VERSION) - VERSION = '0.0.19' + VERSION = '0.0.20' end extend Fog::Provider diff --git a/lib/fog/hp/CHANGELOG.hp b/lib/fog/hp/CHANGELOG.hp index 6f188b6b8..aa91d1418 100644 --- a/lib/fog/hp/CHANGELOG.hp +++ b/lib/fog/hp/CHANGELOG.hp @@ -1,8 +1,18 @@ -0.0.19 18/01/2013 +0.0.20 03/13/2013 +================= +- add Accept header with application/json for all requests +- add support for user_data while creating servers in Compute +- add support for one/two way container synchronisation in Object Storage +- merge with upstream fog v1.10.0 + +0.0.19 01/25/2013 ================= - update Block Storage namespace to be Fog::HP::BlockStorage -- merge with upstream fog v1.8.0 +- merge with upstream fog v1.9.0 - deprecate hp_account_id to use hp_access_key instead +- fix temp_url to use signer that is backward compatible to 1.8.7 +- fix issue in Storage provider with service catalog having an invalid CDN endpoint +- Happy New Year to all... 0.0.18 12/04/2012 ================= diff --git a/lib/fog/hp/block_storage.rb b/lib/fog/hp/block_storage.rb index 530251772..616f2ff50 100644 --- a/lib/fog/hp/block_storage.rb +++ b/lib/fog/hp/block_storage.rb @@ -144,6 +144,7 @@ module Fog response = @connection.request(params.merge!({ :headers => { 'Content-Type' => 'application/json', + 'Accept' => 'application/json', 'X-Auth-Token' => @auth_token }.merge!(params[:headers] || {}), :host => @host, diff --git a/lib/fog/hp/cdn.rb b/lib/fog/hp/cdn.rb index 16473610c..3ced28ad1 100644 --- a/lib/fog/hp/cdn.rb +++ b/lib/fog/hp/cdn.rb @@ -128,6 +128,7 @@ module Fog response = @connection.request(params.merge!({ :headers => { 'Content-Type' => 'application/json', + 'Accept' => 'application/json', 'X-Auth-Token' => @auth_token }.merge!(params[:headers] || {}), :host => @host, diff --git a/lib/fog/hp/compute.rb b/lib/fog/hp/compute.rb index 312c1e1af..f04e74ba0 100644 --- a/lib/fog/hp/compute.rb +++ b/lib/fog/hp/compute.rb @@ -227,6 +227,7 @@ module Fog response = @connection.request(params.merge!({ :headers => { 'Content-Type' => 'application/json', + 'Accept' => 'application/json', 'X-Auth-Token' => @auth_token }.merge!(params[:headers] || {}), :host => @host, diff --git a/lib/fog/hp/models/compute/server.rb b/lib/fog/hp/models/compute/server.rb index bce6828b4..87c711a8f 100644 --- a/lib/fog/hp/models/compute/server.rb +++ b/lib/fog/hp/models/compute/server.rb @@ -27,6 +27,7 @@ module Fog attribute :key_name attribute :security_groups attribute :config_drive + attribute :user_data_encoded # these are implemented as methods attribute :image_id attribute :flavor_id @@ -66,6 +67,10 @@ module Fog metadata.load(metas) end + def user_data=(ascii_userdata) + self.user_data_encoded = [ascii_userdata].pack('m') # same as Base64.encode64 + end + def destroy requires :id service.delete_server(id) @@ -216,15 +221,16 @@ module Fog meta_hash = {} metadata.each { |meta| meta_hash.store(meta.key, meta.value) } options = { - 'metadata' => meta_hash, - 'personality' => personality, - 'accessIPv4' => accessIPv4, - 'accessIPv6' => accessIPv6, - 'min_count' => @min_count, - 'max_count' => @max_count, - 'key_name' => key_name, + 'metadata' => meta_hash, + 'personality' => personality, + 'accessIPv4' => accessIPv4, + 'accessIPv6' => accessIPv6, + 'min_count' => @min_count, + 'max_count' => @max_count, + 'key_name' => key_name, 'security_groups' => security_groups, - 'config_drive' => config_drive + 'config_drive' => config_drive, + 'user_data' => user_data_encoded } options = options.reject {|key, value| value.nil?} # either create a regular server or a persistent server based on input diff --git a/lib/fog/hp/models/storage/directories.rb b/lib/fog/hp/models/storage/directories.rb index dd24961c3..0e7c9bb12 100644 --- a/lib/fog/hp/models/storage/directories.rb +++ b/lib/fog/hp/models/storage/directories.rb @@ -49,7 +49,7 @@ module Fog write_header = nil directory = new(:key => key) for key, value in data.headers - if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key) + if ['X-Container-Bytes-Used', 'X-Container-Object-Count', 'X-Container-Sync-To', 'X-Container-Sync-Key'].include?(key) directory.merge_attributes(key => value) end if key == 'X-Container-Read' diff --git a/lib/fog/hp/models/storage/directory.rb b/lib/fog/hp/models/storage/directory.rb index b03977c77..a94db0c20 100644 --- a/lib/fog/hp/models/storage/directory.rb +++ b/lib/fog/hp/models/storage/directory.rb @@ -7,10 +7,12 @@ module Fog class Directory < Fog::Model - identity :key, :aliases => 'name' + identity :key, :aliases => 'name' - attribute :bytes, :aliases => 'X-Container-Bytes-Used' - attribute :count, :aliases => 'X-Container-Object-Count' + attribute :bytes, :aliases => 'X-Container-Bytes-Used' + attribute :count, :aliases => 'X-Container-Object-Count' + attribute :sync_to, :aliases => 'X-Container-Sync-To' + attribute :sync_key, :aliases => 'X-Container-Sync-Key' def initialize(attributes = {}) @read_acl = [] @@ -205,10 +207,33 @@ module Fog end end + def sync(target_dir, secret) + requires :key + # do not sync if dir is same as target dir + return false if target_dir.key == key + begin service.head_container(key) + if !target_dir.nil? && target_dir.is_a?(Fog::Storage::HP::Directory) && target_dir.respond_to?(:public_url) && !target_dir.public_url.nil? + # set sync metadata on source dir + self.sync_to = target_dir.public_url + self.sync_key = secret + # set sync metadata on target dir + target_dir.sync_key = secret + target_dir.save + true + else + false + end + rescue Fog::Storage::HP::NotFound + false + end + end + def save(options = {}) requires :key # write out the acls into the headers before save options.merge!(service.perm_acl_to_header(@read_acl, @write_acl)) + options.merge!({'X-Container-Sync-To' => self.sync_to}) unless self.sync_to.nil? + options.merge!({'X-Container-Sync-Key' => self.sync_key}) unless self.sync_key.nil? service.put_container(key, options) # Added an extra check to see if CDN is enabled for the container if (!service.cdn.nil? && service.cdn.enabled?) diff --git a/lib/fog/hp/models/storage/files.rb b/lib/fog/hp/models/storage/files.rb index 46718124e..f97f66cf3 100644 --- a/lib/fog/hp/models/storage/files.rb +++ b/lib/fog/hp/models/storage/files.rb @@ -44,7 +44,7 @@ module Fog subset.each_file_this_page {|f| yield f} until subset.empty? || subset.length == (subset.limit || 10000) - subset = subset.all(:marker => subset.last.key) + subset = subset.all('marker' => subset.last.key) subset.each_file_this_page {|f| yield f} end diff --git a/lib/fog/hp/requests/compute/create_server.rb b/lib/fog/hp/requests/compute/create_server.rb index 4487c5eb3..26e10c652 100644 --- a/lib/fog/hp/requests/compute/create_server.rb +++ b/lib/fog/hp/requests/compute/create_server.rb @@ -63,15 +63,11 @@ module Fog 'name' => name } } - if options['metadata'] - data['server']['metadata'] = options['metadata'] - end - if options['accessIPv4'] - data['server']['accessIPv4'] = options['accessIPv4'] - end - if options['accessIPv6'] - data['server']['accessIPv6'] = options['accessIPv6'] + l_options = ['metadata', 'accessIPv4', 'accessIPv6', 'key_name', 'config_drive', 'user_data'] + l_options.select{|o| options[o]}.each do |key| + data['server'][key] = options[key] end + if options['personality'] data['server']['personality'] = [] for file in options['personality'] @@ -86,9 +82,6 @@ module Fog data['server']['min_count'] = min_count data['server']['max_count'] = max_count - if options['key_name'] - data['server']['key_name'] = options['key_name'] - end if options['security_groups'] data['server']['security_groups'] = [] for sg in options['security_groups'] @@ -97,9 +90,6 @@ module Fog } end end - if options['config_drive'] - data['server']['config_drive'] = options['config_drive'] - end request( :body => Fog::JSON.encode(data), diff --git a/lib/fog/hp/storage.rb b/lib/fog/hp/storage.rb index b42466500..60178d4be 100644 --- a/lib/fog/hp/storage.rb +++ b/lib/fog/hp/storage.rb @@ -291,6 +291,7 @@ module Fog response = @connection.request(params.merge!({ :headers => { 'Content-Type' => 'application/json', + 'Accept' => 'application/json', 'X-Auth-Token' => @auth_token }.merge!(params[:headers] || {}), :host => @host, @@ -316,6 +317,7 @@ module Fog response = @connection.request(params.merge!({ :headers => { 'Content-Type' => 'application/json', + 'Accept' => 'application/json', 'X-Auth-Token' => @auth_token }.merge!(params[:headers] || {}), :host => @host, diff --git a/lib/fog/libvirt/requests/compute/get_node_info.rb b/lib/fog/libvirt/requests/compute/get_node_info.rb index 1d1d037da..9903d7673 100644 --- a/lib/fog/libvirt/requests/compute/get_node_info.rb +++ b/lib/fog/libvirt/requests/compute/get_node_info.rb @@ -14,7 +14,7 @@ module Fog node_hash[:uri] = client.uri xml = client.sys_info rescue nil [:uuid, :manufacturer, :product, :serial].each do |attr| - node_hash[attr] = node_attr(attr, xml) + node_hash[attr] = node_attr(attr, xml) rescue nil end if xml node_hash[:hostname] = client.hostname diff --git a/lib/fog/openstack/README.identity.md b/lib/fog/openstack/README.identity.md deleted file mode 100644 index 3eea4fb97..000000000 --- a/lib/fog/openstack/README.identity.md +++ /dev/null @@ -1,69 +0,0 @@ -# OpenStack Identity Service (Keystone) Example - - require 'fog' - require 'pp' - - auth_url = "https://example.net/v2.0/tokens" - username = 'admin@example.net' - password = 'secret' - - keystone = Fog::Identity.new :provider => 'OpenStack', - :openstack_auth_url => auth_url, - :openstack_username => username, - :openstack_api_key => password - # Optional, self-signed certs - #:connection_options => { :ssl_verify_peer => false } - - # - # Listing keystone tenants - # - keystone.tenants.each do |tenant| - # - #pp tenant - end - - # - # List users - # - keystone.users.each do |user| - # - # ... - #pp user - end - - # - # Create a new tenant - # - tenant = keystone.tenants.create :name => 'rubiojr@example.net', - :description => 'My foo tenant' - - # - # Create a new user - # - user = keystone.users.create :name => 'rubiojr@example.net', - :tenant_id => tenant.id, - :password => 'rubiojr@example.net', - :email => 'rubiojr@example.net' - - - # Find the recently created tenant - tenant = keystone.tenants.find { |t| t.name == 'rubiojr@example.net' } - # Destroy the tenant - tenant.destroy - - # Find the recently created user - user = keystone.users.find { |u| u.name == 'rubiojr@example.net' } - # Destroy the user - user.destroy diff --git a/lib/fog/openstack/examples/identity/basics.rb b/lib/fog/openstack/examples/identity/basics.rb new file mode 100644 index 000000000..498f9b70a --- /dev/null +++ b/lib/fog/openstack/examples/identity/basics.rb @@ -0,0 +1,69 @@ +# OpenStack Identity Service (Keystone) Example + +require 'fog' +require 'pp' + +auth_url = "https://example.net/v2.0/tokens" +username = 'admin@example.net' +password = 'secret' + +keystone = Fog::Identity.new :provider => 'OpenStack', + :openstack_auth_url => auth_url, + :openstack_username => username, + :openstack_api_key => password + # Optional, self-signed certs + #:connection_options => { :ssl_verify_peer => false } + +# +# Listing keystone tenants +# +keystone.tenants.each do |tenant| + # + pp tenant +end + +# +# List users +# +keystone.users.each do |user| + # + # ... + pp user +end + +# +# Create a new tenant +# +tenant = keystone.tenants.create :name => 'rubiojr@example.net', + :description => 'My foo tenant' + +# +# Create a new user +# +user = keystone.users.create :name => 'rubiojr@example.net', + :tenant_id => tenant.id, + :password => 'rubiojr@example.net', + :email => 'rubiojr@example.net' + + +# Find the recently created tenant +tenant = keystone.tenants.find { |t| t.name == 'rubiojr@example.net' } +# Destroy the tenant +tenant.destroy + +# Find the recently created user +user = keystone.users.find { |u| u.name == 'rubiojr@example.net' } +# Destroy the user +user.destroy diff --git a/lib/fog/openstack/examples/image/upload-test-image.rb b/lib/fog/openstack/examples/image/upload-test-image.rb new file mode 100644 index 000000000..7f7dc1850 --- /dev/null +++ b/lib/fog/openstack/examples/image/upload-test-image.rb @@ -0,0 +1,77 @@ +require 'securerandom' +require 'rubygems/package' +require 'zlib' +require 'fog' + +# +# Download CirrOS 0.3.0 image from launchpad (~6.5MB) to /tmp +# and upload it to Glance (the OpenStack Image Service). +# +# You will need to source OpenStack credentials since the script +# reads the following envionment variables: +# +# OS_PASSWORD +# OS_USERNAME +# OS_AUTH_URL +# OS_TENANT_NAME +# +# Should work with Fog >= 1.9, ruby 1.8.7 and 2.0 +# +image_url = "https://launchpadlibrarian.net/83305869/cirros-0.3.0-x86_64-uec.tar.gz" +image_out = File.open("/tmp/cirros-image-#{SecureRandom.hex}", 'wb') +extract_path = "/tmp/cirros-#{SecureRandom.hex}-dir" +ami = "#{extract_path}/cirros-0.3.0-x86_64-blank.img" +aki = "#{extract_path}/cirros-0.3.0-x86_64-vmlinuz" +ari = "#{extract_path}/cirros-0.3.0-x86_64-initrd" + +FileUtils.mkdir_p extract_path + +# Efficient image write +puts "Downloading Cirros image..." +streamer = lambda do |chunk, remaining_bytes, total_bytes| + image_out.write chunk +end +Excon.get image_url, :response_block => streamer +image_out.close +puts "Image downloaded to #{image_out.path}" + +puts "Extracting image contents to #{extract_path}..." +Gem::Package::TarReader.new(Zlib::GzipReader.open(image_out.path)).each do |entry| + FileUtils.mkdir_p "#{extract_path}/#{File.dirname(entry.full_name)}" + File.open "#{extract_path}/#{entry.full_name}", 'w' do |f| + f.write entry.read + end +end + +image_service = Fog::Image.new({ + :provider => 'OpenStack', + :openstack_api_key => ENV['OS_PASSWORD'], + :openstack_username => ENV["OS_USERNAME"], + :openstack_auth_url => ENV["OS_AUTH_URL"] + "/tokens", + :openstack_tenant => ENV["OS_TENANT_NAME"] +}) + +puts "Uploading AKI..." +aki = image_service.images.create :name => 'cirros-0.3.0-amd64-aki', + :size => File.size(aki), + :disk_format => 'aki', + :container_format => 'aki', + :location => aki + +puts "Uploading ARI..." +ari = image_service.images.create :name => 'cirros-0.3.0-amd64-ari', + :size => File.size(ari), + :disk_format => 'ari', + :container_format => 'ari', + :location => ari + +puts "Uploading AMI..." +image_service.images.create :name => 'cirros-0.3.0-amd64', + :size => File.size(ami), + :disk_format => 'ami', + :container_format => 'ami', + :location => ami, + :properties => { + 'kernel_id' => aki.id, + 'ramdisk_id' => ari.id + } diff --git a/lib/fog/openstack/models/compute/server.rb b/lib/fog/openstack/models/compute/server.rb index 9f2433007..67aa855ec 100644 --- a/lib/fog/openstack/models/compute/server.rb +++ b/lib/fog/openstack/models/compute/server.rb @@ -40,7 +40,7 @@ module Fog attribute :os_ext_sts_vm_state, :aliases => 'OS-EXT-STS:vm_state' attr_reader :password - attr_writer :image_ref, :flavor_ref, :os_scheduler_hints + attr_writer :image_ref, :flavor_ref, :nics, :os_scheduler_hints def initialize(attributes={}) @@ -50,6 +50,7 @@ module Fog self.security_groups = attributes.delete(:security_groups) self.min_count = attributes.delete(:min_count) self.max_count = attributes.delete(:max_count) + self.nics = attributes.delete(:nics) self.os_scheduler_hints = attributes.delete(:os_scheduler_hints) super @@ -256,7 +257,8 @@ module Fog 'security_groups' => @security_groups, 'min_count' => @min_count, 'max_count' => @max_count, - 'os:scheduler_hints' => @os_scheduler_hints + 'nics' => @nics, + 'os:scheduler_hints' => @os_scheduler_hints, } options['metadata'] = metadata.to_hash unless @metadata.nil? options = options.reject {|key, value| value.nil?} diff --git a/lib/fog/openstack/models/network/floating_ip.rb b/lib/fog/openstack/models/network/floating_ip.rb index b38fc512e..40e2600f3 100644 --- a/lib/fog/openstack/models/network/floating_ip.rb +++ b/lib/fog/openstack/models/network/floating_ip.rb @@ -29,7 +29,7 @@ module Fog def create requires :floating_network_id - merge_attributes(connection.create_floating_ip(self.floating_network_id, + merge_attributes(service.create_floating_ip(self.floating_network_id, self.attributes).body['floatingip']) @@ -42,7 +42,7 @@ module Fog def destroy requires :id - connection.delete_floating_ip(self.id) + service.delete_floating_ip(self.id) true end diff --git a/lib/fog/openstack/models/network/floating_ips.rb b/lib/fog/openstack/models/network/floating_ips.rb index a7e081a65..9a827f015 100644 --- a/lib/fog/openstack/models/network/floating_ips.rb +++ b/lib/fog/openstack/models/network/floating_ips.rb @@ -17,7 +17,7 @@ module Fog def all(filters = filters) self.filters = filters - load(connection.list_floating_ips(filters).body['floatingips']) + load(service.list_floating_ips(filters).body['floatingips']) end def get(floating_network_id) diff --git a/lib/fog/openstack/models/network/router.rb b/lib/fog/openstack/models/network/router.rb new file mode 100644 index 000000000..047320e83 --- /dev/null +++ b/lib/fog/openstack/models/network/router.rb @@ -0,0 +1,56 @@ +require 'fog/core/model' + +module Fog + module Network + class OpenStack + # The Layer-3 Networking Extensions (router) + # + # A logical entity for forwarding packets across internal + # subnets and NATting them on external networks through + # an appropriate external gateway. + # + # @see http://docs.openstack.org/api/openstack-network/2.0/content/router_ext.html + class Router < Fog::Model + identity :id + + attribute :name + attribute :admin_state_up + attribute :tenant_id + attribute :external_gateway_info + attribute :status + + def initialize(attributes) + # Old 'connection' is renamed as service and should be used instead + prepare_service_value(attributes) + super + end + + def save + requires :name + identity ? update : create + end + + def create + requires :name + merge_attributes(service.create_router(self.name, + self.attributes).body['router']) + self + end + + def update + requires :id + merge_attributes(service.update_router(self.id, + self.attributes).body['router']) + self + end + + def destroy + requires :id + service.delete_router(self.id) + true + end + + end + end + end +end diff --git a/lib/fog/openstack/models/network/routers.rb b/lib/fog/openstack/models/network/routers.rb new file mode 100644 index 000000000..79892a00c --- /dev/null +++ b/lib/fog/openstack/models/network/routers.rb @@ -0,0 +1,34 @@ +require 'fog/core/collection' +require 'fog/openstack/models/network/router' + +module Fog + module Network + class OpenStack + class Routers < Fog::Collection + + attribute :filters + + model Fog::Network::OpenStack::Router + + def initialize(attributes) + self.filters ||= {} + super + end + + def all(filters = filters) + self.filters = filters + load(service.list_routers(filters).body['routers']) + end + + def get(router_id) + if router = service.get_router(router_id).body['router'] + new(router) + end + rescue Fog::Network::OpenStack::NotFound + nil + end + + end + end + end +end diff --git a/lib/fog/openstack/network.rb b/lib/fog/openstack/network.rb index 35cf4d979..71ce5ef04 100644 --- a/lib/fog/openstack/network.rb +++ b/lib/fog/openstack/network.rb @@ -21,6 +21,8 @@ module Fog collection :subnets model :floating_ip collection :floating_ips + model :router + collection :routers ## REQUESTS # @@ -55,6 +57,15 @@ module Fog request :associate_floating_ip request :disassociate_floating_ip + # Router CRUD + request :list_routers + request :create_router + request :delete_router + request :get_router + request :update_router + request :add_router_interface + request :remove_router_interface + # Tenant request :set_tenant @@ -66,6 +77,7 @@ module Fog :ports => {}, :subnets => {}, :floating_ips => {}, + :routers => {}, } end end diff --git a/lib/fog/openstack/requests/compute/create_server.rb b/lib/fog/openstack/requests/compute/create_server.rb index 467bbaec9..4e701196d 100644 --- a/lib/fog/openstack/requests/compute/create_server.rb +++ b/lib/fog/openstack/requests/compute/create_server.rb @@ -41,6 +41,17 @@ module Fog end end + if options['nics'] + data['server']['networks'] = + Array(options['nics']).map do |nic| + { + 'uuid' => nic['net_id'], + 'fixed_ip' => nic['v4_fixed_ip'], + 'port' => nic['port_id'] + } + end + end + if options['os:scheduler_hints'] data['os:scheduler_hints'] = options['os:scheduler_hints'] end diff --git a/lib/fog/openstack/requests/network/add_router_interface.rb b/lib/fog/openstack/requests/network/add_router_interface.rb new file mode 100644 index 000000000..afa4ca6ae --- /dev/null +++ b/lib/fog/openstack/requests/network/add_router_interface.rb @@ -0,0 +1,48 @@ +module Fog + module Network + class OpenStack + + class Real + def add_router_interface(router_id, subnet_id, options = {}) + data = { + 'subnet_id' => subnet_id, + } + + request( + :body => Fog::JSON.encode(data), + :expects => [200], + :method => 'PUT', + :path => "routers/#{router_id}/add_router_interface" + ) + end + end + + class Mock + def add_router_interface(router_id, subnet_id, options = {}) + response = Excon::Response.new + response.status = 201 + data = { + 'status' => 'ACTIVE', + 'name' => '', + 'admin_state_up' => true, + 'network_id' => '5307648b-e836-4658-8f1a-ff7536870c64', + 'tenant_id' => '6b96ff0cb17a4b859e1e575d221683d3', + 'device_owner' => 'network:router_interface', + 'mac_address' => 'fa:16:3e:f7:d1:9c', + 'fixed_ips' => { + 'subnet_id' => 'a2f1f29d-571b-4533-907f-5803ab96ead1', + 'ip_address' => '10.1.1.1' + }, + 'id' => '3a44f4e5-1694-493a-a1fb-393881c673a4', + 'device_id' => '7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b' + } + + self.data[:routers][data['router_id']] = data + response.body = { 'router' => data } + response + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/network/create_network.rb b/lib/fog/openstack/requests/network/create_network.rb index 77968b8a5..08902d2fd 100644 --- a/lib/fog/openstack/requests/network/create_network.rb +++ b/lib/fog/openstack/requests/network/create_network.rb @@ -6,11 +6,45 @@ module Fog def create_network(options = {}) data = { 'network' => {} } - vanilla_options = [:name, :shared, :admin_state_up, :tenant_id] + vanilla_options = [ + :name, + :shared, + :admin_state_up, + :tenant_id + ] + vanilla_options.reject{ |o| options[o].nil? }.each do |key| data['network'][key] = options[key] end + # Advanced Features through API Extensions + # + # Not strictly required but commonly found in OpenStack + # installs with Quantum networking. + # + # @see http://docs.openstack.org/trunk/openstack-network/admin/content/provider_attributes.html + provider_options = [ + :router_external, + :provider_network_type, + :provider_segmentation_id, + :provider_physical_network + ] + + # Map Fog::Network::OpenStack::Network + # model attributes to OpenStack provider attributes + aliases = { + :provider_network_type => 'provider:network_type', + # Not applicable to the "local" or "gre" network types + :provider_physical_network => 'provider:physical_network', + :provider_segmentation_id => 'provider:segmentation_id', + :router_external => 'router:external' + } + + provider_options.reject{ |o| options[o].nil? }.each do |key| + aliased_key = aliases[key] || key + data['network'][aliased_key] = options[key] + end + request( :body => Fog::JSON.encode(data), :expects => [201], @@ -33,6 +67,27 @@ module Fog 'admin_state_up' => options[:admin_state_up], 'tenant_id' => options[:tenant_id], } + + # Add provider specific attributes when found + # + provider_options = [ + :router_external, + :provider_network_type, + :provider_segmentation_id, + :provider_physical_network + ] + aliases = { + :provider_network_type => 'provider:network_type', + # Not applicable to the "local" or "gre" network types + :provider_physical_network => 'provider:physical_network', + :provider_segmentation_id => 'provider:segmentation_id', + :router_external => 'router:external' + } + provider_options.reject{ |o| options[o].nil? }.each do |key| + aliased_key = aliases[key] || key + data[aliased_key] = options[key] + end + self.data[:networks][data['id']] = data response.body = { 'network' => data } response @@ -41,4 +96,4 @@ module Fog end end -end \ No newline at end of file +end diff --git a/lib/fog/openstack/requests/network/create_router.rb b/lib/fog/openstack/requests/network/create_router.rb new file mode 100644 index 000000000..1b9a8dbdc --- /dev/null +++ b/lib/fog/openstack/requests/network/create_router.rb @@ -0,0 +1,58 @@ +module Fog + module Network + class OpenStack + + class Real + def create_router(name, options = {}) + data = { + 'router' => { + 'name' => name, + } + } + + vanilla_options = [ + :admin_state_up, + :tenant_id, + :network_id, + :external_gateway_info, + :status, + :subnet_id + ] + + vanilla_options.reject{ |o| options[o].nil? }.each do |key| + data['router'][key] = options[key] + end + + request( + :body => Fog::JSON.encode(data), + :expects => [201], + :method => 'POST', + :path => 'routers' + ) + end + end + + class Mock + def create_router(name, options = {}) + response = Excon::Response.new + response.status = 201 + data = { + 'router' => { + 'status' => 'ACTIVE', + 'external_gateway_info' => nil, + 'name' => 'another_router', + 'admin_state_up' => true, + 'tenant_id' => '6b96ff0cb17a4b859e1e575d221683d3', + 'id' => '8604a0de-7f6b-409a-a47c-a1cc7bc77b2e' + } + } + self.data['routers'] ||= [] + self.data['routers'] << data['router'] + response.body = data + response + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/network/delete_router.rb b/lib/fog/openstack/requests/network/delete_router.rb new file mode 100644 index 000000000..5f957aab3 --- /dev/null +++ b/lib/fog/openstack/requests/network/delete_router.rb @@ -0,0 +1,30 @@ +module Fog + module Network + class OpenStack + + class Real + def delete_router(router_id) + request( + :expects => 204, + :method => 'DELETE', + :path => "routers/#{router_id}" + ) + end + end + + class Mock + def delete_router(router_id) + response = Excon::Response.new + if list_routers.body['routers'].map { |r| r['id'] }.include? router_id + self.data[:routers].delete(router_id) + response.status = 204 + response + else + raise Fog::Network::OpenStack::NotFound + end + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/network/get_router.rb b/lib/fog/openstack/requests/network/get_router.rb new file mode 100644 index 000000000..7e58a7514 --- /dev/null +++ b/lib/fog/openstack/requests/network/get_router.rb @@ -0,0 +1,41 @@ +module Fog + module Network + class OpenStack + + class Real + def get_router(router_id) + request( + :expects => [200], + :method => 'GET', + :path => "routers/#{router_id}" + ) + end + end + + class Mock + def get_router(router_id) + response = Excon::Response.new + if data = (self.data['routers'].find { |r| r['id'] == router_id }) + response.status = 200 + response.body = { + 'router' => { + 'status' => 'ACTIVE', + 'external_gateway_info' => { + 'network_id' => '3c5bcddd-6af9-4e6b-9c3e-c153e521cab8' + }, + 'name' => 'router1', + 'admin_state_up' => true, + 'tenant_id' => '33a40233088643acb66ff6eb0ebea679', + 'id' => 'a9254bdb-2613-4a13-ac4c-adc581fba50d' + } + } + response + else + raise Fog::Network::OpenStack::NotFound + end + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/network/list_routers.rb b/lib/fog/openstack/requests/network/list_routers.rb new file mode 100644 index 000000000..18172f81b --- /dev/null +++ b/lib/fog/openstack/requests/network/list_routers.rb @@ -0,0 +1,27 @@ +module Fog + module Network + class OpenStack + + class Real + def list_routers(filters = {}) + request( + :expects => 200, + :method => 'GET', + :path => 'routers', + :query => filters + ) + end + end + + class Mock + def list_routers(filters = {}) + Excon::Response.new( + :body => { 'routers' => self.data['routers'] }, + :status => 200 + ) + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/network/remove_router_interface.rb b/lib/fog/openstack/requests/network/remove_router_interface.rb new file mode 100644 index 000000000..c822ab1c4 --- /dev/null +++ b/lib/fog/openstack/requests/network/remove_router_interface.rb @@ -0,0 +1,36 @@ +module Fog + module Network + class OpenStack + + class Real + def remove_router_interface(router_id, subnet_id, options = {}) + data = { + 'subnet_id' => subnet_id, + } + + request( + :body => Fog::JSON.encode(data), + :expects => [200], + :method => 'PUT', + :path => "routers/#{router_id}/remove_router_interface" + ) + end + end + + class Mock + def remove_router_interface(router_id, subnet_id, options = {}) + response = Excon::Response.new + response.status = 201 + data = { + 'subnet_id' => 'a2f1f29d-571b-4533-907f-5803ab96ead1' + } + + self.data[:routers][data['router_id']] = data + response.body = { 'router' => data } + response + end + end + + end + end +end diff --git a/lib/fog/openstack/requests/network/update_router.rb b/lib/fog/openstack/requests/network/update_router.rb new file mode 100644 index 000000000..19d5cda47 --- /dev/null +++ b/lib/fog/openstack/requests/network/update_router.rb @@ -0,0 +1,85 @@ +module Fog + module Network + class OpenStack + + class Real + + # Update Router + # + # Beyond the name and the administrative state, the only + # parameter which can be updated with this operation is + # the external gateway. + # + # router = Fog::Network[:openstack].routers.first + # net = Fog::Network[:openstack].networks.first + # + # # :external_gateway_info can be either a + # # Fog::Network::OpenStack::Network or a Hash + # # like { 'network_id' => network.id } + # Fog::Network[:openstack].update_router router.id, + # :name => 'foo', + # :external_gateway_info => net, + # :admin_state_up => true + # + # @see http://docs.openstack.org/api/openstack-network/2.0/content/router_update.html + def update_router(router_id, options = {}) + data = { 'router' => {} } + + vanilla_options = [:name, :admin_state_up] + + egi = options[:external_gateway_info] + if egi + if egi.is_a?(Fog::Network::OpenStack::Network) + data['router']['external_gateway_info'] = { 'network_id' => egi.id } + elsif egi.is_a?(Hash) and egi['network_id'] + data['router']['external_gateway_info'] = egi + else + raise ArgumentError.new('Invalid external_gateway_info attribute') + end + end + + vanilla_options.reject{ |o| options[o].nil? }.each do |key| + data['router'][key] = options[key] + end + + request( + :body => Fog::JSON.encode(data), + :expects => 200, + :method => 'PUT', + :path => "routers/#{router_id}.json" + ) + end + end + + class Mock + def update_router(router_id, options = {}) + router = self.data['routers'].find { |r| r['id'] == router_id } + raise Fog::Network::OpenStack::NotFound unless router + data = { 'router' => router } + + vanilla_options = [:name, :admin_state_up] + + egi = options[:external_gateway_info] + if egi + if egi.is_a?(Fog::Network::OpenStack::Network) + data['router']['external_gateway_info'] = { 'network_id' => egi.id } + elsif egi.is_a?(Hash) and egi['network_id'] + data['router']['external_gateway_info'] = egi + else + raise ArgumentError.new('Invalid external_gateway_info attribute') + end + end + + vanilla_options.reject{ |o| options[o].nil? }.each do |key| + data['router'][key] = options[key] + end + response = Excon::Response.new + response.status = 201 + response.body = data + response + end + end + + end + end +end diff --git a/lib/fog/rackspace/compute_v2.rb b/lib/fog/rackspace/compute_v2.rb index 41d5ee504..f992a0638 100644 --- a/lib/fog/rackspace/compute_v2.rb +++ b/lib/fog/rackspace/compute_v2.rb @@ -103,8 +103,7 @@ module Fog @rackspace_api_key = options[:rackspace_api_key] @rackspace_username = options[:rackspace_username] @rackspace_auth_url = options[:rackspace_auth_url] - @rackspace_endpoint = options[:rackspace_compute_url] || options[:rackspace_endpoint] - @rackspace_region = options[:rackspace_region] || :dfw + setup_custom_endpoint(options) @rackspace_must_reauthenticate = false @connection_options = options[:connection_options] || {} @@ -124,7 +123,7 @@ module Fog 'Accept' => 'application/json', 'X-Auth-Token' => auth_token }.merge!(params[:headers] || {}), - :host => @uri.host, + :host => endpoint_uri.host, :path => "#{endpoint_uri.path}/#{params[:path]}" })) rescue Excon::Errors::NotFound => error @@ -170,16 +169,37 @@ module Fog private + def setup_custom_endpoint(options) + @rackspace_endpoint = 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] || :dfw + end + 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(:cloudServersOpenStack) - Fog::Logger.deprecation("Please specify region using :rackspace_region rather than :rackspace_endpoint. Valid region for :rackspace_region are #{regions}.") + 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 setup_endpoint(credentials) + 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 @@ -189,7 +209,7 @@ module Fog def authenticate_v1(options) credentials = Fog::Rackspace.authenticate(options, @connection_options) - setup_endpoint credentials + append_tenant_v1 credentials @auth_token = credentials['X-Auth-Token'] end end diff --git a/lib/fog/rackspace/examples/compute_v2/create_image.rb b/lib/fog/rackspace/examples/compute_v2/create_image.rb index 58048f854..52ded23b5 100644 --- a/lib/fog/rackspace/examples/compute_v2/create_image.rb +++ b/lib/fog/rackspace/examples/compute_v2/create_image.rb @@ -40,7 +40,7 @@ service = Fog::Compute.new({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key, :version => :v2, # Use Next Gen Cloud Servers - :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT #Use Chicago Region + :rackspace_region => :ord #Use Chicago Region }) # retrieve list of servers diff --git a/lib/fog/rackspace/examples/compute_v2/create_server.rb b/lib/fog/rackspace/examples/compute_v2/create_server.rb index d519d031b..342507937 100644 --- a/lib/fog/rackspace/examples/compute_v2/create_server.rb +++ b/lib/fog/rackspace/examples/compute_v2/create_server.rb @@ -29,7 +29,7 @@ service = Fog::Compute.new({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key, :version => :v2, # Use Next Gen Cloud Servers - :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT #Use Chicago Region + :rackspace_region => :ord #Use Chicago Region }) # pick the first flavor diff --git a/lib/fog/rackspace/examples/compute_v2/delete_image.rb b/lib/fog/rackspace/examples/compute_v2/delete_image.rb index 779db40d0..9508de2d1 100644 --- a/lib/fog/rackspace/examples/compute_v2/delete_image.rb +++ b/lib/fog/rackspace/examples/compute_v2/delete_image.rb @@ -40,7 +40,7 @@ service = Fog::Compute.new({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key, :version => :v2, # Use Next Gen Cloud Servers - :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT #Use Chicago Region + :rackspace_region => :ord #Use Chicago Region }) # retrieve list of images diff --git a/lib/fog/rackspace/examples/compute_v2/delete_server.rb b/lib/fog/rackspace/examples/compute_v2/delete_server.rb index cd37d268a..b01419dc4 100644 --- a/lib/fog/rackspace/examples/compute_v2/delete_server.rb +++ b/lib/fog/rackspace/examples/compute_v2/delete_server.rb @@ -40,7 +40,7 @@ service = Fog::Compute.new({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key, :version => :v2, # Use Next Gen Cloud Servers - :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT #Use Chicago Region + :rackspace_region => :ord #Use Chicago Region }) #retrieve list of servers diff --git a/lib/fog/rackspace/examples/compute_v2/detach_volume.rb b/lib/fog/rackspace/examples/compute_v2/detach_volume.rb index 85f01fbb9..189b4b2a2 100644 --- a/lib/fog/rackspace/examples/compute_v2/detach_volume.rb +++ b/lib/fog/rackspace/examples/compute_v2/detach_volume.rb @@ -52,7 +52,7 @@ compute_service = Fog::Compute.new({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key, :version => :v2, # Use Next Gen Cloud Servers - :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT #Use Chicago Region + :rackspace_region => :ord #Use Chicago Region }) cbs_service = Fog::Rackspace::BlockStorage.new({ diff --git a/lib/fog/rackspace/examples/compute_v2/resize_server.rb b/lib/fog/rackspace/examples/compute_v2/resize_server.rb index c404a47cd..b909ba153 100644 --- a/lib/fog/rackspace/examples/compute_v2/resize_server.rb +++ b/lib/fog/rackspace/examples/compute_v2/resize_server.rb @@ -51,7 +51,7 @@ service = Fog::Compute.new({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key, :version => :v2, # Use Next Gen Cloud Servers - :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT #Use Chicago Region + :rackspace_region => :ord #Use Chicago Region }) #retrieve list of servers diff --git a/lib/fog/rackspace/examples/compute_v2/server_attachments.rb b/lib/fog/rackspace/examples/compute_v2/server_attachments.rb index 345ab846e..11a12f197 100644 --- a/lib/fog/rackspace/examples/compute_v2/server_attachments.rb +++ b/lib/fog/rackspace/examples/compute_v2/server_attachments.rb @@ -40,7 +40,7 @@ compute_service = Fog::Compute.new({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key, :version => :v2, # Use Next Gen Cloud Servers - :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT #Use Chicago Region + :rackspace_region => :ord #Use Chicago Region }) cbs_service = Fog::Rackspace::BlockStorage.new({ diff --git a/lib/fog/rackspace/examples/compute_v2/server_metadata.rb b/lib/fog/rackspace/examples/compute_v2/server_metadata.rb index 1f9bdac18..56e36f7bd 100644 --- a/lib/fog/rackspace/examples/compute_v2/server_metadata.rb +++ b/lib/fog/rackspace/examples/compute_v2/server_metadata.rb @@ -30,7 +30,7 @@ service = Fog::Compute.new({ :rackspace_username => rackspace_username, :rackspace_api_key => rackspace_api_key, :version => :v2, # Use Next Gen Cloud Servers - :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT #Use Chicago Region + :rackspace_region => :ord #Use Chicago Region }) # Pick the first flavor diff --git a/lib/fog/rackspace/models/dns/zones.rb b/lib/fog/rackspace/models/dns/zones.rb index b9524cf5b..9de234f25 100644 --- a/lib/fog/rackspace/models/dns/zones.rb +++ b/lib/fog/rackspace/models/dns/zones.rb @@ -8,21 +8,17 @@ module Fog model Fog::DNS::Rackspace::Zone + # List all domains. Return by default a maximum of 100 items + # @param [Hash] options Options to pass to the underlying API call + # @option options [String] :name search for domains containing the given substring + # @option options [Integer] :limit number of records to return + # @option options [Integer] :offset starting offset of records to return def all(options={}) clear data = service.list_domains(options).body['domains'] load(data) end - # Returns all domains containing the given substring. Still limited - # by the 100-domain pagination limit. Returns an empty array if - # no matches. - def find(substring) - clear - data = service.list_domains(:name => substring).body['domains'] - load(data) - end - alias :each_zone_this_page :each def each if !block_given? diff --git a/lib/fog/rackspace/models/storage/file.rb b/lib/fog/rackspace/models/storage/file.rb index ab24a5f8d..42d5744d0 100644 --- a/lib/fog/rackspace/models/storage/file.rb +++ b/lib/fog/rackspace/models/storage/file.rb @@ -19,6 +19,8 @@ module Fog # @see http://www.iana.org/assignments/media-types attribute :content_type, :aliases => ['content_type', 'Content-Type'] + attribute :content_disposition, :aliases => 'Content-Disposition' + # @!attribute [rw] etag # The MD5 checksum of file. If included file creation request, will ensure integrity of the file. # @return [String] MD5 checksum of file. @@ -170,6 +172,7 @@ module Fog options['Content-Type'] = content_type if content_type options['Access-Control-Allow-Origin'] = access_control_allow_origin if access_control_allow_origin options['Origin'] = origin if origin + options['Content-Disposition'] = content_disposition if content_disposition options.merge!(metadata.to_headers) data = service.put_object(directory.key, key, body, options) diff --git a/lib/fog/rackspace/service.rb b/lib/fog/rackspace/service.rb index 5e75cea5d..3d0256231 100644 --- a/lib/fog/rackspace/service.rb +++ b/lib/fog/rackspace/service.rb @@ -33,22 +33,21 @@ module Fog private def authentication_method - return :authenticate_v2 unless @rackspace_auth_url - if @rackspace_auth_url =~ /v2(\.\d)?\w*$/ + if v2_authentication? :authenticate_v2 else Fog::Logger.deprecation "Authentication using a v1.0/v1.1 endpoint is deprecated. Please specify a v2.0 endpoint using :rackpace_auth_url.\ For a list of v2.0 endpoints refer to http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/Endpoints-d1e180.html" :authenticate_v1 - end + end end def v1_authentication? - @identity_service.nil? + !v2_authentication? end def v2_authentication? - @identity_service != nil + @rackspace_auth_url.nil? || @rackspace_auth_url =~ /v2(\.\d)?\w*$/ end def authenticate_v2(identity_options) diff --git a/lib/fog/vcloud/requests/compute/configure_vm_network.rb b/lib/fog/vcloud/requests/compute/configure_vm_network.rb index 8d657c043..5d18ddb74 100644 --- a/lib/fog/vcloud/requests/compute/configure_vm_network.rb +++ b/lib/fog/vcloud/requests/compute/configure_vm_network.rb @@ -19,7 +19,6 @@ module Fog EOF - print "Request: #{body}" request( :body => body, :expects => 202, diff --git a/lib/fog/vsphere/models/compute/servers.rb b/lib/fog/vsphere/models/compute/servers.rb index 46672e4b5..727b873f2 100644 --- a/lib/fog/vsphere/models/compute/servers.rb +++ b/lib/fog/vsphere/models/compute/servers.rb @@ -17,13 +17,15 @@ module Fog # 'folder' => '/Datacenters/vm/Jeff/Templates' will be MUCH faster. # than simply listing everything. def all(filters = { }) - load service.list_virtual_machines(filters.merge( - :datacenter => datacenter, - :cluster => cluster, - :network => network, - :resource_pool => resource_pool, - :folder => folder - )) + f = { + :datacenter => datacenter, + :cluster => cluster, + :network => network, + :resource_pool => resource_pool, + :folder => folder + }.merge(filters) + + load service.list_virtual_machines(f) end def get(id, datacenter = nil) @@ -31,9 +33,7 @@ module Fog rescue Fog::Compute::Vsphere::NotFound nil end - end - end end end diff --git a/lib/fog/zerigo/models/dns/records.rb b/lib/fog/zerigo/models/dns/records.rb index 5682a7532..eca25255d 100644 --- a/lib/fog/zerigo/models/dns/records.rb +++ b/lib/fog/zerigo/models/dns/records.rb @@ -10,15 +10,23 @@ module Fog attribute :zone model Fog::DNS::Zerigo::Record - - def all + + # List all domains + # @param [Hash] options Options to pass to the underlying API call + # @option options [String] :fqdn search for the given fqdn + def all(options = {}) requires :zone - parent = zone.collection.get(zone.identity) - if parent - merge_attributes(parent.records.attributes) - load(parent.records.map {|record| record.attributes}) + if options[:fqdn] + hosts = service.find_hosts(options[:fqdn], zone.id).body['hosts'] + load(hosts) else - nil + parent = zone.collection.get(zone.identity) + if parent + merge_attributes(parent.records.attributes) + load(parent.records.map {|record| record.attributes}) + else + nil + end end end @@ -34,11 +42,6 @@ module Fog super({ :zone => zone }.merge!(attributes)) end - def find(fqdn) - hosts = service.find_hosts(fqdn, zone.id).body['hosts'] - hosts.collect { |host| new(host) } - end - end end diff --git a/tests/aws/requests/iam/server_certificate_tests.rb b/tests/aws/requests/iam/server_certificate_tests.rb index 6f835863d..aec71b3db 100644 --- a/tests/aws/requests/iam/server_certificate_tests.rb +++ b/tests/aws/requests/iam/server_certificate_tests.rb @@ -13,6 +13,9 @@ Shindo.tests('AWS::IAM | server certificate requests', ['aws']) do 'Certificate' => @certificate_format, 'RequestId' => String } + @update_format = { + 'RequestId' => String + } @get_server_certificate_format = { 'Certificate' => @certificate_format, 'RequestId' => String @@ -64,6 +67,35 @@ Shindo.tests('AWS::IAM | server certificate requests', ['aws']) do end end + tests('#update_server_certificate') do + public_key = AWS::IAM::SERVER_CERT_PUBLIC_KEY + private_key = AWS::IAM::SERVER_CERT_PRIVATE_KEY + key_name = "update-key" + + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key, key_name) + + tests('duplicate name').raises(Fog::AWS::IAM::EntityAlreadyExists) do + other_key_name = "other-key-name" + Fog::AWS::IAM.new.upload_server_certificate(public_key, private_key, other_key_name) + + Fog::AWS::IAM.new.update_server_certificate(key_name, {'NewServerCertificateName' => other_key_name}) + end + + tests('unknown name').raises(Fog::AWS::IAM::NotFound) do + Fog::AWS::IAM.new.update_server_certificate("unknown-key-name", {'NewServerCertificateName' => "other-keyname"}) + end + + tests('format').formats(@update_format) do + Fog::AWS::IAM.new.update_server_certificate(key_name).body + end + + tests('updates name') do + other_key_name = "successful-update-key-name" + Fog::AWS::IAM.new.update_server_certificate(key_name, {'NewServerCertificateName' => other_key_name}) + returns(true) { Fog::AWS::IAM.new.get_server_certificate(other_key_name).body['Certificate']['ServerCertificateName'] == other_key_name } + end + end + tests('#get_server_certificate').formats(@get_server_certificate_format) do tests('raises NotFound').raises(Fog::AWS::IAM::NotFound) do Fog::AWS::IAM.new.get_server_certificate("#{@key_name}fake") diff --git a/tests/helpers/collection_helper.rb b/tests/helpers/collection_helper.rb index c37493fec..b5168a46f 100644 --- a/tests/helpers/collection_helper.rb +++ b/tests/helpers/collection_helper.rb @@ -21,6 +21,8 @@ def collection_tests(collection, params = {}, mocks_implemented = true) pending if Fog.mocking? && !mocks_implemented collection.all end + + if !Fog.mocking? || mocks_implemented @identity = @instance.identity @@ -31,6 +33,39 @@ def collection_tests(collection, params = {}, mocks_implemented = true) collection.get(@identity) end + tests('Enumerable') do + pending if Fog.mocking? && !mocks_implemented + + [ + 'all?', 'any?', 'find', 'detect', 'collect', 'map', + 'find_index', 'flat_map', 'collect_concat', 'group_by', + 'none?', 'one?' + ].each do |enum_method| + if collection.respond_to?(enum_method) + tests("##{enum_method}").succeeds do + block_called = false + collection.send(enum_method) {|x| block_called = true } + block_called + end + end + end + + [ + 'max_by','min_by' + ].each do |enum_method| + if collection.respond_to?(enum_method) + tests("##{enum_method}").succeeds do + block_called = false + collection.send(enum_method) {|x| block_called = true; 0 } + block_called + end + end + + end + + end + + if block_given? yield end @@ -39,7 +74,7 @@ def collection_tests(collection, params = {}, mocks_implemented = true) @instance.destroy end end - + tests('failure') do if !Fog.mocking? || mocks_implemented diff --git a/tests/openstack/models/network/network_tests.rb b/tests/openstack/models/network/network_tests.rb index 28491f9f2..4dca50d2a 100644 --- a/tests/openstack/models/network/network_tests.rb +++ b/tests/openstack/models/network/network_tests.rb @@ -10,6 +10,23 @@ Shindo.tests("Fog::Network[:openstack] | network", ['openstack']) do !@instance.id.nil? end + tests('#create+extensions').succeeds do + net = Fog::Network[:openstack].networks.create( + :name => 'net_name', + :shared => false, + :admin_state_up => true, + :tenant_id => 'tenant_id', + :router_external => true, + # local, gre, vlan. Depends on the provider. + # May rise an exception if the network_type isn't valid: + # QuantumError: "Invalid input for operation: provider:physical_network" + :provider_network_type => 'gre', + :provider_segmentation_id => 22 + ) + net.destroy + net.provider_network_type == 'gre' + end + tests('have attributes') do attributes = [ :name, diff --git a/tests/openstack/models/network/router_tests.rb b/tests/openstack/models/network/router_tests.rb new file mode 100644 index 000000000..9390fe8ee --- /dev/null +++ b/tests/openstack/models/network/router_tests.rb @@ -0,0 +1,38 @@ +Shindo.tests("Fog::Network[:openstack] | router", ['openstack']) do + + tests('success') do + + tests('#create').succeeds do + @instance = Fog::Network[:openstack].routers.create( + :name => 'router_name', + :admin_state_up => true + ) + !@instance.id.nil? + end + + tests('#update') do + test 'router name' do + @instance.name = 'new_name' + @instance.update.name == 'new_name' + end + # Needs code from issue #1598 + #test 'external_gateway_info' do + # net = Fog::Network[:openstack].networks.create( + # :name => 'net_name', + # :shared => false, + # :admin_state_up => true, + # :tenant_id => 'tenant_id', + # :router_external => true, + # ) + # @instance.external_gateway_info = net + # @instance.update + #end + end + + tests('#destroy').succeeds do + @instance.destroy == true + end + + end + +end diff --git a/tests/openstack/models/network/routers_tests.rb b/tests/openstack/models/network/routers_tests.rb new file mode 100644 index 000000000..f21014a1d --- /dev/null +++ b/tests/openstack/models/network/routers_tests.rb @@ -0,0 +1,21 @@ +Shindo.tests("Fog::Network[:openstack] | routers", ['openstack']) do + @router = Fog::Network[:openstack].routers.create( + :name => 'router_name', + :admin_state_up => true + ) + @routers = Fog::Network[:openstack].routers + + tests('success') do + + tests('#all').succeeds do + @routers.all + end + + tests('#get').succeeds do + @routers.get @router.id + end + + end + + @router.destroy +end diff --git a/tests/openstack/requests/network/network_tests.rb b/tests/openstack/requests/network/network_tests.rb index cb6f4a890..ad1c32337 100644 --- a/tests/openstack/requests/network/network_tests.rb +++ b/tests/openstack/requests/network/network_tests.rb @@ -1,19 +1,47 @@ Shindo.tests('Fog::Network[:openstack] | network requests', ['openstack']) do @network_format = { - 'id' => String, - 'name' => String, - 'subnets' => Array, - 'shared' => Fog::Boolean, - 'status' => String, - 'admin_state_up' => Fog::Boolean, - 'tenant_id' => String, + 'id' => String, + 'name' => String, + 'subnets' => Array, + 'shared' => Fog::Boolean, + 'status' => String, + 'admin_state_up' => Fog::Boolean, + 'tenant_id' => String + } + + @network_format_extensions = { + 'router:external' => Fog::Boolean, + 'provider:network_type' => String, + 'provider:physical_network' => Fog::Nullable::String, + 'provider:segmentation_id' => Integer } tests('success') do tests('#create_network').formats({'network' => @network_format}) do - attributes = {:name => 'net_name', :shared => false, - :admin_state_up => true, :tenant_id => 'tenant_id'} + attributes = { + :name => 'net_name', + :shared => false, + :admin_state_up => true, + :tenant_id => 'tenant_id' + } + Fog::Network[:openstack].create_network(attributes).body + end + tests('#create_network+provider extensions').formats( + {'network' => @network_format.merge(@network_format_extensions)} + ) do + attributes = { + :name => 'net_name', + :shared => false, + :admin_state_up => true, + :tenant_id => 'tenant_id', + :router_external => true, + # local, gre, vlan. Depends on the provider. + # May rise an exception if the network_type isn't valid: + # QuantumError: "Invalid input for operation: provider:physical_network" + :provider_network_type => 'gre', + :provider_segmentation_id => 22, + } Fog::Network[:openstack].create_network(attributes).body end @@ -40,6 +68,24 @@ Shindo.tests('Fog::Network[:openstack] | network requests', ['openstack']) do end tests('failure') do + tests('#create_network+provider extensions').raises( + Excon::Errors::BadRequest + ) do + pending if Fog.mocking? + + attributes = { + :name => 'net_name', + :shared => false, + :admin_state_up => true, + :tenant_id => 'tenant_id', + :router_external => true, + # QuantumError: "Invalid input for operation: provider:physical_network" + :provider_network_type => 'foobar', + :provider_segmentation_id => 22, + } + Fog::Network[:openstack].create_network(attributes) + end + tests('#get_network').raises(Fog::Network::OpenStack::NotFound) do Fog::Network[:openstack].get_network(0) end @@ -52,5 +98,10 @@ Shindo.tests('Fog::Network[:openstack] | network requests', ['openstack']) do Fog::Network[:openstack].delete_network(0) end end + + # Cleaning up the mess + Fog::Network[:openstack].networks.each do |n| + Fog::Network[:openstack].delete_network(n.id) + end -end \ No newline at end of file +end diff --git a/tests/openstack/requests/network/router_tests.rb b/tests/openstack/requests/network/router_tests.rb new file mode 100644 index 000000000..a0df1a6e2 --- /dev/null +++ b/tests/openstack/requests/network/router_tests.rb @@ -0,0 +1,75 @@ +Shindo.tests('Fog::Network[:openstack] | router requests', ['openstack']) do + + @router_format = { + 'id' => String, + 'name' => String, + 'status' => String, + 'admin_state_up' => Fog::Boolean, + 'tenant_id' => String, + 'external_gateway_info' => Fog::Nullable::Hash, + } + + tests('success') do + tests('#create_router').formats({'router' => @router_format}) do + attributes = { + :admin_state_up => true, + :tenant_id => 'tenant_id' + } + Fog::Network[:openstack].create_router('router_name', attributes).body + end + + tests('#list_routers').formats({'routers' => [@router_format]}) do + Fog::Network[:openstack].list_routers.body + end + + tests('#get_router').formats({'router' => @router_format}) do + router_id = Fog::Network[:openstack].routers.all.first.id + Fog::Network[:openstack].get_router(router_id).body + end + + tests('#update_router').formats({'router' => @router_format}) do + router_id = Fog::Network[:openstack].routers.all.first.id + attributes = {} + { + :name => 'net_name', + :external_gateway_info => { :network_id => 'net_id' }, + :status => 'ACTIVE', + :admin_state_up => 'true' + } + Fog::Network[:openstack].update_router(router_id, attributes).body + end + + tests('#update_router_with_network').formats({'router' => @router_format}) do + router_id = Fog::Network[:openstack].routers.all.first.id + net = Fog::Network[:openstack].networks.first + attributes = {} + { + :name => 'net_name', + :external_gateway_info => net, + :status => 'ACTIVE', + :admin_state_up => 'true' + } + Fog::Network[:openstack].update_router(router_id, attributes).body + end + + tests('#delete_router').succeeds do + router_id = Fog::Network[:openstack].routers.all.last.id + Fog::Network[:openstack].delete_router(router_id) + end + end + + tests('failure') do + tests('#get_router').raises(Fog::Network::OpenStack::NotFound) do + Fog::Network[:openstack].get_router(0) + end + + tests('#update_router').raises(Fog::Network::OpenStack::NotFound) do + Fog::Network[:openstack].update_router(0, {}) + end + + tests('#delete_router').raises(Fog::Network::OpenStack::NotFound) do + Fog::Network[:openstack].delete_router(0) + end + end + +end diff --git a/tests/rackspace/cdn_tests.rb b/tests/rackspace/cdn_tests.rb index 1ffc1aa8a..66745157a 100644 --- a/tests/rackspace/cdn_tests.rb +++ b/tests/rackspace/cdn_tests.rb @@ -6,7 +6,7 @@ Shindo.tests('Fog::CDN::Rackspace', ['rackspace']) do end tests('#authentication_method') do - @service = Fog::Storage::Rackspace.new + @service = Fog::CDN::Rackspace.new assert_method nil, :authenticate_v2 diff --git a/tests/rackspace/compute_v2_tests.rb b/tests/rackspace/compute_v2_tests.rb index 0ffc86e31..5b5d31763 100644 --- a/tests/rackspace/compute_v2_tests.rb +++ b/tests/rackspace/compute_v2_tests.rb @@ -6,7 +6,7 @@ Shindo.tests('Fog::Compute::RackspaceV2', ['rackspace']) do end tests('#authentication_method') do - @service = Fog::Storage::Rackspace.new + @service = Fog::Compute::RackspaceV2.new assert_method nil, :authenticate_v2 @@ -30,7 +30,7 @@ Shindo.tests('Fog::Compute::RackspaceV2', ['rackspace']) do tests('variables populated') do returns(true, "auth token populated") { !@service.send(:auth_token).nil? } returns(false, "path populated") { @service.instance_variable_get("@uri").path.nil? } - returns(true, "identity_service was not used") { @service.instance_variable_get("@identity_service").nil? } + returns(true, "identity_service was not used") { @service.instance_variable_get("@identity_service").nil? } end tests('custom endpoint') do @@ -76,6 +76,10 @@ Shindo.tests('Fog::Compute::RackspaceV2', ['rackspace']) do returns(true, "auth token populated") { !@service.send(:auth_token).nil? } returns(true) { (@service.instance_variable_get("@uri").host =~ /dfw/) != nil } end + tests('specify old contstant style service endoint').succeeds do + @service = Fog::Compute::RackspaceV2.new :rackspace_endpoint => Fog::Compute::RackspaceV2::ORD_ENDPOINT + @service.list_flavors + end tests('specify region') do @service = Fog::Compute::RackspaceV2.new :rackspace_region => :ord returns(true, "auth token populated") { !@service.send(:auth_token).nil? } diff --git a/tests/rackspace/models/storage/file_tests.rb b/tests/rackspace/models/storage/file_tests.rb index e0c218ad3..399330d54 100644 --- a/tests/rackspace/models/storage/file_tests.rb +++ b/tests/rackspace/models/storage/file_tests.rb @@ -2,8 +2,12 @@ Shindo.tests('Fog::Rackspace::Storage | file', ['rackspace']) do pending if Fog.mocking? + def object_attributes(file=@instance) + @instance.service.head_object(@directory.key, file.key).headers + end + def object_meta_attributes(file=@instance) - @instance.service.head_object(@directory.key, file.key).headers.reject {|k, v| !(k =~ /X-Object-Meta-/)} + object_attributes(file).reject {|k, v| !(k =~ /X-Object-Meta-/)} end def clear_metadata @@ -85,6 +89,11 @@ Shindo.tests('Fog::Rackspace::Storage | file', ['rackspace']) do @file = @directory.files.create :key => 'meta-test', :body => lorem_file, :metadata => {:works => true } object_meta_attributes(@file)["X-Object-Meta-Works"] end + + tests("sets Content-Disposition on create").returns("ho-ho-ho") do + @file = @directory.files.create :key => 'meta-test', :body => lorem_file, :content_disposition => 'ho-ho-ho' + object_attributes(@file)["Content-Disposition"] + end ensure @file.destroy if @file end