mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
c3e4d7eddf
To standardised with the Delete in CRUD we decided to update the API documentation but had used the old names in the Fog requests. This replaces them with deprecation to the old methods so they continue to work as before.
475 lines
18 KiB
Ruby
475 lines
18 KiB
Ruby
require 'fog/brightbox'
|
|
require 'fog/compute'
|
|
require 'fog/brightbox/oauth2'
|
|
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
|
|
|
|
# API endpoint settings
|
|
recognizes :brightbox_auth_url, :brightbox_api_url
|
|
|
|
# User credentials (still requires client details)
|
|
recognizes :brightbox_username, :brightbox_password, :brightbox_account
|
|
|
|
# Cached tokens
|
|
recognizes :brightbox_access_token, :brightbox_refresh_token
|
|
|
|
# Automatic token management
|
|
recognizes :brightbox_token_management
|
|
|
|
# Excon connection settings
|
|
recognizes :persistent
|
|
|
|
model_path 'fog/brightbox/models/compute'
|
|
collection :accounts
|
|
model :account
|
|
collection :applications
|
|
model :application
|
|
collection :api_clients
|
|
model :api_client
|
|
collection :servers
|
|
model :server
|
|
collection :server_groups
|
|
model :server_group
|
|
collection :firewall_policies
|
|
model :firewall_policy
|
|
collection :firewall_rules
|
|
model :firewall_rule
|
|
collection :flavors
|
|
model :flavor
|
|
collection :images
|
|
model :image
|
|
collection :load_balancers
|
|
model :load_balancer
|
|
collection :zones
|
|
model :zone
|
|
collection :cloud_ips
|
|
model :cloud_ip
|
|
collection :users
|
|
model :user
|
|
|
|
request_path 'fog/brightbox/requests/compute'
|
|
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 :remove_firewall_policy
|
|
request :create_api_client
|
|
request :create_application
|
|
request :create_cloud_ip
|
|
request :create_firewall_policy
|
|
request :create_firewall_rule
|
|
request :create_image
|
|
request :create_load_balancer
|
|
request :create_server
|
|
request :create_server_group
|
|
request :delete_api_client
|
|
request :delete_application
|
|
request :delete_cloud_ip
|
|
request :delete_firewall_policy
|
|
request :delete_firewall_rule
|
|
request :delete_image
|
|
request :delete_load_balancer
|
|
request :delete_server
|
|
request :delete_server_group
|
|
request :get_account
|
|
request :get_api_client
|
|
request :get_application
|
|
request :get_authenticated_user
|
|
request :get_cloud_ip
|
|
request :get_firewall_policy
|
|
request :get_firewall_rule
|
|
request :get_image
|
|
request :get_interface
|
|
request :get_load_balancer
|
|
request :get_scoped_account
|
|
request :get_server
|
|
request :get_server_group
|
|
request :get_server_type
|
|
request :get_user
|
|
request :get_zone
|
|
request :list_accounts
|
|
request :list_api_clients
|
|
request :list_applications
|
|
request :list_cloud_ips
|
|
request :list_firewall_policies
|
|
request :list_images
|
|
request :list_load_balancers
|
|
request :list_server_groups
|
|
request :list_server_types
|
|
request :list_servers
|
|
request :list_users
|
|
request :list_zones
|
|
request :map_cloud_ip
|
|
request :move_servers_server_group
|
|
request :remove_listeners_load_balancer
|
|
request :remove_nodes_load_balancer
|
|
request :remove_servers_server_group
|
|
request :reset_ftp_password_account
|
|
request :reset_ftp_password_scoped_account
|
|
request :reset_secret_api_client
|
|
request :reset_secret_application
|
|
request :shutdown_server
|
|
request :snapshot_server
|
|
request :start_server
|
|
request :stop_server
|
|
request :unmap_cloud_ip
|
|
request :update_account
|
|
request :update_api_client
|
|
request :update_application
|
|
request :update_cloud_ip
|
|
request :update_firewall_policy
|
|
request :update_firewall_rule
|
|
request :update_image
|
|
request :update_load_balancer
|
|
request :update_scoped_account
|
|
request :update_server
|
|
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
|
|
|
|
# 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
|
|
|
|
def request(method, path, expected_responses, parameters = {})
|
|
_request
|
|
end
|
|
|
|
def request_access_token(connection, credentials)
|
|
_request
|
|
end
|
|
|
|
private
|
|
|
|
def _request
|
|
raise Fog::Errors::MockNotImplemented
|
|
end
|
|
|
|
def select_default_image
|
|
"img-mockd"
|
|
end
|
|
end
|
|
|
|
# The Real Service actually makes real connections to the Brightbox
|
|
# service.
|
|
#
|
|
class Real
|
|
include Shared
|
|
|
|
# Makes an API request to the given path using passed options or those
|
|
# set with the service setup
|
|
#
|
|
# @todo Standard Fog behaviour is to return the Excon::Response but
|
|
# this was unintentionally changed to be the Hash version of the
|
|
# data in the body. This loses access to some details and should
|
|
# be corrected in a backwards compatible manner
|
|
#
|
|
# @overload request(params)
|
|
# @param [Hash] params Excon compatible options
|
|
# @option params [String] :body text to be sent over a socket
|
|
# @option params [Hash<Symbol, String>] :headers The default headers to supply in a request
|
|
# @option params [String] :host The destination host's reachable DNS name or IP, in the form of a String
|
|
# @option params [String] :path appears after 'scheme://host:port/'
|
|
# @option params [Fixnum] :port The port on which to connect, to the destination host
|
|
# @option params [Hash] :query appended to the 'scheme://host:port/path/' in the form of '?key=value'
|
|
# @option params [String] :scheme The protocol; 'https' causes OpenSSL to be used
|
|
# @return [Excon::Response]
|
|
# @see https://github.com/geemus/excon/blob/master/lib/excon/connection.rb
|
|
#
|
|
# @overload request(method, path, expected_responses, params = {})
|
|
# @param [String] method HTTP method to use for the request
|
|
# @param [String] path The absolute path for the request
|
|
# @param [Array<Fixnum>] expected_responses HTTP response codes that have been successful
|
|
# @param [Hash] params Keys and values for JSON
|
|
# @option params [String] :account_id The scoping account if required
|
|
# @deprecated #request with multiple arguments is deprecated
|
|
# since it is inconsistent with original fog version.
|
|
# @return [Hash]
|
|
def request(*args)
|
|
if args.size == 1
|
|
authenticated_request(*args)
|
|
else
|
|
Fog::Logger.deprecation("#request with multiple parameters is deprecated, use #wrapped_request instead [light_black](#{caller.first})[/]")
|
|
wrapped_request(*args)
|
|
end
|
|
end
|
|
|
|
# Makes a request but with seperated arguments and parses the response to a hash
|
|
#
|
|
# @note #wrapped_request is the non-standard form of request introduced by mistake
|
|
#
|
|
# @param [String] method HTTP method to use for the request
|
|
# @param [String] path The absolute path for the request
|
|
# @param [Array<Fixnum>] expected_responses HTTP response codes that have been successful
|
|
# @param [Hash] parameters Keys and values for JSON
|
|
# @option parameters [String] :account_id The scoping account if required
|
|
#
|
|
# @return [Hash]
|
|
def wrapped_request(method, path, expected_responses, parameters = {})
|
|
_wrapped_request(method, path, expected_responses, parameters)
|
|
end
|
|
|
|
private
|
|
|
|
# Wrapped request is the non-standard form of request introduced by mistake
|
|
#
|
|
# @param [String] method HTTP method to use for the request
|
|
# @param [String] path The absolute path for the request
|
|
# @param [Array<Fixnum>] expected_responses HTTP response codes that have been successful
|
|
# @param [Hash] parameters Keys and values for JSON
|
|
# @option parameters [String] :account_id The scoping account if required
|
|
#
|
|
# @return [Hash]
|
|
def _wrapped_request(method, path, expected_responses, parameters = {})
|
|
request_options = {
|
|
:method => method.to_s.upcase,
|
|
:path => path,
|
|
:expects => expected_responses
|
|
}
|
|
|
|
# Select the account to scope for this request
|
|
account = scoped_account(parameters.fetch(:account_id, nil))
|
|
if account
|
|
request_options[:query] = { :account_id => account }
|
|
end
|
|
|
|
request_options[:body] = Fog::JSON.encode(parameters) unless parameters.empty?
|
|
|
|
response = make_request(request_options)
|
|
|
|
# FIXME We should revert to returning the Excon::Request after a suitable
|
|
# configuration option is in place to switch back to this incorrect behaviour
|
|
unless response.body.empty?
|
|
Fog::JSON.decode(response.body)
|
|
else
|
|
response
|
|
end
|
|
end
|
|
|
|
# Queries the API and tries to select the most suitable official Image
|
|
# to use if the user chooses not to select their own.
|
|
#
|
|
# @return [String] if image is found, the image's identifier
|
|
# @return [NilClass] if no image found or an error occured
|
|
#
|
|
def select_default_image
|
|
Fog::Brightbox::Compute::ImageSelector.new(list_images).latest_ubuntu
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|