mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
Basic analytics support including a class for joyent 'modules'. Note that these are named 'JoyentModule' instead of 'Module' to avoid obvious namespace problems.
This commit is contained in:
parent
2150f32b74
commit
35964c89aa
5 changed files with 224 additions and 0 deletions
|
@ -4,6 +4,7 @@ module Fog
|
|||
module Joyent
|
||||
extend Fog::Provider
|
||||
|
||||
service(:analytics, 'joyent/analytics', 'Analytics')
|
||||
service(:compute, 'joyent/compute', 'Compute')
|
||||
|
||||
end
|
||||
|
|
210
lib/fog/joyent/analytics.rb
Normal file
210
lib/fog/joyent/analytics.rb
Normal file
|
@ -0,0 +1,210 @@
|
|||
require 'fog/joyent'
|
||||
require 'fog/joyent/errors'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics < Fog::Service
|
||||
requires :joyent_username
|
||||
|
||||
recognizes :joyent_password
|
||||
recognizes :joyent_url
|
||||
|
||||
recognizes :joyent_keyname
|
||||
recognizes :joyent_keyfile
|
||||
recognizes :joyent_keydata
|
||||
recognizes :joyent_keyphrase
|
||||
recognizes :joyent_version
|
||||
request_path 'fog/joyent/requests/analytics'
|
||||
|
||||
request :describe_analytics
|
||||
|
||||
|
||||
model_path 'fog/joyent/models/analytics'
|
||||
|
||||
collection :joyent_modules
|
||||
model :joyent_module
|
||||
|
||||
class Mock
|
||||
def self.data
|
||||
@data ||= Hash.new do |hash, key|
|
||||
hash[key] = {}
|
||||
end
|
||||
end
|
||||
|
||||
def data
|
||||
self.class.data
|
||||
end
|
||||
|
||||
def initialize(options = {})
|
||||
@joyent_username = options[:joyent_username] || Fog.credentials[:joyent_username]
|
||||
@joyent_password = options[:joyent_password] || Fog.credentials[:joyent_password]
|
||||
end
|
||||
|
||||
def request(opts)
|
||||
raise "Not Implemented"
|
||||
end
|
||||
end # Mock
|
||||
|
||||
class Real
|
||||
def initialize(options = {})
|
||||
|
||||
@connection_options = options[:connection_options] || {}
|
||||
@persistent = options[:persistent] || false
|
||||
|
||||
@joyent_url = options[:joyent_url] || 'https://us-sw-1.api.joyentcloud.com'
|
||||
@joyent_version = options[:joyent_version] || '~7'
|
||||
@joyent_username = options[:joyent_username]
|
||||
|
||||
unless @joyent_username
|
||||
raise ArgumentError, "options[:joyent_username] required"
|
||||
end
|
||||
|
||||
if options[:joyent_keyname]
|
||||
@joyent_keyname = options[:joyent_keyname]
|
||||
@joyent_keyphrase = options[:joyent_keyphrase]
|
||||
@key_manager = Net::SSH::Authentication::KeyManager.new(nil, {
|
||||
:keys_only => true,
|
||||
:passphrase => @joyent_keyphrase
|
||||
})
|
||||
@header_method = method(:header_for_signature_auth)
|
||||
|
||||
if options[:joyent_keyfile]
|
||||
if File.exists?(options[:joyent_keyfile])
|
||||
@joyent_keyfile = options[:joyent_keyfile]
|
||||
@key_manager.add(@joyent_keyfile)
|
||||
else
|
||||
raise ArgumentError, "options[:joyent_keyfile] provided does not exist."
|
||||
end
|
||||
elsif options[:joyent_keydata]
|
||||
if options[:joyent_keydata].to_s.empty?
|
||||
raise ArgumentError, 'options[:joyent_keydata] must not be blank'
|
||||
else
|
||||
@joyent_keydata = options[:joyent_keydata]
|
||||
@key_manager.add_key_data(@joyent_keydata)
|
||||
end
|
||||
end
|
||||
elsif options[:joyent_password]
|
||||
@joyent_password = options[:joyent_password]
|
||||
@header_method = method(:header_for_basic_auth)
|
||||
else
|
||||
raise ArgumentError, "Must provide either a joyent_password or joyent_keyname and joyent_keyfile pair"
|
||||
end
|
||||
|
||||
@connection = Fog::Connection.new(
|
||||
@joyent_url,
|
||||
@persistent,
|
||||
@connection_options
|
||||
)
|
||||
end
|
||||
|
||||
def request(opts = {})
|
||||
opts[:headers] = {
|
||||
"X-Api-Version" => @joyent_version,
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json"
|
||||
}.merge(opts[:headers] || {}).merge(@header_method.call)
|
||||
|
||||
if opts[:body]
|
||||
opts[:body] = Fog::JSON.encode(opts[:body])
|
||||
end
|
||||
|
||||
|
||||
response = @connection.request(opts)
|
||||
if response.headers["Content-Type"] == "application/json"
|
||||
response.body = json_decode(response.body)
|
||||
end
|
||||
|
||||
response
|
||||
rescue Excon::Errors::HTTPStatusError => e
|
||||
raise_if_error!(e.request, e.response)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def json_decode(body)
|
||||
parsed = Fog::JSON.decode(body)
|
||||
decode_time_attrs(parsed)
|
||||
end
|
||||
|
||||
def header_for_basic_auth
|
||||
{
|
||||
"Authorization" => "Basic #{Base64.encode64("#{@joyent_username}:#{@joyent_password}").delete("\r\n")}"
|
||||
}
|
||||
end
|
||||
|
||||
def header_for_signature_auth
|
||||
date = Time.now.utc.httpdate
|
||||
|
||||
# Force KeyManager to load the key(s)
|
||||
@key_manager.each_identity {}
|
||||
|
||||
key = @key_manager.known_identities.keys.first
|
||||
|
||||
sig = if key.kind_of? OpenSSL::PKey::RSA
|
||||
@key_manager.sign(key, date)[15..-1]
|
||||
else
|
||||
key = OpenSSL::PKey::DSA.new(File.read(@joyent_keyfile), @joyent_keyphrase)
|
||||
key.sign('sha1', date)
|
||||
end
|
||||
|
||||
key_id = "/#{@joyent_username}/keys/#{@joyent_keyname}"
|
||||
key_type = key.class.to_s.split('::').last.downcase.to_sym
|
||||
|
||||
unless [:rsa, :dsa].include? key_type
|
||||
raise Joyent::Errors::Unauthorized.new('Invalid key type -- only rsa or dsa key is supported')
|
||||
end
|
||||
|
||||
signature = Base64.encode64(sig).delete("\r\n")
|
||||
|
||||
{
|
||||
"Date" => date,
|
||||
"Authorization" => "Signature keyId=\"#{key_id}\",algorithm=\"#{key_type}-sha1\" #{signature}"
|
||||
}
|
||||
rescue Net::SSH::Authentication::KeyManagerError => e
|
||||
raise Joyent::Errors::Unauthorized.new('SSH Signing Error: :#{e.message}', e)
|
||||
end
|
||||
|
||||
def decode_time_attrs(obj)
|
||||
if obj.kind_of?(Hash)
|
||||
obj["created"] = Time.parse(obj["created"]) unless obj["created"].nil? or obj["created"] == ''
|
||||
obj["updated"] = Time.parse(obj["updated"]) unless obj["updated"].nil? or obj["updated"] == ''
|
||||
elsif obj.kind_of?(Array)
|
||||
obj.map do |o|
|
||||
decode_time_attrs(o)
|
||||
end
|
||||
end
|
||||
|
||||
obj
|
||||
end
|
||||
|
||||
def raise_if_error!(request, response)
|
||||
case response.status
|
||||
when 401 then
|
||||
raise Fog::Compute::Joyent::Errors::Unauthorized.new('Invalid credentials were used', request, response)
|
||||
when 403 then
|
||||
raise Fog::Compute::Joyent::Errors::Forbidden.new('No permissions to the specified resource', request, response)
|
||||
when 404 then
|
||||
raise Fog::Compute::Joyent::Errors::NotFound.new('Requested resource was not found', request, response)
|
||||
when 405 then
|
||||
raise Fog::Compute::Joyent::Errors::MethodNotAllowed.new('Method not supported for the given resource', request, response)
|
||||
when 406 then
|
||||
raise Fog::Compute::Joyent::Errors::NotAcceptable.new('Try sending a different Accept header', request, response)
|
||||
when 409 then
|
||||
raise Fog::Compute::Joyent::Errors::Conflict.new('Most likely invalid or missing parameters', request, response)
|
||||
when 414 then
|
||||
raise Fog::Compute::Joyent::Errors::RequestEntityTooLarge.new('You sent too much data', request, response)
|
||||
when 415 then
|
||||
raise Fog::Compute::Joyent::Errors::UnsupportedMediaType.new('You encoded your request in a format we don\'t understand', request, response)
|
||||
when 420 then
|
||||
raise Fog::Compute::Joyent::Errors::PolicyNotForfilled.new('You are sending too many requests', request, response)
|
||||
when 449 then
|
||||
raise Fog::Compute::Joyent::Errors::RetryWith.new('Invalid API Version requested; try with a different API Version', request, response)
|
||||
when 503 then
|
||||
raise Fog::Compute::Joyent::Errors::ServiceUnavailable.new('Either there\'s no capacity in this datacenter, or we\'re in a maintenance window', request, response)
|
||||
end
|
||||
end
|
||||
|
||||
end # Real
|
||||
end
|
||||
end
|
||||
end
|
13
lib/fog/joyent/models/analytics/joyent_module.rb
Normal file
13
lib/fog/joyent/models/analytics/joyent_module.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
|
||||
# named 'JoyentModule' to avoid name conflicts with ruby's 'Module'
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class JoyentModule < Fog::Model
|
||||
attribute :label
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
0
lib/fog/joyent/models/analytics/joyent_modules.rb
Normal file
0
lib/fog/joyent/models/analytics/joyent_modules.rb
Normal file
0
lib/fog/joyent/requests/analytics/describe_analytics.rb
Normal file
0
lib/fog/joyent/requests/analytics/describe_analytics.rb
Normal file
Loading…
Add table
Reference in a new issue