From 316618a8c88ff53b72b5481ed5c2da8ce79fe382 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Fri, 19 Oct 2012 21:08:44 +0530 Subject: [PATCH 1/2] [Brightbox] Updates to add collaborations Adds requests and models for collaborations --- lib/fog/brightbox/compute.rb | 17 +++++ .../brightbox/models/compute/collaboration.rb | 43 ++++++++++++ .../models/compute/collaborations.rb | 23 +++++++ .../models/compute/user_collaboration.rb | 29 ++++++++ .../models/compute/user_collaborations.rb | 23 +++++++ .../compute/accept_user_collaboration.rb | 21 ++++++ .../requests/compute/create_collaboration.rb | 23 +++++++ .../requests/compute/delete_collaboration.rb | 28 ++++++++ .../compute/delete_user_collaboration.rb | 28 ++++++++ .../compute/destroy_user_collaboration.rb | 21 ++++++ .../requests/compute/get_collaboration.rb | 21 ++++++ .../compute/get_user_collaboration.rb | 21 ++++++ .../requests/compute/list_collaborations.rb | 19 ++++++ .../compute/list_user_collaborations.rb | 19 ++++++ .../compute/reject_user_collaboration.rb | 21 ++++++ .../requests/compute/resend_collaboration.rb | 21 ++++++ .../requests/compute/collaboration_tests.rb | 41 ++++++++++++ tests/brightbox/requests/compute/helper.rb | 48 ++++++++++++- .../compute/user_collaboration_tests.rb | 67 +++++++++++++++++++ 19 files changed, 532 insertions(+), 2 deletions(-) create mode 100644 lib/fog/brightbox/models/compute/collaboration.rb create mode 100644 lib/fog/brightbox/models/compute/collaborations.rb create mode 100644 lib/fog/brightbox/models/compute/user_collaboration.rb create mode 100644 lib/fog/brightbox/models/compute/user_collaborations.rb create mode 100644 lib/fog/brightbox/requests/compute/accept_user_collaboration.rb create mode 100644 lib/fog/brightbox/requests/compute/create_collaboration.rb create mode 100644 lib/fog/brightbox/requests/compute/delete_collaboration.rb create mode 100644 lib/fog/brightbox/requests/compute/delete_user_collaboration.rb create mode 100644 lib/fog/brightbox/requests/compute/destroy_user_collaboration.rb create mode 100644 lib/fog/brightbox/requests/compute/get_collaboration.rb create mode 100644 lib/fog/brightbox/requests/compute/get_user_collaboration.rb create mode 100644 lib/fog/brightbox/requests/compute/list_collaborations.rb create mode 100644 lib/fog/brightbox/requests/compute/list_user_collaborations.rb create mode 100644 lib/fog/brightbox/requests/compute/reject_user_collaboration.rb create mode 100644 lib/fog/brightbox/requests/compute/resend_collaboration.rb create mode 100644 tests/brightbox/requests/compute/collaboration_tests.rb create mode 100644 tests/brightbox/requests/compute/user_collaboration_tests.rb diff --git a/lib/fog/brightbox/compute.rb b/lib/fog/brightbox/compute.rb index 3e21628219..ecb25a1719 100644 --- a/lib/fog/brightbox/compute.rb +++ b/lib/fog/brightbox/compute.rb @@ -34,6 +34,8 @@ class Brightbox < Fog::Service model :application collection :api_clients model :api_client + collection :collaborations + model :collaboration collection :servers model :server collection :server_groups @@ -54,17 +56,22 @@ class Brightbox < Fog::Service model :cloud_ip collection :users model :user + collection :user_collaborations + model :user_collaboration request_path 'fog/brightbox/requests/compute' + request :accept_user_collaboration request :activate_console_server request :add_listeners_load_balancer request :add_nodes_load_balancer request :add_servers_server_group request :apply_to_firewall_policy + request :accept_user_collaboration request :remove_firewall_policy request :create_api_client request :create_application request :create_cloud_ip + request :create_collaboration request :create_firewall_policy request :create_firewall_rule request :create_image @@ -74,17 +81,20 @@ class Brightbox < Fog::Service request :delete_api_client request :delete_application request :delete_cloud_ip + request :delete_collaboration request :delete_firewall_policy request :delete_firewall_rule request :delete_image request :delete_load_balancer request :delete_server request :delete_server_group + request :delete_user_collaboration request :get_account request :get_api_client request :get_application request :get_authenticated_user request :get_cloud_ip + request :get_collaboration request :get_firewall_policy request :get_firewall_rule request :get_image @@ -95,11 +105,13 @@ class Brightbox < Fog::Service request :get_server_group request :get_server_type request :get_user + request :get_user_collaboration request :get_zone request :list_accounts request :list_api_clients request :list_applications request :list_cloud_ips + request :list_collaborations request :list_firewall_policies request :list_images request :list_load_balancers @@ -107,16 +119,21 @@ class Brightbox < Fog::Service request :list_server_types request :list_servers request :list_users + request :list_user_collaborations request :list_zones request :map_cloud_ip request :move_servers_server_group + request :reject_user_collaboration request :remove_listeners_load_balancer request :remove_nodes_load_balancer request :remove_servers_server_group + request :resend_collaboration request :reset_ftp_password_account request :reset_ftp_password_scoped_account request :reset_secret_api_client request :reset_secret_application + request :resend_collaboration + request :reject_user_collaboration request :shutdown_server request :snapshot_server request :start_server diff --git a/lib/fog/brightbox/models/compute/collaboration.rb b/lib/fog/brightbox/models/compute/collaboration.rb new file mode 100644 index 0000000000..f2660cb8f2 --- /dev/null +++ b/lib/fog/brightbox/models/compute/collaboration.rb @@ -0,0 +1,43 @@ +require 'fog/core/model' + +module Fog + module Compute + class Brightbox + class Collaboration < Fog::Model + identity :id + attribute :status + attribute :email + attribute :role + attribute :role_label + attribute :account + attribute :user + attribute :inviter + + def account_id + account['id'] || account[:id] + end + + def save + raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if identity + + options = { + :role => role, + :email => email + }.delete_if { |k, v| v.nil? || v == "" } + + data = connection.create_collaboration(options) + merge_attributes(data) + true + end + + def destroy + requires :identity + connection.destroy_collaboration(identity) + true + end + + end + end + end +end + diff --git a/lib/fog/brightbox/models/compute/collaborations.rb b/lib/fog/brightbox/models/compute/collaborations.rb new file mode 100644 index 0000000000..b8e4494656 --- /dev/null +++ b/lib/fog/brightbox/models/compute/collaborations.rb @@ -0,0 +1,23 @@ +require "fog/core/collection" +require "fog/brightbox/models/compute/collaboration" + +module Fog + module Compute + class Brightbox + class Collaborations < Fog::Collection + model Fog::Compute::Brightbox::Collaboration + + def all + data = connection.list_collaborations + load(data) + end + + def destroy + requires :identity + connection.destroy_collaboration(identity) + true + end + end + end + end +end diff --git a/lib/fog/brightbox/models/compute/user_collaboration.rb b/lib/fog/brightbox/models/compute/user_collaboration.rb new file mode 100644 index 0000000000..88a7bbc1bb --- /dev/null +++ b/lib/fog/brightbox/models/compute/user_collaboration.rb @@ -0,0 +1,29 @@ +require 'fog/core/model' + +module Fog + module Compute + class Brightbox + class UserCollaboration < Fog::Model + identity :id + attribute :status + attribute :email + attribute :role + attribute :role_label + attribute :account + attribute :user + attribute :inviter + + def account_id + account['id'] || account[:id] + end + + def destroy + requires :identity + connection.destroy_user_collaboration(identity) + true + end + + end + end + end +end diff --git a/lib/fog/brightbox/models/compute/user_collaborations.rb b/lib/fog/brightbox/models/compute/user_collaborations.rb new file mode 100644 index 0000000000..43a963d925 --- /dev/null +++ b/lib/fog/brightbox/models/compute/user_collaborations.rb @@ -0,0 +1,23 @@ +require "fog/core/collection" +require "fog/brightbox/models/compute/user_collaboration" + +module Fog + module Compute + class Brightbox + class UserCollaborations < Fog::Collection + model Fog::Compute::Brightbox::UserCollaboration + + def all + data = connection.list_user_collaborations + load(data) + end + + def destroy + requires :identity + connection.destroy_user_collaboration(identity) + true + end + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/accept_user_collaboration.rb b/lib/fog/brightbox/requests/compute/accept_user_collaboration.rb new file mode 100644 index 0000000000..d9f8a353e9 --- /dev/null +++ b/lib/fog/brightbox/requests/compute/accept_user_collaboration.rb @@ -0,0 +1,21 @@ +module Fog + module Compute + class Brightbox + class Real + # Accepts the collaboration and gaining permitted access + # + # @param [String] identifier Unique reference to identify the resource + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#user_collaboration_accept_user_collaboration + # + def accept_user_collaboration(identifier) + return nil if identifier.nil? || identifier == "" + wrapped_request("post", "/1.0/user/collaborations/#{identifier}/accept", [200]) + end + + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/create_collaboration.rb b/lib/fog/brightbox/requests/compute/create_collaboration.rb new file mode 100644 index 0000000000..13088c36f1 --- /dev/null +++ b/lib/fog/brightbox/requests/compute/create_collaboration.rb @@ -0,0 +1,23 @@ +module Fog + module Compute + class Brightbox + class Real + # Creates a new collaboration for a user for the account + # + # @param [Hash] options + # @option options [String] :email Email address of user to invite + # @option options [String] :role Role to grant to the user. Currently only `admin` + # + # @return [Hash] if successful Hash version of JSON object + # @return [NilClass] if no options were passed + # + # @see https://api.gb1.brightbox.com/1.0/#collaboration_create_collaboration + # + def create_collaboration(options) + wrapped_request("post", "/1.0/collaborations", [201], options) + end + + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/delete_collaboration.rb b/lib/fog/brightbox/requests/compute/delete_collaboration.rb new file mode 100644 index 0000000000..39eef88f1a --- /dev/null +++ b/lib/fog/brightbox/requests/compute/delete_collaboration.rb @@ -0,0 +1,28 @@ +module Fog + module Compute + class Brightbox + class Real + # Cancels or completes the collaboration + # + # @param [String] identifier Unique reference to identify the resource + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#collaboration_delete_collaboration + # + def delete_collaboration(identifier) + return nil if identifier.nil? || identifier == "" + wrapped_request("delete", "/1.0/collaborations/#{identifier}", [200]) + end + + # Old format of the delete request. + # + # @deprecated Use +#delete_collaboration+ instead + # + def destroy_collaboration(identifier) + delete_collaboration(identifier) + end + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/delete_user_collaboration.rb b/lib/fog/brightbox/requests/compute/delete_user_collaboration.rb new file mode 100644 index 0000000000..2aad328ca7 --- /dev/null +++ b/lib/fog/brightbox/requests/compute/delete_user_collaboration.rb @@ -0,0 +1,28 @@ +module Fog + module Compute + class Brightbox + class Real + # Ends an existing 'accepted' collaboration + # + # @param [String] identifier Unique reference to identify the resource + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#user_collaboration_delete_user_collaboration + # + def delete_user_collaboration(identifier) + return nil if identifier.nil? || identifier == "" + wrapped_request("delete", "/1.0/user/collaborations/#{identifier}", [200]) + end + + # Old format of the delete request. + # + # @deprecated Use +#delete_user_collaboration+ instead + # + def destroy_user_collaboration(identifier) + delete_user_collaboration(identifier) + end + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/destroy_user_collaboration.rb b/lib/fog/brightbox/requests/compute/destroy_user_collaboration.rb new file mode 100644 index 0000000000..139b146092 --- /dev/null +++ b/lib/fog/brightbox/requests/compute/destroy_user_collaboration.rb @@ -0,0 +1,21 @@ +module Fog + module Compute + class Brightbox + class Real + # Ends an existing 'accepted' collaboration + # + # @param [String] identifier Unique reference to identify the resource + # + # @return [Hash] The JSON response parsed to a Hash + # + # @see https://api.gb1.brightbox.com/1.0/#user_collaboration_destroy_user_collaboration + # + def destroy_user_collaboration(identifier) + return nil if identifier.nil? || identifier == "" + wrapped_request("delete", "/1.0/user/collaborations/#{identifier}", [200]) + end + + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/get_collaboration.rb b/lib/fog/brightbox/requests/compute/get_collaboration.rb new file mode 100644 index 0000000000..27140ea302 --- /dev/null +++ b/lib/fog/brightbox/requests/compute/get_collaboration.rb @@ -0,0 +1,21 @@ +module Fog + module Compute + class Brightbox + class Real + # Shows details of one collaboration + # + # @param [String] identifier Unique reference to identify the resource + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#collaboration_get_collaboration + # + def get_collaboration(identifier) + return nil if identifier.nil? || identifier == "" + wrapped_request("get", "/1.0/collaborations/#{identifier}", [200]) + end + + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/get_user_collaboration.rb b/lib/fog/brightbox/requests/compute/get_user_collaboration.rb new file mode 100644 index 0000000000..4ff7c538bd --- /dev/null +++ b/lib/fog/brightbox/requests/compute/get_user_collaboration.rb @@ -0,0 +1,21 @@ +module Fog + module Compute + class Brightbox + class Real + # Shows details of one collaboration + # + # @param [String] identifier Unique reference to identify the resource + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#user_collaboration_get_user_collaboration + # + def get_user_collaboration(identifier) + return nil if identifier.nil? || identifier == "" + wrapped_request("get", "/1.0/user/collaborations/#{identifier}", [200]) + end + + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/list_collaborations.rb b/lib/fog/brightbox/requests/compute/list_collaborations.rb new file mode 100644 index 0000000000..c57615672c --- /dev/null +++ b/lib/fog/brightbox/requests/compute/list_collaborations.rb @@ -0,0 +1,19 @@ +module Fog + module Compute + class Brightbox + class Real + # Lists all the account collaborations + # + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#collaboration_list_collaborations + # + def list_collaborations + wrapped_request("get", "/1.0/collaborations", [200]) + end + + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/list_user_collaborations.rb b/lib/fog/brightbox/requests/compute/list_user_collaborations.rb new file mode 100644 index 0000000000..0033fe2406 --- /dev/null +++ b/lib/fog/brightbox/requests/compute/list_user_collaborations.rb @@ -0,0 +1,19 @@ +module Fog + module Compute + class Brightbox + class Real + # Lists all collaborations the user is involved with + # + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#user_collaboration_list_user_collaborations + # + def list_user_collaborations + wrapped_request("get", "/1.0/user/collaborations", [200]) + end + + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/reject_user_collaboration.rb b/lib/fog/brightbox/requests/compute/reject_user_collaboration.rb new file mode 100644 index 0000000000..ff12cb48c2 --- /dev/null +++ b/lib/fog/brightbox/requests/compute/reject_user_collaboration.rb @@ -0,0 +1,21 @@ +module Fog + module Compute + class Brightbox + class Real + # Rejects the collaboration and removes the offer + # + # @param [String] identifier Unique reference to identify the resource + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#user_collaboration_reject_user_collaboration + # + def reject_user_collaboration(identifier) + return nil if identifier.nil? || identifier == "" + wrapped_request("post", "/1.0/user/collaborations/#{identifier}/reject", [200]) + end + + end + end + end +end diff --git a/lib/fog/brightbox/requests/compute/resend_collaboration.rb b/lib/fog/brightbox/requests/compute/resend_collaboration.rb new file mode 100644 index 0000000000..f003c58b8e --- /dev/null +++ b/lib/fog/brightbox/requests/compute/resend_collaboration.rb @@ -0,0 +1,21 @@ +module Fog + module Compute + class Brightbox + class Real + # Resends the invitation email to the collaborator + # + # @param [String] identifier Unique reference to identify the resource + # + # @return [Hash] if successful Hash version of JSON object + # + # @see https://api.gb1.brightbox.com/1.0/#collaboration_resend_collaboration + # + def resend_collaboration(identifier) + return nil if identifier.nil? || identifier == "" + wrapped_request("post", "/1.0/collaborations/#{identifier}/resend", [200]) + end + + end + end + end +end diff --git a/tests/brightbox/requests/compute/collaboration_tests.rb b/tests/brightbox/requests/compute/collaboration_tests.rb new file mode 100644 index 0000000000..b389615748 --- /dev/null +++ b/tests/brightbox/requests/compute/collaboration_tests.rb @@ -0,0 +1,41 @@ +Shindo.tests('Fog::Compute[:brightbox] | collaboration requests', ['brightbox']) do + + tests('success') do + + tests("#create_collaboration") do + pending if Fog.mocking? + collaboration = Fog::Compute[:brightbox].create_collaboration(:email => "paul@example.com", :role => "admin") + @collaboration_id = collaboration['id'] + formats(Brightbox::Compute::Formats::Full::COLLABORATION, false) { collaboration } + end + + + tests("#list_collaborations") do + pending if Fog.mocking? + result = Fog::Compute[:brightbox].list_collaborations + + formats(Brightbox::Compute::Formats::Collection::COLLABORATIONS, false) { result } + end + + tests("#get_collaboration") do + pending if Fog.mocking? + result = Fog::Compute[:brightbox].get_collaboration(@collaboration_id) + formats(Brightbox::Compute::Formats::Full::COLLABORATION, false) { result } + end + + + tests("#destroy_collaboration") do + pending if Fog.mocking? + result = Fog::Compute[:brightbox].destroy_collaboration(@collaboration_id) + formats(Brightbox::Compute::Formats::Full::COLLABORATION, false) { result } + end + end + + tests("failure") do + tests("get_collaboration('col-abcde')").raises(Excon::Errors::NotFound) do + pending if Fog.mocking? + Fog::Compute[:brightbox].get_collaboration("col-abcde") + end + end + +end diff --git a/tests/brightbox/requests/compute/helper.rb b/tests/brightbox/requests/compute/helper.rb index c8fa7e907b..04ab579e2c 100644 --- a/tests/brightbox/requests/compute/helper.rb +++ b/tests/brightbox/requests/compute/helper.rb @@ -8,6 +8,7 @@ module Interface; end module LoadBalancer; end module Server; end module ServerGroup; end + module User; end module Zone; end end end @@ -34,6 +35,9 @@ module Zone; end Hash.send :include, Fog::Brightbox::Nullable::ServerGroup NilClass.send :include, Fog::Brightbox::Nullable::ServerGroup +Hash.send :include, Fog::Brightbox::Nullable::User +NilClass.send :include, Fog::Brightbox::Nullable::User + Hash.send :include, Fog::Brightbox::Nullable::Zone NilClass.send :include, Fog::Brightbox::Nullable::Zone @@ -75,8 +79,8 @@ def self.select_testing_image_from_api raise "No available images!" if images.empty? images.select { |img| img["official"] && img["virtual_size"] != 0 }.sort_by { |img| img["disk_size"] }.first || images.first end - end + module Formats module Struct CIP_PORT_TRANSLATOR = { @@ -231,6 +235,20 @@ module Nested "email_address" => String } + + COLLABORATION = { + "id" => String, + "resource_type" => String, + "url" => String, + "status" => String, + "email" => Fog::Nullable::String, + "role" => String, + "role_label" => String, + "user" => Fog::Brightbox::Nullable::User, + "account" => Brightbox::Compute::Formats::Nested::ACCOUNT, + "inviter" => Brightbox::Compute::Formats::Nested::USER + } + ZONE = { "id" => String, "resource_type" => String, @@ -413,6 +431,19 @@ module Collected "default_account" => NilClass } + COLLABORATION = { + "id" => String, + "resource_type" => String, + "url" => String, + "status" => String, + "role" => String, + "role_label" => String, + "email" => Fog::Nullable::String, + "user" => Fog::Brightbox::Nullable::User, + "account" => Brightbox::Compute::Formats::Nested::ACCOUNT, + "inviter" => Brightbox::Compute::Formats::Nested::USER + } + ZONE = { "id" => String, "resource_type" => String, @@ -656,13 +687,25 @@ module Full "messaging_pref" => Fog::Boolean } + COLLABORATION = { + "id" => String, + "resource_type" => String, + "url" => String, + "status" => String, + "role" => String, + "role_label" => String, + "email" => Fog::Nullable::String, + "user" => Fog::Brightbox::Nullable::User, + "account" => Brightbox::Compute::Formats::Nested::ACCOUNT, + "inviter" => Brightbox::Compute::Formats::Nested::USER + } + ZONE = { "id" => String, "resource_type" => String, "url" => String, "handle" => String } - end module Collection @@ -678,6 +721,7 @@ module Collection SERVER_TYPES = [Brightbox::Compute::Formats::Collected::SERVER_TYPE] USERS = [Brightbox::Compute::Formats::Collected::USER] ZONES = [Brightbox::Compute::Formats::Collected::ZONE] + COLLABORATIONS = [Brightbox::Compute::Formats::Collected::COLLABORATION] end end diff --git a/tests/brightbox/requests/compute/user_collaboration_tests.rb b/tests/brightbox/requests/compute/user_collaboration_tests.rb new file mode 100644 index 0000000000..79ee9f14cd --- /dev/null +++ b/tests/brightbox/requests/compute/user_collaboration_tests.rb @@ -0,0 +1,67 @@ +Shindo.tests('Fog::Compute[:brightbox] | user collaboration requests', ['brightbox']) do + + @service = Fog::Compute[:brightbox] + + tests("when accessing with user application") do + pending unless @service.authenticating_as_user? + tests("success") do + tests("#list_user_collaborations") do + pending if Fog.mocking? + result = @service.list_user_collaborations + + formats(Brightbox::Compute::Formats::Collection::COLLABORATIONS, false) { result } + end + end + + tests("failure") do + tests("get_user_collaboration('col-abcde')").raises(Excon::Errors::NotFound) do + pending if Fog.mocking? + + @service.get_user_collaboration('col-abcde') + end + + tests("accept_user_collaboration('col-abcde')").raises(Excon::Errors::NotFound) do + pending if Fog.mocking? + + @service.accept_user_collaboration('col-abcde') + end + + tests("reject_user_collaboration('col-abcde')").raises(Excon::Errors::NotFound) do + pending if Fog.mocking? + + @service.reject_user_collaboration('col-abcde') + end + end + end + + tests("when accessing with API client") do + pending if @service.authenticating_as_user? + tests("forbidden") do + + tests("#list_user_collaborations").raises(Excon::Errors::Forbidden) do + pending if Fog.mocking? + result = @service.list_user_collaborations + + formats(Brightbox::Compute::Formats::Collection::COLLABORATIONS, false) { result } + end + + tests("get_user_collaboration('col-abcde')").raises(Excon::Errors::Forbidden) do + pending if Fog.mocking? + + @service.get_user_collaboration('col-abcde') + end + + tests("accept_user_collaboration('col-abcde')").raises(Excon::Errors::Forbidden) do + pending if Fog.mocking? + + @service.accept_user_collaboration('col-abcde') + end + + tests("reject_user_collaboration('col-abcde')").raises(Excon::Errors::Forbidden) do + pending if Fog.mocking? + + @service.reject_user_collaboration('col-abcde') + end + end + end +end From e7030a63cc1b3ea8e97b11c9213706b8e58f817b Mon Sep 17 00:00:00 2001 From: Paul Thornthwaite Date: Mon, 24 Jun 2013 13:48:06 +0100 Subject: [PATCH 2/2] [Brightbox] Extract Compute::Shared to own file Seeing a lot of churn in lib/fog/brightbox/compute.rb because of adding new requests or models as well as any implementation changes. This moves the common behaviour between Compute's Real and Mock classes into their own file to cut down on the noise when refactoring or merging. --- lib/fog/brightbox/compute.rb | 215 +------------------------- lib/fog/brightbox/compute/shared.rb | 232 ++++++++++++++++++++++++++++ 2 files changed, 235 insertions(+), 212 deletions(-) create mode 100644 lib/fog/brightbox/compute/shared.rb diff --git a/lib/fog/brightbox/compute.rb b/lib/fog/brightbox/compute.rb index ecb25a1719..8444f9701e 100644 --- a/lib/fog/brightbox/compute.rb +++ b/lib/fog/brightbox/compute.rb @@ -1,14 +1,12 @@ require 'fog/brightbox' require 'fog/compute' -require 'fog/brightbox/oauth2' +require 'fog/brightbox/compute/shared' require 'fog/brightbox/compute/image_selector' module Fog module Compute class Brightbox < Fog::Service - API_URL = "https://api.gb1.brightbox.com/" - # Client credentials requires :brightbox_client_id, :brightbox_secret @@ -152,220 +150,13 @@ class Brightbox < Fog::Service request :update_server_group request :update_user - module Shared - include Fog::Brightbox::OAuth2 - - # Creates a new instance of the Brightbox Compute service - # - # @note If you create service using just a refresh token when it - # expires the service will no longer be able to authenticate. - # - # @param [Hash] options - # @option options [String] :brightbox_api_url Override the default (or configured) API endpoint - # @option options [String] :brightbox_auth_url Override the default (or configured) API authentication endpoint - # @option options [String] :brightbox_client_id Client identifier to authenticate with (overrides configured) - # @option options [String] :brightbox_secret Client secret to authenticate with (overrides configured) - # @option options [String] :brightbox_username Email or user identifier for user based authentication - # @option options [String] :brightbox_password Password for user based authentication - # @option options [String] :brightbox_account Account identifier to scope this connection to - # @option options [String] :connection_options Settings to pass to underlying {Fog::Connection} - # @option options [Boolean] :persistent Sets a persistent HTTP {Fog::Connection} - # @option options [String] :brightbox_access_token Sets the OAuth access token to use rather than requesting a new token - # @option options [String] :brightbox_refresh_token Sets the refresh token to use when requesting a newer access token - # @option options [String] :brightbox_token_management Overide the existing behaviour to request access tokens if expired (default is `true`) - # - def initialize(options) - # Currently authentication and api endpoints are the same but may change - @auth_url = options[:brightbox_auth_url] || Fog.credentials[:brightbox_auth_url] || API_URL - @auth_connection = Fog::Connection.new(@auth_url) - - @api_url = options[:brightbox_api_url] || Fog.credentials[:brightbox_api_url] || API_URL - @connection_options = options[:connection_options] || {} - @persistent = options[:persistent] || false - @connection = Fog::Connection.new(@api_url, @persistent, @connection_options) - - # Authentication options - client_id = options[:brightbox_client_id] || Fog.credentials[:brightbox_client_id] - client_secret = options[:brightbox_secret] || Fog.credentials[:brightbox_secret] - - username = options[:brightbox_username] || Fog.credentials[:brightbox_username] - password = options[:brightbox_password] || Fog.credentials[:brightbox_password] - @configured_account = options[:brightbox_account] || Fog.credentials[:brightbox_account] - # Request account can be changed at anytime and changes behaviour of future requests - @scoped_account = @configured_account - - credential_options = {:username => username, :password => password} - @credentials = CredentialSet.new(client_id, client_secret, credential_options) - - # If existing tokens have been cached, allow continued use of them in the service - @credentials.update_tokens(options[:brightbox_access_token], options[:brightbox_refresh_token]) - - @token_management = options.fetch(:brightbox_token_management, true) - end - - # Sets the scoped account for future requests - # @param [String] scoped_account Identifier of the account to scope request to - def scoped_account=(scoped_account) - @scoped_account = scoped_account - end - - # This returns the account identifier that the request should be scoped by - # based on the options passed to the request and current configuration - # - # @param [String] options_account Any identifier passed into the request - # - # @return [String, nil] The account identifier to scope the request to or nil - def scoped_account(options_account = nil) - [options_account, @scoped_account].compact.first - end - - # Resets the scoped account back to intially configured one - def scoped_account_reset - @scoped_account = @configured_account - end - - # Returns the scoped account being used for requests - # - # * For API clients this is the owning account - # * For User applications this is the account specified by either +account_id+ - # option on the service or the +brightbox_account+ setting in your configuration - # - # @return [Fog::Compute::Brightbox::Account] - # - def account - account_data = get_scoped_account.merge(:service => self) - Fog::Compute::Brightbox::Account.new(account_data) - end - - # Returns true if authentication is being performed as a user - # @return [Boolean] - def authenticating_as_user? - @credentials.user_details? - end - - # Returns true if an access token is set - # @return [Boolean] - def access_token_available? - !! @credentials.access_token - end - - # Returns the current access token or nil - # @return [String,nil] - def access_token - @credentials.access_token - end - - # Returns the current refresh token or nil - # @return [String,nil] - def refresh_token - @credentials.refresh_token - end - - # Returns the current token expiry time in seconds or nil - # @return [Number,nil] - def expires_in - @credentials.expires_in - end - - # Requests a new access token - # - # @return [String] New access token - def get_access_token - begin - get_access_token! - rescue Excon::Errors::Unauthorized, Excon::Errors::BadRequest - @credentials.update_tokens(nil, nil) - end - @credentials.access_token - end - - # Requests a new access token and raises if there is a problem - # - # @return [String] New access token - # @raise [Excon::Errors::BadRequest] The credentials are expired or incorrect - # - def get_access_token! - response = request_access_token(@auth_connection, @credentials) - update_credentials_from_response(@credentials, response) - @credentials.access_token - end - - # Returns an identifier for the default image for use - # - # Currently tries to find the latest version of Ubuntu (i686) from - # Brightbox. - # - # Highly recommended that you actually select the image you want to run - # on your servers yourself! - # - # @return [String] if image is found, returns the identifier - # @return [NilClass] if no image is found or an error occurs - # - def default_image - return @default_image_id unless @default_image_id.nil? - @default_image_id = Fog.credentials[:brightbox_default_image] || select_default_image - end - - private - - # This makes a request of the API based on the configured setting for - # token management. - # - # @param [Hash] options Excon compatible options - # @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb - # - # @return [Hash] Data of response body - # - def make_request(options) - if @token_management - managed_token_request(options) - else - authenticated_request(options) - end - end - - # This request checks for access tokens and will ask for a new one if - # it receives Unauthorized from the API before repeating the request - # - # @param [Hash] options Excon compatible options - # - # @return [Excon::Response] - def managed_token_request(options) - begin - get_access_token unless access_token_available? - response = authenticated_request(options) - rescue Excon::Errors::Unauthorized - get_access_token - response = authenticated_request(options) - end - end - - # This request makes an authenticated request of the API using currently - # setup credentials. - # - # @param [Hash] options Excon compatible options - # - # @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb - # - # @return [Excon::Response] - def authenticated_request(options) - headers = options[:headers] || {} - headers.merge!("Authorization" => "OAuth #{@credentials.access_token}", "Content-Type" => "application/json") - options[:headers] = headers - # TODO This is just a wrapper around a call to Excon::Connection#request - # so can be extracted from Compute by passing in the connection, - # credentials and options - @connection.request(options) - end - end - # The Mock Service allows you to run a fake instance of the Service # which makes no real connections. # # @todo Implement # class Mock - include Shared + include Fog::Brightbox::Compute::Shared def request(method, path, expected_responses, parameters = {}) _request @@ -390,7 +181,7 @@ def select_default_image # service. # class Real - include Shared + include Fog::Brightbox::Compute::Shared # Makes an API request to the given path using passed options or those # set with the service setup diff --git a/lib/fog/brightbox/compute/shared.rb b/lib/fog/brightbox/compute/shared.rb new file mode 100644 index 0000000000..b889b4f3e2 --- /dev/null +++ b/lib/fog/brightbox/compute/shared.rb @@ -0,0 +1,232 @@ +require "fog/brightbox/oauth2" + +module Fog + module Brightbox + module Compute + + # The Shared module consists of code that was duplicated between the Real + # and Mock implementations. + # + module Shared + include Fog::Brightbox::OAuth2 + + API_URL = "https://api.gb1.brightbox.com/" + + # Creates a new instance of the Brightbox Compute service + # + # @note If you create service using just a refresh token when it + # expires the service will no longer be able to authenticate. + # + # @param [Hash] options + # @option options [String] :brightbox_api_url + # Override the default (or configured) API endpoint + # @option options [String] :brightbox_auth_url + # Override the default (or configured) API authentication endpoint + # @option options [String] :brightbox_client_id + # Client identifier to authenticate with (overrides configured) + # @option options [String] :brightbox_secret + # Client secret to authenticate with (overrides configured) + # @option options [String] :brightbox_username + # Email or user identifier for user based authentication + # @option options [String] :brightbox_password + # Password for user based authentication + # @option options [String] :brightbox_account + # Account identifier to scope this connection to + # @option options [String] :connection_options + # Settings to pass to underlying {Fog::Connection} + # @option options [Boolean] :persistent + # Sets a persistent HTTP {Fog::Connection} + # @option options [String] :brightbox_access_token + # Sets the OAuth access token to use rather than requesting a new token + # @option options [String] :brightbox_refresh_token + # Sets the refresh token to use when requesting a newer access token + # @option options [String] (true) :brightbox_token_management + # Overide the existing behaviour to request access tokens if expired + # + def initialize(options) + # Currently authentication and api endpoints are the same but may change + @auth_url = options[:brightbox_auth_url] || Fog.credentials[:brightbox_auth_url] || API_URL + @auth_connection = Fog::Connection.new(@auth_url) + + @api_url = options[:brightbox_api_url] || Fog.credentials[:brightbox_api_url] || API_URL + @connection_options = options[:connection_options] || {} + @persistent = options[:persistent] || false + @connection = Fog::Connection.new(@api_url, @persistent, @connection_options) + + # Authentication options + client_id = options[:brightbox_client_id] || Fog.credentials[:brightbox_client_id] + client_secret = options[:brightbox_secret] || Fog.credentials[:brightbox_secret] + + username = options[:brightbox_username] || Fog.credentials[:brightbox_username] + password = options[:brightbox_password] || Fog.credentials[:brightbox_password] + @configured_account = options[:brightbox_account] || Fog.credentials[:brightbox_account] + # Request account can be changed at anytime and changes behaviour of future requests + @scoped_account = @configured_account + + credential_options = {:username => username, :password => password} + @credentials = CredentialSet.new(client_id, client_secret, credential_options) + + # If existing tokens have been cached, allow continued use of them in the service + @credentials.update_tokens(options[:brightbox_access_token], options[:brightbox_refresh_token]) + + @token_management = options.fetch(:brightbox_token_management, true) + end + + # Sets the scoped account for future requests + # @param [String] scoped_account Identifier of the account to scope request to + def scoped_account=(scoped_account) + @scoped_account = scoped_account + end + + # This returns the account identifier that the request should be scoped by + # based on the options passed to the request and current configuration + # + # @param [String] options_account Any identifier passed into the request + # + # @return [String, nil] The account identifier to scope the request to or nil + def scoped_account(options_account = nil) + [options_account, @scoped_account].compact.first + end + + # Resets the scoped account back to intially configured one + def scoped_account_reset + @scoped_account = @configured_account + end + + # Returns the scoped account being used for requests + # + # * For API clients this is the owning account + # * For User applications this is the account specified by either +account_id+ + # option on the service or the +brightbox_account+ setting in your configuration + # + # @return [Fog::Compute::Brightbox::Account] + # + def account + account_data = get_scoped_account.merge(:service => self) + Fog::Compute::Brightbox::Account.new(account_data) + end + + # Returns true if authentication is being performed as a user + # @return [Boolean] + def authenticating_as_user? + @credentials.user_details? + end + + # Returns true if an access token is set + # @return [Boolean] + def access_token_available? + !! @credentials.access_token + end + + # Returns the current access token or nil + # @return [String,nil] + def access_token + @credentials.access_token + end + + # Returns the current refresh token or nil + # @return [String,nil] + def refresh_token + @credentials.refresh_token + end + + # Returns the current token expiry time in seconds or nil + # @return [Number,nil] + def expires_in + @credentials.expires_in + end + + # Requests a new access token + # + # @return [String] New access token + def get_access_token + begin + get_access_token! + rescue Excon::Errors::Unauthorized, Excon::Errors::BadRequest + @credentials.update_tokens(nil, nil) + end + @credentials.access_token + end + + # Requests a new access token and raises if there is a problem + # + # @return [String] New access token + # @raise [Excon::Errors::BadRequest] The credentials are expired or incorrect + # + def get_access_token! + response = request_access_token(@auth_connection, @credentials) + update_credentials_from_response(@credentials, response) + @credentials.access_token + end + + # Returns an identifier for the default image for use + # + # Currently tries to find the latest version of Ubuntu (i686) from + # Brightbox. + # + # Highly recommended that you actually select the image you want to run + # on your servers yourself! + # + # @return [String] if image is found, returns the identifier + # @return [NilClass] if no image is found or an error occurs + # + def default_image + return @default_image_id unless @default_image_id.nil? + @default_image_id = Fog.credentials[:brightbox_default_image] || select_default_image + end + + private + + # This makes a request of the API based on the configured setting for + # token management. + # + # @param [Hash] options Excon compatible options + # @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb + # + # @return [Hash] Data of response body + # + def make_request(options) + if @token_management + managed_token_request(options) + else + authenticated_request(options) + end + end + + # This request checks for access tokens and will ask for a new one if + # it receives Unauthorized from the API before repeating the request + # + # @param [Hash] options Excon compatible options + # + # @return [Excon::Response] + def managed_token_request(options) + begin + get_access_token unless access_token_available? + response = authenticated_request(options) + rescue Excon::Errors::Unauthorized + get_access_token + response = authenticated_request(options) + end + end + + # This request makes an authenticated request of the API using currently + # setup credentials. + # + # @param [Hash] options Excon compatible options + # + # @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb + # + # @return [Excon::Response] + def authenticated_request(options) + headers = options[:headers] || {} + headers.merge!("Authorization" => "OAuth #{@credentials.access_token}", "Content-Type" => "application/json") + options[:headers] = headers + # TODO This is just a wrapper around a call to Excon::Connection#request + # so can be extracted from Compute by passing in the connection, + # credentials and options + @connection.request(options) + end + end + end + end +end