Joyent Extraction
This commit is contained in:
parent
a7745f3d0f
commit
6db4bab94c
|
@ -1,33 +0,0 @@
|
|||
class Joyent < Fog::Bin
|
||||
class << self
|
||||
def class_for(key)
|
||||
case key
|
||||
when :compute
|
||||
Fog::Compute::Joyent
|
||||
when :analytics
|
||||
Fog::Joyent::Analytics
|
||||
else
|
||||
raise ArgumentError, "Unrecognized service: #{key}"
|
||||
end
|
||||
end
|
||||
|
||||
def [](service)
|
||||
@@connections ||= Hash.new do |hash, key|
|
||||
hash[key] = case key
|
||||
when :compute
|
||||
Fog::Logger.warning("Joyent[:compute] is not recommended, use Compute[:joyent] for portability")
|
||||
Fog::Compute.new(:provider => 'Joyent')
|
||||
when :analytics
|
||||
Fog::Joyent::Analytics.new
|
||||
else
|
||||
raise ArgumentError, "Unrecognized service: #{key.inspect}"
|
||||
end
|
||||
end
|
||||
@@connections[service]
|
||||
end
|
||||
|
||||
def services
|
||||
Fog::Joyent.services
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,12 +0,0 @@
|
|||
require 'fog/joyent/compute'
|
||||
require 'fog/joyent/errors'
|
||||
require 'fog/core'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
extend Fog::Provider
|
||||
|
||||
service(:analytics, 'Analytics')
|
||||
service(:compute, 'Compute')
|
||||
end
|
||||
end
|
|
@ -1,310 +0,0 @@
|
|||
require 'fog/joyent'
|
||||
require 'fog/joyent/errors'
|
||||
require 'thread'
|
||||
|
||||
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
|
||||
request :list_instrumentations
|
||||
request :get_instrumentation
|
||||
request :create_instrumentation
|
||||
request :delete_instrumentation
|
||||
request :get_instrumentation_value
|
||||
|
||||
model_path 'fog/joyent/models/analytics'
|
||||
|
||||
collection :joyent_modules
|
||||
model :joyent_module
|
||||
|
||||
collection :metrics
|
||||
model :metric
|
||||
|
||||
collection :fields
|
||||
model :field
|
||||
|
||||
collection :types
|
||||
model :type
|
||||
|
||||
collection :transformations
|
||||
model :transformation
|
||||
|
||||
collection :instrumentations
|
||||
model :instrumentation
|
||||
|
||||
model :value
|
||||
|
||||
class Mock
|
||||
def self.data
|
||||
@data ||= Hash.new do |hash, key|
|
||||
hash[key] =case key
|
||||
when :instrumentation
|
||||
{ 'module' => "cpu",
|
||||
'stat' => "usage",
|
||||
'predicate' => {},
|
||||
'decomposition' => ["zonename"],
|
||||
'value-dimension' => 2,
|
||||
'value-arity' => "discrete-decomposition",
|
||||
'enabled' => true,
|
||||
'retention-time' => 86400,
|
||||
'idle-max' => 86400,
|
||||
'transformations' => [],
|
||||
'nsources' => 3,
|
||||
'granularity' => 30,
|
||||
'persist-data' => false,
|
||||
'crtime' => 1388690982000,
|
||||
'value-scope' => "point",
|
||||
'id' => "63",
|
||||
'uris' =>
|
||||
[{ "uri" => "/#{@joyent_username}/analytics/instrumentations/63/value/raw",
|
||||
"name" => "value_raw" }] }
|
||||
when :values
|
||||
{
|
||||
'value' => { 'zoneid' => 0 },
|
||||
'transformations' => {},
|
||||
'start_time' => Time.now.utc - 600,
|
||||
'duration' => 30,
|
||||
'end_time' => Time.now.utc - 570,
|
||||
'nsources' => 1,
|
||||
'minreporting' => 1,
|
||||
'requested_start_time' => Time.now.utc - 600,
|
||||
'requested_duration' => 30,
|
||||
'requested_end_time' => Time.now.utc - 570
|
||||
}
|
||||
when :describe_analytics
|
||||
{
|
||||
'fields' => {
|
||||
'zonename' => {
|
||||
'label' => 'zone name',
|
||||
'type' => 'string'
|
||||
},
|
||||
'pid' => {
|
||||
'label' => 'process identifier',
|
||||
'type' => 'string'
|
||||
}
|
||||
},
|
||||
'modules' => {
|
||||
'cpu' => {
|
||||
'label' => 'CPU'
|
||||
}
|
||||
},
|
||||
'transformations' => {
|
||||
'geolocate' => {
|
||||
'label' => 'geolocate IP addresses',
|
||||
'fields' => ['raddr'] }
|
||||
},
|
||||
'metrics' => [{
|
||||
"module" => "cpu",
|
||||
"stat" => "thread_executions",
|
||||
"label" => "thread executions",
|
||||
"interval" => "interval",
|
||||
"fields" => ["hostname", "zonename", "runtime"],
|
||||
"unit" => "operations"
|
||||
}],
|
||||
'types' => {
|
||||
'string' => {
|
||||
'arity' => "discrete",
|
||||
'unit' => ""
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def data
|
||||
self.class.data
|
||||
end
|
||||
|
||||
def initialize(options = {})
|
||||
@joyent_username = options[:joyent_username]
|
||||
@joyent_password = options[:joyent_password]
|
||||
@joyent_url = 'https://us-sw-1.api.joyentcloud.com'
|
||||
@joyent_version = '~7'
|
||||
end
|
||||
|
||||
def request(opts)
|
||||
raise "Not Implemented"
|
||||
end
|
||||
end # Mock
|
||||
|
||||
class Real
|
||||
def initialize(options = {})
|
||||
@mutex = Mutex.new
|
||||
@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.exist?(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::XML::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
|
||||
if e.response.headers["Content-Type"] == "application/json"
|
||||
e.response.body = json_decode(e.response.body)
|
||||
end
|
||||
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)
|
||||
@mutex.synchronize do
|
||||
@key_manager.each_identity {}
|
||||
end
|
||||
|
||||
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
|
|
@ -1,272 +0,0 @@
|
|||
require 'fog/joyent/core'
|
||||
require 'fog/joyent/errors'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent < Fog::Service
|
||||
requires :joyent_username
|
||||
|
||||
recognizes :joyent_url
|
||||
|
||||
recognizes :joyent_keyname
|
||||
recognizes :joyent_keyfile
|
||||
recognizes :joyent_keydata
|
||||
recognizes :joyent_keyphrase
|
||||
recognizes :joyent_version
|
||||
|
||||
secrets :joyent_keydata, :joyent_keyphrase
|
||||
|
||||
model_path 'fog/joyent/models/compute'
|
||||
request_path 'fog/joyent/requests/compute'
|
||||
|
||||
request :list_datacenters
|
||||
# request :get_datacenter
|
||||
|
||||
# Datacenters
|
||||
collection :datacenters
|
||||
model :datacenter
|
||||
|
||||
# Keys
|
||||
collection :keys
|
||||
model :key
|
||||
|
||||
request :list_keys
|
||||
request :get_key
|
||||
request :create_key
|
||||
request :delete_key
|
||||
|
||||
# Images
|
||||
collection :images
|
||||
model :image
|
||||
request :list_datasets
|
||||
request :get_dataset
|
||||
request :list_images
|
||||
request :get_image
|
||||
|
||||
# Flavors
|
||||
collection :flavors
|
||||
model :flavor
|
||||
request :list_packages
|
||||
request :get_package
|
||||
|
||||
# Servers
|
||||
collection :servers
|
||||
model :server
|
||||
request :list_machines
|
||||
request :get_machine
|
||||
request :create_machine
|
||||
request :start_machine
|
||||
request :stop_machine
|
||||
request :reboot_machine
|
||||
request :resize_machine
|
||||
request :delete_machine
|
||||
|
||||
# Snapshots
|
||||
collection :snapshots
|
||||
model :snapshot
|
||||
request :create_machine_snapshot
|
||||
request :start_machine_from_snapshot
|
||||
request :list_machine_snapshots
|
||||
request :get_machine_snapshot
|
||||
request :delete_machine_snapshot
|
||||
request :update_machine_metadata
|
||||
request :get_machine_metadata
|
||||
request :delete_machine_metadata
|
||||
request :delete_all_machine_metadata
|
||||
|
||||
# MachineTags
|
||||
request :add_machine_tags
|
||||
request :list_machine_tags
|
||||
request :get_machine_tag
|
||||
request :delete_machine_tag
|
||||
request :delete_all_machine_tags
|
||||
|
||||
# Networks
|
||||
collection :networks
|
||||
model :network
|
||||
request :list_networks
|
||||
|
||||
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]
|
||||
end
|
||||
|
||||
def request(opts)
|
||||
raise "Not Implemented"
|
||||
end
|
||||
end # Mock
|
||||
|
||||
class Real
|
||||
attr_accessor :joyent_version
|
||||
attr_accessor :joyent_url
|
||||
|
||||
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]
|
||||
begin
|
||||
require "net/ssh"
|
||||
rescue LoadError
|
||||
Fog::Logger.warning("'net/ssh' missing, please install and try again.")
|
||||
exit(1)
|
||||
end
|
||||
@joyent_keyname = options[:joyent_keyname]
|
||||
@joyent_keyphrase = options[:joyent_keyphrase]
|
||||
@key_manager = Net::SSH::Authentication::KeyManager.new(nil, {
|
||||
:keys_only => true,
|
||||
:passphrase => @joyent_keyphrase
|
||||
})
|
||||
|
||||
if options[:joyent_keyfile]
|
||||
if File.exist?(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
|
||||
else
|
||||
raise ArgumentError, "Must provide a joyent_keyname and joyent_keyfile pair"
|
||||
end
|
||||
|
||||
@connection = Fog::XML::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_for_signature_auth)
|
||||
|
||||
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
|
||||
if e.response.headers["Content-Type"] == "application/json"
|
||||
e.response.body = json_decode(e.response.body)
|
||||
end
|
||||
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_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 400 then
|
||||
raise Joyent::Errors::BadRequest.new('Bad Request', request, response)
|
||||
when 401 then
|
||||
raise Joyent::Errors::Unauthorized.new('Invalid credentials were used', request, response)
|
||||
when 403 then
|
||||
raise Joyent::Errors::Forbidden.new('No permissions to the specified resource', request, response)
|
||||
when 404 then
|
||||
raise Joyent::Errors::NotFound.new('Requested resource was not found', request, response)
|
||||
when 405 then
|
||||
raise Joyent::Errors::MethodNotAllowed.new('Method not supported for the given resource', request, response)
|
||||
when 406 then
|
||||
raise Joyent::Errors::NotAcceptable.new('Try sending a different Accept header', request, response)
|
||||
when 409 then
|
||||
raise Joyent::Errors::Conflict.new('Most likely invalid or missing parameters', request, response)
|
||||
when 414 then
|
||||
raise Joyent::Errors::RequestEntityTooLarge.new('You sent too much data', request, response)
|
||||
when 415 then
|
||||
raise Joyent::Errors::UnsupportedMediaType.new('You encoded your request in a format we don\'t understand', request, response)
|
||||
when 420 then
|
||||
raise Joyent::Errors::PolicyNotForfilled.new('You are sending too many requests', request, response)
|
||||
when 449 then
|
||||
raise Joyent::Errors::RetryWith.new('Invalid API Version requested; try with a different API Version', request, response)
|
||||
when 503 then
|
||||
raise 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
|
|
@ -1,10 +0,0 @@
|
|||
require 'fog/core'
|
||||
require 'fog/json'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
extend Fog::Provider
|
||||
|
||||
service(:compute, 'Compute')
|
||||
end
|
||||
end
|
|
@ -1,91 +0,0 @@
|
|||
require 'fog/joyent/core'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent < Fog::Service
|
||||
class Errors
|
||||
module MessageParserMixin
|
||||
def message
|
||||
if response.body["code"] && response.body["message"]
|
||||
"[ERROR #{response.body['code']}] : #{response.body['message']}"
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
message
|
||||
end
|
||||
end
|
||||
|
||||
# https://us-west-1.api.joyentcloud.com/docs#cloudapi-http-responses
|
||||
#
|
||||
# HTTP Status Codes
|
||||
#
|
||||
# Your client should check for each of the following status codes from any API request:
|
||||
#
|
||||
# Response Code Description
|
||||
|
||||
# 400 Bad Request Invalid HTTP Request
|
||||
class BadRequest < Excon::Errors::BadRequest
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 401 Unauthorized Either no Authorization header was sent, or invalid credentials were used
|
||||
class Unauthorized < Excon::Errors::Unauthorized
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 403 Forbidden No permissions to the specified resource
|
||||
class Forbidden < Excon::Errors::Forbidden
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 404 Not Found Something you requested was not found
|
||||
class NotFound < Excon::Errors::NotFound
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 405 Method Not Allowed Method not supported for the given resource
|
||||
class MethodNotAllowed < Excon::Errors::MethodNotAllowed
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 406 Not Acceptable Try sending a different Accept header
|
||||
class NotAcceptable < Excon::Errors::NotAcceptable
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 409 Conflict Most likely invalid or missing parameters
|
||||
class Conflict < Excon::Errors::Conflict
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 413 Request Entity Too Large You sent too much data
|
||||
class RequestEntityTooLarge < Excon::Errors::RequestEntityTooLarge
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 415 Unsupported Media Type You encoded your request in a format we don't understand
|
||||
class UnsupportedMediaType < Excon::Errors::UnsupportedMediaType
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 420 Slow Down You're sending too many requests
|
||||
class PolicyNotForfilled < Excon::Errors::HTTPStatusError
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 449 Retry With Invalid Version header; try with a different X-Api-Version string
|
||||
class RetryWith < Excon::Errors::HTTPStatusError
|
||||
include MessageParserMixin
|
||||
end
|
||||
|
||||
# 503 Service Unavailable Either there's no capacity in this datacenter, or we're in a maintenance window
|
||||
class ServiceUnavailable < Excon::Errors::ServiceUnavailable
|
||||
include MessageParserMixin
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Field < Fog::Model
|
||||
attribute :name
|
||||
attribute :label
|
||||
attribute :type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
require 'fog/joyent/models/analytics/field'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Fields < Fog::Collection
|
||||
model Fog::Joyent::Analytics::Field
|
||||
|
||||
def all
|
||||
data = service.describe_analytics.body['fields']
|
||||
load(data)
|
||||
end
|
||||
|
||||
# Joyent returns an odd data structure like this:
|
||||
# { 'apache' => {'label' => 'Apache'}}
|
||||
# where the key is the name of the module
|
||||
def new(attributes = {})
|
||||
name, other_attributes = attributes
|
||||
super(other_attributes.merge('name' => name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,82 +0,0 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Instrumentation < Fog::Model
|
||||
identity :id
|
||||
attribute :joyent_module, :aliases => 'module'
|
||||
attribute :stat
|
||||
attribute :predicate
|
||||
attribute :decomposition, :type => :array
|
||||
attribute :value_dimension, :aliases => 'value-dimension', :type => :integer
|
||||
attribute :value_arity, :aliases => 'value-arity'
|
||||
attribute :retention_time, :aliases => 'retention-time', :type => :integer
|
||||
attribute :granularity, :type => :integer
|
||||
attribute :idle_max, :aliases => 'idle-max', :type => :integer
|
||||
attribute :transformations, :type => :array
|
||||
attribute :persist_data, :aliases => 'persist-data', :type => :boolean
|
||||
attribute :crtime
|
||||
attribute :value_scope, :aliases => 'value-scope'
|
||||
attribute :uris, :type => :array
|
||||
|
||||
def initialize(attributes={})
|
||||
self.decomposition = []
|
||||
self.value_arity = 'scalar'
|
||||
self.retention_time = 600
|
||||
self.idle_max = 3600
|
||||
self.persist_data = false
|
||||
self.value_scope = 'interval'
|
||||
super
|
||||
end
|
||||
|
||||
def crtime=(new_crtime)
|
||||
attributes[:crtime] = Time.at(new_crtime.to_i / 1000)
|
||||
end
|
||||
|
||||
def decomposition=(value)
|
||||
attributes[:decomposition] = value
|
||||
self.value_dimension = self.decomposition.size + 1
|
||||
self.decomposition
|
||||
end
|
||||
|
||||
def save
|
||||
requires :joyent_module, :stat
|
||||
munged_attributes = self.attributes.dup
|
||||
remap_attributes(munged_attributes, {
|
||||
:joyent_module => 'module',
|
||||
:value_dimension => 'value-dimension',
|
||||
:value_arity => 'value-arity',
|
||||
:retention_time => 'retention-time',
|
||||
:idle_max => 'idle-max',
|
||||
:persist_data => 'persist-data',
|
||||
:value_scope => 'value-scope'
|
||||
})
|
||||
|
||||
data = service.create_instrumentation(munged_attributes)
|
||||
merge_attributes(data.body)
|
||||
true
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :id
|
||||
service.delete_instrumentation(self.identity)
|
||||
true
|
||||
end
|
||||
|
||||
# Get a set of datapoints back for an instrumentation
|
||||
# use start_time and ndatapoints so we can get back a range of datapoints
|
||||
# the interval between datapoints should correspond to the granularity of the instrumentation
|
||||
# @param [Time] start_time
|
||||
# @param [Integer] ndatapoints
|
||||
def values(start_time, ndatapoints)
|
||||
requires :id, :granularity
|
||||
data = service.get_instrumentation_value(self.uris.find {|uri| uri['name'] == 'value_raw'}['uri'], start_time, ndatapoints, self.granularity).body
|
||||
data.map do |datum|
|
||||
Fog::Joyent::Analytics::Value.new(datum)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
require 'fog/joyent/models/analytics/instrumentation'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Instrumentations < Fog::Collection
|
||||
model Fog::Joyent::Analytics::Instrumentation
|
||||
|
||||
def all
|
||||
data = service.list_instrumentations.body
|
||||
load(data)
|
||||
end
|
||||
|
||||
def get(id)
|
||||
data = service.get_instrumentation(id).body
|
||||
new(data)
|
||||
rescue Fog::Compute::Joyent::Errors::NotFound
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
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 :name
|
||||
attribute :label
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
require 'fog/joyent/models/analytics/joyent_module'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class JoyentModules < Fog::Collection
|
||||
model Fog::Joyent::Analytics::JoyentModule
|
||||
|
||||
def all
|
||||
data = service.describe_analytics.body['modules']
|
||||
load(data)
|
||||
end
|
||||
|
||||
# Joyent returns an odd data structure like this:
|
||||
# { 'apache' => {'label' => 'Apache'}}
|
||||
# where the key is the name of the module
|
||||
def new(attributes = {})
|
||||
name, other_attributes = attributes
|
||||
super(other_attributes.merge('name' => name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Metric < Fog::Model
|
||||
attribute :module
|
||||
attribute :stat
|
||||
attribute :label
|
||||
attribute :interval
|
||||
attribute :fields
|
||||
attribute :unit
|
||||
attribute :type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
require 'fog/joyent/models/analytics/metric'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Metrics < Fog::Collection
|
||||
model Fog::Joyent::Analytics::Metric
|
||||
|
||||
def all
|
||||
data = service.describe_analytics.body['metrics']
|
||||
load(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Transformation < Fog::Model
|
||||
attribute :name
|
||||
attribute :label
|
||||
attribute :fields
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
require 'fog/joyent/models/analytics/transformation'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Transformations < Fog::Collection
|
||||
model Fog::Joyent::Analytics::Transformation
|
||||
|
||||
def all
|
||||
data = service.describe_analytics.body['transformations']
|
||||
load(data)
|
||||
end
|
||||
|
||||
# Joyent returns an odd data structure like this:
|
||||
# { 'apache' => {'label' => 'Apache'}}
|
||||
# where the key is the name of the module
|
||||
def new(attributes = {})
|
||||
name, other_attributes = attributes
|
||||
super(other_attributes.merge('name' => name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Type < Fog::Model
|
||||
attribute :name
|
||||
attribute :arity
|
||||
attribute :unit
|
||||
attribute :abbr
|
||||
attribute :base
|
||||
attribute :power
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
require 'fog/joyent/models/analytics/type'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Types < Fog::Collection
|
||||
model Fog::Joyent::Analytics::Type
|
||||
|
||||
def all
|
||||
data = service.describe_analytics.body['types']
|
||||
load(data)
|
||||
end
|
||||
|
||||
# Joyent returns an odd data structure like this:
|
||||
# { 'apache' => {'label' => 'Apache'}}
|
||||
# where the key is the name of the module
|
||||
def new(attributes = {})
|
||||
name, other_attributes = attributes
|
||||
super(other_attributes.merge('name' => name))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Value < Fog::Model
|
||||
attribute :value
|
||||
attribute :transformations
|
||||
attribute :start_time, :type => :timestamp
|
||||
attribute :duration
|
||||
attribute :end_time, :type => :timestamp
|
||||
attribute :nsources
|
||||
attribute :minreporting
|
||||
attribute :requested_start_time, :type => :timestamp
|
||||
attribute :requested_duration
|
||||
attribute :requested_end_time, :type => :timestamp
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Datacenter < Fog::Model
|
||||
identity :name
|
||||
|
||||
attribute :url
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/joyent/models/compute/datacenter'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Datacenters < Fog::Collection
|
||||
model Fog::Compute::Joyent::Datacenter
|
||||
|
||||
def all
|
||||
data = service.list_datacenters().body.map {|k,v| {:name => k, :url => v}}
|
||||
load(data)
|
||||
end
|
||||
|
||||
def get(id)
|
||||
all[id]
|
||||
end
|
||||
end
|
||||
end # Joyent
|
||||
end # Compute
|
||||
end # Fog
|
|
@ -1,19 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Flavor < Fog::Model
|
||||
identity :id
|
||||
|
||||
attribute :name
|
||||
attribute :memory
|
||||
attribute :swap
|
||||
attribute :disk
|
||||
attribute :vcpus
|
||||
attribute :default, :type => :boolean
|
||||
attribute :description
|
||||
attribute :version
|
||||
attribute :group
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/joyent/models/compute/flavor'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Flavors < Fog::Collection
|
||||
model Fog::Compute::Joyent::Flavor
|
||||
|
||||
def all
|
||||
load(service.list_packages().body)
|
||||
end
|
||||
|
||||
def get(id)
|
||||
data = service.get_package(id).body
|
||||
new(data)
|
||||
end
|
||||
end
|
||||
end # Joyent
|
||||
end # Compute
|
||||
end # Fog
|
|
@ -1,26 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Image < Fog::Model
|
||||
identity :id
|
||||
|
||||
attribute :name
|
||||
attribute :os
|
||||
attribute :version
|
||||
attribute :type
|
||||
attribute :description
|
||||
attribute :requirements
|
||||
attribute :homepage
|
||||
attribute :published_at, :type => :time
|
||||
attribute :public, :type => :boolean
|
||||
attribute :owner
|
||||
attribute :state
|
||||
attribute :tags
|
||||
attribute :eula
|
||||
attribute :acl
|
||||
attribute :created, :type => :time
|
||||
attribute :default, :type => :boolean
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/joyent/models/compute/image'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Images < Fog::Collection
|
||||
model Fog::Compute::Joyent::Image
|
||||
|
||||
def all
|
||||
# the API call for getting images changed from 6.5 to 7.0. Joyent seems to still support the old url, but no idea for how long
|
||||
if service.joyent_version.gsub(/[^0-9.]/,'').to_f < 7.0
|
||||
load(service.list_datasets.body)
|
||||
else
|
||||
load(service.list_images.body)
|
||||
end
|
||||
end
|
||||
|
||||
def get(id)
|
||||
data = if service.joyent_version.gsub(/[^0-9.]/,'').to_f < 7.0
|
||||
service.get_dataset(id).body
|
||||
else
|
||||
service.get_image(id).body
|
||||
end
|
||||
new(data)
|
||||
end
|
||||
end # Images
|
||||
end # Joyent
|
||||
end # Compute
|
||||
end # Fog
|
|
@ -1,19 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Key < Fog::Model
|
||||
identity :name
|
||||
|
||||
attribute :name
|
||||
attribute :key
|
||||
|
||||
attribute :created, :type => :time
|
||||
|
||||
def destroy
|
||||
requires :name
|
||||
service.delete_key(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
require 'fog/joyent/models/compute/key'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Keys < Fog::Collection
|
||||
model Fog::Compute::Joyent::Key
|
||||
|
||||
def all
|
||||
data = service.list_keys.body
|
||||
load(data)
|
||||
end
|
||||
|
||||
def get(keyname)
|
||||
data = service.get_key(keyname).body
|
||||
if data
|
||||
new(data)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def create(params = {})
|
||||
raise ArgumentError, "option [name] required" unless params.key?(:name)
|
||||
raise ArgumentError, "option [key] required" unless params.key?(:key)
|
||||
|
||||
service.create_key(params)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,12 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Network < Fog::Model
|
||||
identity :id
|
||||
|
||||
attribute :name
|
||||
attribute :public
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
require 'fog/joyent/models/compute/network'
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Networks < Fog::Collection
|
||||
model Fog::Compute::Joyent::Network
|
||||
|
||||
def all
|
||||
load(service.list_networks.body)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,124 +0,0 @@
|
|||
require 'fog/compute/models/server'
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Server < Fog::Compute::Server
|
||||
identity :id
|
||||
|
||||
attribute :name
|
||||
attribute :state
|
||||
attribute :type
|
||||
attribute :dataset
|
||||
attribute :compute_node
|
||||
attribute :networks
|
||||
attribute :ips
|
||||
attribute :memory
|
||||
attribute :disk
|
||||
attribute :metadata
|
||||
attribute :tags
|
||||
attribute :package
|
||||
attribute :image
|
||||
attribute :primary_ip, :aliases => 'primaryIp'
|
||||
|
||||
attribute :created, :type => :time
|
||||
attribute :updated, :type => :time
|
||||
|
||||
def public_ip_address
|
||||
ips.empty? ? nil : ips.first
|
||||
end
|
||||
|
||||
def ready?
|
||||
self.state == 'running'
|
||||
end
|
||||
|
||||
def stopped?
|
||||
requires :id
|
||||
self.state == 'stopped'
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :id
|
||||
service.delete_machine(id)
|
||||
true
|
||||
end
|
||||
|
||||
def start
|
||||
requires :id
|
||||
service.start_machine(id)
|
||||
self.wait_for { ready? }
|
||||
true
|
||||
end
|
||||
|
||||
def stop
|
||||
requires :id
|
||||
service.stop_machine(id)
|
||||
self.wait_for { stopped? }
|
||||
true
|
||||
end
|
||||
|
||||
def resize(flavor)
|
||||
requires :id
|
||||
service.resize_machine(id, flavor.name)
|
||||
true
|
||||
end
|
||||
|
||||
def reboot
|
||||
requires :id
|
||||
service.reboot_machine(id)
|
||||
true
|
||||
end
|
||||
|
||||
def snapshots
|
||||
requires :id
|
||||
service.snapshots.all(id)
|
||||
end
|
||||
|
||||
def update_metadata(data = {})
|
||||
requires :id
|
||||
service.update_machine_metadata(self.id, data)
|
||||
self.reload
|
||||
true
|
||||
end
|
||||
|
||||
def delete_metadata(keyname)
|
||||
raise ArgumentError, "Must provide a key name to delete" if keyname.nil? || keyname.empty?
|
||||
requires :id
|
||||
|
||||
service.delete_machine_metadata(self.id, keyname)
|
||||
true
|
||||
end
|
||||
|
||||
def delete_all_metadata
|
||||
requires :id
|
||||
service.delete_all_machine_metadata(self.id)
|
||||
true
|
||||
end
|
||||
|
||||
def list_tags
|
||||
requires :id
|
||||
service.list_machine_tags(id).body
|
||||
end
|
||||
|
||||
def add_tags(tags_hash = {})
|
||||
requires :id
|
||||
service.add_machine_tags(self.id, tags_hash).body
|
||||
end
|
||||
|
||||
def delete_tag(tagname)
|
||||
requires :id
|
||||
|
||||
raise ArgumentError, "Must provide a tag name to delete" if tagname.nil? || tagname.empty?
|
||||
service.delete_machine_tag(self.id, tagname)
|
||||
true
|
||||
end
|
||||
|
||||
def delete_all_tags
|
||||
requires :id
|
||||
|
||||
service.delete_all_machine_tags(self.id)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/joyent/models/compute/server'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Servers < Fog::Collection
|
||||
model Fog::Compute::Joyent::Server
|
||||
|
||||
def all
|
||||
load(service.list_machines().body)
|
||||
end
|
||||
|
||||
def create(params = {})
|
||||
data = service.create_machine(params).body
|
||||
server = new(data)
|
||||
server
|
||||
end
|
||||
|
||||
def bootstrap(new_attributes = {})
|
||||
server = create(new_attributes)
|
||||
server.wait_for { ready? }
|
||||
server
|
||||
end
|
||||
|
||||
def get(machine_id)
|
||||
data = service.get_machine(machine_id).body
|
||||
server = new(data)
|
||||
server.tags = server.list_tags if server.tags.nil?
|
||||
server
|
||||
end
|
||||
end
|
||||
end # Joyent
|
||||
end # Compute
|
||||
end # Fog
|
|
@ -1,44 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Snapshot < Fog::Model
|
||||
identity :name
|
||||
|
||||
attribute :name
|
||||
attribute :state
|
||||
attribute :machine_id
|
||||
attribute :created, :type => :time
|
||||
attribute :updated, :type => :time
|
||||
|
||||
def reload
|
||||
requires :name
|
||||
requires :machine_id
|
||||
|
||||
service.snapshots.get(self.machine_id, self.name)
|
||||
end
|
||||
|
||||
def start
|
||||
requires :name
|
||||
requires :machine_id
|
||||
|
||||
service.start_machine_from_snapshot(self.machine_id, self.name)
|
||||
true
|
||||
end
|
||||
|
||||
def destroy
|
||||
requires :name
|
||||
requires :machine_id
|
||||
|
||||
service.delete_machine_snapshot(self.machine_id, self.name)
|
||||
true
|
||||
end
|
||||
|
||||
def machine
|
||||
requires :machine_id
|
||||
|
||||
service.servers.get(self.machine_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
require 'fog/joyent/models/compute/snapshot'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Snapshots < Fog::Collection
|
||||
model Fog::Compute::Joyent::Snapshot
|
||||
|
||||
def create(machine_id, snapshot_name)
|
||||
data = self.service.create_machine_snapshot(machine_id, snapshot_name).body
|
||||
data['machine_id'] = machine_id
|
||||
new(data)
|
||||
end
|
||||
|
||||
def all(machine_id)
|
||||
data = service.list_machine_snapshots(machine_id).body.map do |m|
|
||||
m["machine_id"] = machine_id
|
||||
m
|
||||
end
|
||||
load(data)
|
||||
end
|
||||
|
||||
def get(machine_id, snapshot_name)
|
||||
data = service.get_machine_snapshot(machine_id, snapshot_name).body
|
||||
if data
|
||||
data["machine_id"] = machine_id
|
||||
new(data)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Real
|
||||
def create_instrumentation(values = {})
|
||||
request(
|
||||
:path => "#{@joyent_username}/analytics/instrumentations",
|
||||
:method => "POST",
|
||||
:body => values,
|
||||
:expects => [200,201]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def create_instrumentation(values = {})
|
||||
response = Excon::Response.new
|
||||
response.status = 201
|
||||
response.body = self.data[:instrumentation]
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Real
|
||||
def delete_instrumentation(id)
|
||||
request(
|
||||
:path => "#{@joyent_username}/analytics/instrumentations/#{id}",
|
||||
:method => "DELETE",
|
||||
:expects => 204
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def delete_instrumentation(id)
|
||||
response = Excon::Response.new
|
||||
response.status = 204
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Real
|
||||
def describe_analytics(force = false)
|
||||
@describe_analytics = nil if force
|
||||
@describe_analytics ||= request(
|
||||
:path => "#{@joyent_username}/analytics",
|
||||
:method => "GET",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def describe_analytics(force = false)
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = self.data[:describe_analytics]
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Real
|
||||
def get_instrumentation(id)
|
||||
request(
|
||||
:path => "#{@joyent_username}/analytics/instrumentations/#{id}",
|
||||
:method => "GET",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def get_instrumentation(id)
|
||||
raise Fog::Compute::Joyent::Errors::NotFound.new('not found') unless id == self.data[:instrumentation]['id']
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = self.data[:instrumentation]
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Real
|
||||
def get_instrumentation_value(url, requested_start_time, ndatapoints, duration)
|
||||
request(
|
||||
:path => url,
|
||||
:method => 'GET',
|
||||
:expects => 200,
|
||||
:idempotent => true,
|
||||
:query => {
|
||||
:ndatapoints => ndatapoints,
|
||||
:start_time => requested_start_time.to_i,
|
||||
:duration => duration
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def get_instrumentation_value(url, requested_start_time, ndatapoints, duration)
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = [self.data[:values]]
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
module Fog
|
||||
module Joyent
|
||||
class Analytics
|
||||
class Real
|
||||
def list_instrumentations
|
||||
request(
|
||||
:path => "#{@joyent_username}/analytics/instrumentations",
|
||||
:method => "GET",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
def list_instrumentations
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = [self.data[:instrumentation]]
|
||||
response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
# https://us-west-1.api.joyentcloud.com/docs#AddMachineTags
|
||||
def add_machine_tags(machine_id, tags={})
|
||||
raise ArgumentError, "tags must be a Hash of tags" unless tags.is_a?(Hash)
|
||||
|
||||
request(
|
||||
:path => "/my/machines/#{machine_id}/tags",
|
||||
:method => "POST",
|
||||
:body => tags,
|
||||
:expects => 200
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,54 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
#
|
||||
# https://us-west-1.api.joyentcloud.com/docs#CreateKey
|
||||
#
|
||||
def create_key(params)
|
||||
name = params[:name]
|
||||
key = params[:key]
|
||||
|
||||
record = {
|
||||
"name" => name,
|
||||
"key" => key,
|
||||
"created" => Time.now.utc,
|
||||
"updated" => Time.now.utc
|
||||
}
|
||||
|
||||
self.data[:keys][name] = record
|
||||
|
||||
response = Excon::Response.new
|
||||
response.status = 201
|
||||
response.body = record
|
||||
response
|
||||
end
|
||||
end # Mock
|
||||
|
||||
class Real
|
||||
# Creates a new SSH Key
|
||||
# ==== Parameters
|
||||
# * name<~String> - Name to assign to this key
|
||||
# * key<~String> - OpenSSH formatted public key
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * body<~Hash>:
|
||||
# * 'name'<~String> - Name for this key
|
||||
# * 'key'<~String> - OpenSSH formatted public key
|
||||
#
|
||||
def create_key(params={})
|
||||
raise ArgumentError, "error creating key: [name] is required" unless params[:name]
|
||||
raise ArgumentError, "error creating key: [key] is required" unless params[:key]
|
||||
|
||||
request(
|
||||
:method => "POST",
|
||||
:path => "/my/keys",
|
||||
:body => { "name" => params[:name], "key" => params[:key] },
|
||||
:expects => 201
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def create_machine(params = {})
|
||||
request(
|
||||
:method => "POST",
|
||||
:path => "/my/machines",
|
||||
:body => params,
|
||||
:expects => [200, 201, 202]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def create_machine_snapshot(machine_id, snapshot_name)
|
||||
request(
|
||||
:method => "POST",
|
||||
:path => "/my/machines/#{machine_id}/snapshots",
|
||||
:body => {"name" => snapshot_name },
|
||||
:expects => [201]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
# https://us-west-1.api.joyentcloud.com/docs#DeleteMachineMetadata
|
||||
def delete_all_machine_metadata(machine_id)
|
||||
request(
|
||||
:method => "DELETE",
|
||||
:path => "/my/machines/#{machine_id}/metadata",
|
||||
:expects => 204
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def delete_all_machine_tags(machine_id)
|
||||
request(
|
||||
:path => "/my/machines/#{machine_id}/tags",
|
||||
:method => "DELETE",
|
||||
:expects => 204
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def delete_key(keyname)
|
||||
if self.data[:keys].delete(keyname)
|
||||
response = Excon::Response.new
|
||||
response.status = 204
|
||||
response
|
||||
else
|
||||
raise Excon::Errors::NotFound, "Not Found"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def delete_key(name)
|
||||
request(
|
||||
:method => "DELETE",
|
||||
:path => "/my/keys/#{name}",
|
||||
:expects => 204
|
||||
)
|
||||
end
|
||||
end # Real
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def delete_machine(machine_id)
|
||||
request(
|
||||
:path => "/my/machines/#{machine_id}",
|
||||
:method => "DELETE",
|
||||
:expects => [200, 204, 410]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
# https://us-west-1.api.joyentcloud.com/docs#DeleteAllMachineMetadata
|
||||
def delete_machine_metadata(machine_id, key)
|
||||
request(
|
||||
:method => "DELETE",
|
||||
:path => "/my/machines/#{machine_id}/metadata/#{key}",
|
||||
:expects => [200, 204]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def delete_machine_snapshot(machine_id, snapshot)
|
||||
request(
|
||||
:method => "DELETE",
|
||||
:path => "/my/machines/#{machine_id}/snapshots/#{snapshot}",
|
||||
:expects => [200, 204]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def delete_machine_tag(machine_id, tagname)
|
||||
request(
|
||||
:path => "/my/machines/#{machine_id}/tags/#{tagname}",
|
||||
:method => "DELETE",
|
||||
:expects => 204
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def get_dataset(id)
|
||||
if ds = self.data[:datasets][id]
|
||||
res = Excon::Response.new
|
||||
res.status = 200
|
||||
res.body = ds
|
||||
else
|
||||
raise Excon::Errors::NotFound
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def get_dataset
|
||||
request(
|
||||
:method => "GET",
|
||||
:path => "/my/datasets",
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,28 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def get_image(id)
|
||||
if ds = self.data[:datasets][id]
|
||||
res = Excon::Response.new
|
||||
res.status = 200
|
||||
res.body = ds
|
||||
else
|
||||
raise Excon::Errors::NotFound
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def get_image(id)
|
||||
request(
|
||||
:method => "GET",
|
||||
:path => "/#{@joyent_username}/images/#{id}",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def get_key(keyid)
|
||||
if key = self.data[:keys][keyid]
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = key
|
||||
response
|
||||
else
|
||||
raise Excon::Errors::NotFound
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def get_key(keyid)
|
||||
request(
|
||||
:method => "GET",
|
||||
:path => "/my/keys/#{keyid}",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,29 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def get_machine(uuid)
|
||||
if machine = self.data[:machines][uuid]
|
||||
res = Excon::Response.new
|
||||
res.status = 200
|
||||
res.body = machine
|
||||
res
|
||||
else
|
||||
raise Excon::Errors::NotFound, "Not Found"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def get_machine(uuid)
|
||||
request(
|
||||
:method => "GET",
|
||||
:path => "/my/machines/#{uuid}",
|
||||
:expects => [200, 410],
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def get_machine_metadata(machine_id, options = {})
|
||||
query = {}
|
||||
if options[:credentials]
|
||||
if options[:credentials].is_a?(Boolean)
|
||||
query[:credentials] = options[:credentials]
|
||||
else
|
||||
raise ArgumentError, "options[:credentials] must be a Boolean or nil"
|
||||
end
|
||||
end
|
||||
|
||||
request(
|
||||
:path => "/my/machines/#{machine_id}/metadata",
|
||||
:query => query,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def get_machine_snapshot(machine_id, snapshot_name)
|
||||
request(
|
||||
:path => "/my/machines/#{machine_id}/snapshots/#{snapshot_name}",
|
||||
:method => "GET",
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
# https://us-west-1.api.joyentcloud.com/docs#GetMachineTag
|
||||
def get_machine_tag(machine_id, tagname)
|
||||
request(
|
||||
:path => "/my/machines/#{machine_id}/tags/#{tagname}",
|
||||
:method => "GET",
|
||||
:headers => {"Accept" => "text/plain"},
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
require 'uri'
|
||||
|
||||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def get_package(name)
|
||||
if pkg = self.data[:packages][name]
|
||||
response = Excon::Response.new
|
||||
response.body = pkg
|
||||
response.status = 200
|
||||
response
|
||||
else
|
||||
raise Excon::Errors::NotFound
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def get_package(name)
|
||||
name = URI.escape(name)
|
||||
request(
|
||||
:method => "GET",
|
||||
:path => "/my/packages/#{name}",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def list_datacenters
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => :'GET',
|
||||
:path => '/my/datacenters',
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end # Real
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def list_datasets
|
||||
res = Excon::Response.new
|
||||
res.status = 200
|
||||
res.body = self.data[:datasets].values
|
||||
res
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def list_datasets
|
||||
request(
|
||||
:method => "GET",
|
||||
:path => "/my/datasets",
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def list_images
|
||||
res = Excon::Response.new
|
||||
res.status = 200
|
||||
res.body = self.data[:datasets].values
|
||||
res
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def list_images
|
||||
request(
|
||||
:method => "GET",
|
||||
:path => "/#{@joyent_username}/images",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,25 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def list_keys
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = self.data[:keys].values
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def list_keys
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => :'GET',
|
||||
:path => '/my/keys',
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end # Real
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def list_machine_snapshots(machine_id)
|
||||
request(
|
||||
:method => "GET",
|
||||
:path => "/my/machines/#{machine_id}/snapshots",
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
# https://us-west-1.api.joyentcloud.com/docs#ListMachineTags
|
||||
def list_machine_tags(machine_id)
|
||||
request(
|
||||
:path => "/my/machines/#{machine_id}/tags",
|
||||
:method => "GET",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def list_machines(options={})
|
||||
res = Excon::Response.new
|
||||
res.status = 200
|
||||
res.body = self.data[:machines].values
|
||||
res
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def list_machines(options={})
|
||||
request(
|
||||
:path => "/my/machines",
|
||||
:method => "GET",
|
||||
:query => options,
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def list_networks(options={})
|
||||
res = Excon::Response.new
|
||||
res.status = 200
|
||||
res.body = self.data[:networks].values
|
||||
res
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
def list_networks(options={})
|
||||
request(
|
||||
:path => "/my/networks",
|
||||
:method => "GET",
|
||||
:query => options,
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,34 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Mock
|
||||
def list_packages
|
||||
response = Excon::Response.new()
|
||||
response.status = 200
|
||||
response.body = self.data[:packages].values
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
# Lists all the packages available to the authenticated user
|
||||
# ==== Returns
|
||||
# Exon::Response<Array>
|
||||
# * name<~String> The "friendly name for this package
|
||||
# * memory<~Number> How much memory will by available (in Mb)
|
||||
# * disk<~Number> How much disk space will be available (in Gb)
|
||||
# * swap<~Number> How much swap memory will be available (in Mb)
|
||||
# * default<~Boolean> Whether this is the default package in this datacenter"
|
||||
#
|
||||
def list_packages
|
||||
request(
|
||||
:path => "/my/packages",
|
||||
:method => "GET",
|
||||
:expects => 200,
|
||||
:idempotent => true
|
||||
)
|
||||
end
|
||||
end # Real
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def reboot_machine(id)
|
||||
request(
|
||||
:method => "POST",
|
||||
:query => {"action" => "reboot"},
|
||||
:path => "/my/machines/#{id}"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def resize_machine(id, package)
|
||||
request(
|
||||
:method => "POST",
|
||||
:path => "/my/machines/#{id}",
|
||||
:query => {"action" => "resize", "package" => package},
|
||||
:expects => [202]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def start_machine(id)
|
||||
request(
|
||||
:method => "POST",
|
||||
:path => "/my/machines/#{id}",
|
||||
:query => {"action" => "start"},
|
||||
:expects => 202
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def start_machine_from_snapshot(machine_id, snapshot_name)
|
||||
request(
|
||||
:method => "POST",
|
||||
:path => "/my/machines/#{machine_id}/snapshots/#{snapshot_name}",
|
||||
:expects => 202
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def stop_machine(uuid)
|
||||
request(
|
||||
:method => "POST",
|
||||
:path => "/my/machines/#{uuid}",
|
||||
:query => {"action" => "stop"},
|
||||
:expects => 202
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,15 +0,0 @@
|
|||
module Fog
|
||||
module Compute
|
||||
class Joyent
|
||||
class Real
|
||||
def update_machine_metadata(machine_id, metadata)
|
||||
request(
|
||||
:method => "POST",
|
||||
:path => "/my/machines/#{machine_id}/metadata",
|
||||
:body => metadata
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -71,9 +71,6 @@ def compute_providers
|
|||
:server_attributes => {},
|
||||
:mocked => true
|
||||
},
|
||||
:joyent => {
|
||||
:mocked => false
|
||||
},
|
||||
:openstack => {
|
||||
:mocked => true,
|
||||
:server_attributes => {
|
||||
|
|
|
@ -45,8 +45,6 @@ if Fog.mock?
|
|||
:os_account_meta_temp_url_key => 'os_account_meta_temp_url_key',
|
||||
:ibm_username => 'ibm_username',
|
||||
:ibm_password => 'ibm_password',
|
||||
:joyent_username => "joyentuser",
|
||||
:joyent_password => "joyentpass",
|
||||
:linode_api_key => 'linode_api_key',
|
||||
:local_root => '~/.fog',
|
||||
:bare_metal_cloud_password => 'bare_metal_cloud_password',
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | field", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@field = @analytics.fields.first
|
||||
|
||||
tests('read only') do
|
||||
returns(false, 'should not save') { @field.respond_to?(:save)}
|
||||
returns(false, 'should not allow creating a new one') { @field.respond_to?(:create)}
|
||||
returns(false, 'should not allow destroying') { @field.respond_to?(:destroy)}
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | fields", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@fields = @analytics.fields
|
||||
|
||||
tests('#all').succeeds do
|
||||
@fields.all
|
||||
end
|
||||
|
||||
tests('#new').succeeds do
|
||||
@fields.new(['apache', { 'label' => 'Apache', 'type' => 'string' }])
|
||||
end
|
||||
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | instrumentation", %w{joyent }) do
|
||||
model_tests(Fog::Joyent[:analytics].instrumentations, {:joyent_module => 'cpu', :stat => 'usage'}, true)
|
||||
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@instrumentation = @analytics.instrumentations.first
|
||||
|
||||
tests('#values') do
|
||||
@values = @instrumentation.values(Time.now.utc.to_i - 600, 5)
|
||||
|
||||
returns(Array) { @values.class }
|
||||
returns(Fog::Joyent::Analytics::Value) { @values.first.class }
|
||||
end
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | instrumentations", %w{joyent}) do
|
||||
collection_tests(Fog::Joyent[:analytics].instrumentations, {:joyent_module => 'cpu', :stat => 'usage'}, true)
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | joyent_module", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@joyent_module = @analytics.joyent_modules.first
|
||||
|
||||
tests('read only') do
|
||||
returns(false, 'should not save') { @joyent_module.respond_to?(:save)}
|
||||
returns(false, 'should not allow creating a new one') { @joyent_module.respond_to?(:create)}
|
||||
returns(false, 'should not allow destroying') { @joyent_module.respond_to?(:destroy)}
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | joyent_modules", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@joyent_modules = @analytics.joyent_modules
|
||||
|
||||
tests('#all').succeeds do
|
||||
@joyent_modules.all
|
||||
end
|
||||
|
||||
tests('#new').succeeds do
|
||||
@joyent_modules.new(['cpu', { 'label' => 'CPU' }])
|
||||
end
|
||||
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | metric", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@metric = @analytics.metrics.first
|
||||
|
||||
tests('read only') do
|
||||
returns(false, 'should not save') { @metric.respond_to?(:save)}
|
||||
returns(false, 'should not allow creating a new one') { @metric.respond_to?(:create)}
|
||||
returns(false, 'should not allow destroying') { @metric.respond_to?(:destroy)}
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | metrics", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@metrics = @analytics.metrics
|
||||
|
||||
tests('#all').succeeds do
|
||||
@metrics.all
|
||||
end
|
||||
|
||||
tests('#new').succeeds do
|
||||
@metrics.new({
|
||||
"module" => "cpu",
|
||||
"stat" => "thread_executions",
|
||||
"label" => "thread executions",
|
||||
"interval" => "interval",
|
||||
"fields" => ["hostname", "zonename", "runtime"],
|
||||
"unit" => "operations"
|
||||
})
|
||||
end
|
||||
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | transformation", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@transformation = @analytics.transformations.first
|
||||
|
||||
tests('read only') do
|
||||
returns(false, 'should not save') { @transformation.respond_to?(:save)}
|
||||
returns(false, 'should not allow creating a new one') { @transformation.respond_to?(:create)}
|
||||
returns(false, 'should not allow destroying') { @transformation.respond_to?(:destroy)}
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | transformations", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@transformations = @analytics.transformations
|
||||
|
||||
tests('#all').succeeds do
|
||||
@transformations.all
|
||||
end
|
||||
|
||||
tests('#new').succeeds do
|
||||
@transformations.new(['geolocate', { 'label' => 'geolocate IP addresses', "fields" => ["raddr"] }])
|
||||
end
|
||||
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | type", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@type = @analytics.types.first
|
||||
|
||||
tests('read only') do
|
||||
returns(false, 'should not save') { @type.respond_to?(:save)}
|
||||
returns(false, 'should not allow creating a new one') { @type.respond_to?(:create)}
|
||||
returns(false, 'should not allow destroying') { @type.respond_to?(:destroy)}
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | types", %w{joyent}) do
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
@types = @analytics.types
|
||||
|
||||
tests('#all').succeeds do
|
||||
@types.all
|
||||
end
|
||||
|
||||
tests('#new').succeeds do
|
||||
@types.new(['string', {'arity' => 'discrete', 'unit' => ''}])
|
||||
end
|
||||
|
||||
end
|
|
@ -1,44 +0,0 @@
|
|||
Shindo.tests("Fog::Joyent[:analytics] | instrumentation requests", %w{joyent}) do
|
||||
|
||||
@analytics = Fog::Joyent[:analytics]
|
||||
|
||||
@instrumentation_schema = {
|
||||
'id' => String,
|
||||
'module' => String,
|
||||
'stat' => String,
|
||||
'predicate' => Hash,
|
||||
'decomposition' => [String],
|
||||
'value-dimension' => Integer,
|
||||
'value-arity' => String,
|
||||
'retention-time' => Integer,
|
||||
'granularity' => Integer,
|
||||
'idle-max' => Integer,
|
||||
'transformations' => [String],
|
||||
'persist-data' => Fog::Boolean,
|
||||
'crtime' => Integer,
|
||||
'value-scope' => String,
|
||||
'uris' => [
|
||||
{
|
||||
'uri' => String,
|
||||
'name' => String
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
tests('#create_instrumentation').data_matches_schema(@instrumentation_schema) do
|
||||
@analytics.create_instrumentation.body
|
||||
end
|
||||
|
||||
tests('#list_instrumentations') do
|
||||
data_matches_schema(@instrumentation_schema) do
|
||||
@analytics.list_instrumentations.body.first
|
||||
end
|
||||
|
||||
returns(Array) { @analytics.list_instrumentations.body.class }
|
||||
end
|
||||
|
||||
tests('#delete_instrumentation') do
|
||||
returns(204) { @analytics.delete_instrumentation(Fog::Joyent::Analytics::Mock.data[:instrumentation]['id']).status }
|
||||
end
|
||||
|
||||
end
|
|
@ -1,58 +0,0 @@
|
|||
Shindo.tests("Fog::Compute[:joyent] | dataset requests", ["joyent"]) do
|
||||
@dataset_format = {
|
||||
"description" => String,
|
||||
"requirements" => {
|
||||
"max_memory" => Integer,
|
||||
"min_memory" => Integer
|
||||
},
|
||||
"name" => String,
|
||||
"version" => String,
|
||||
"os" => String,
|
||||
"id" => String,
|
||||
"urn" => String,
|
||||
"default" => Fog::Boolean,
|
||||
"type" => String,
|
||||
"created" => Time,
|
||||
}
|
||||
|
||||
if Fog.mock?
|
||||
Fog::Compute[:joyent].data[:datasets] = {
|
||||
"33904834-1f01-49d3-bed3-b642e158c375" => {
|
||||
"id" => "33904834-1f01-49d3-bed3-b642e158c375",
|
||||
"urn" => "sdc:sdc:zeus-simple-lb-200mbps:1.1.1",
|
||||
"name" => "zeus-simple-lb-200mbps",
|
||||
"os" => "smartos",
|
||||
"type" => "smartmachine",
|
||||
"description" => "Zeus Simple Load Balancer 200 Mbps SmartMachine",
|
||||
"default" => false,
|
||||
"requirements" => {
|
||||
"max_memory" => 32768,
|
||||
"min_memory" => 4096
|
||||
},
|
||||
"version" => "1.1.1",
|
||||
"created" => Time.parse("2011-09-15T07:39:13+00:00")
|
||||
},
|
||||
"3fcf35d2-dd79-11e0-bdcd-b3c7ac8aeea6" => {
|
||||
"id" => "3fcf35d2-dd79-11e0-bdcd-b3c7ac8aeea6",
|
||||
"urn" => "sdc:sdc:mysql:1.4.1",
|
||||
"name" => "mysql",
|
||||
"os" => "smartos",
|
||||
"type" => "smartmachine",
|
||||
"description" => "MySQL SmartMachine",
|
||||
"default" => false,
|
||||
"requirements" => {
|
||||
"max_memory" => 32768,
|
||||
"min_memory" => 4096
|
||||
},
|
||||
"version" => "1.4.1",
|
||||
"created" => Time.parse("2011-09-15T05:01:34+00:00")
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
tests("#list_datasets") do
|
||||
formats(@dataset_format) do
|
||||
Fog::Compute[:joyent].list_datasets.body.first
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
Shindo.tests("Fog::Compute[:joyent] | key requests", ['joyent']) do
|
||||
|
||||
@key_format = {
|
||||
"name" => String,
|
||||
"key" => String,
|
||||
"created" => Time,
|
||||
"updated" => Time
|
||||
}
|
||||
|
||||
before do
|
||||
#
|
||||
# Clear out all the test keys on the account in prep for test
|
||||
#
|
||||
Fog::Compute[:joyent].list_keys.body.each do |key|
|
||||
if key["name"] =~ /^fog-test/
|
||||
Fog::Compute[:joyent].delete_key(key["name"])
|
||||
end
|
||||
end
|
||||
|
||||
@test_key_name = "fog-test-#{Time.now.utc.to_i}"
|
||||
|
||||
Fog::Compute[:joyent].create_key(
|
||||
:name => @test_key_name,
|
||||
:key => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDWxSNYngOTeu0pYd+2tpfYGISuMfMUNGyAIh4yRprAbacVddRq4Nyr12vDklzaRTzgd9PgX/82JMb4RARbVTtUKXJXmaBLvg2epGM+ScanZIitzL53whJrlGx+7nT+TnRdkB1XG7uIf2EpTQBaKrT4iG0magCXh5bmOqCyWte2gV8fArMg5bZclUT1p2E7qEW0htaLOiMSyGkjBlxb6vYQCA/Pa8VWETHehIF46S942gCj0aaL81gTocfyTm5/F+AgvUAsjHzRVkB/Dlhwq7Q7sK+4iAhlKPYMflkKC8r+nF0/LL9S3lllLZvbkEWJfEqlMCAbgmjTpYlBzQEqf/eN"
|
||||
)
|
||||
end
|
||||
|
||||
tests("#list_keys").formats(@key_format) do
|
||||
Fog::Compute[:joyent].list_keys.body.first
|
||||
end
|
||||
|
||||
tests("#get_key").formats(@key_format) do
|
||||
Fog::Compute[:joyent].get_key(@test_key_name).body
|
||||
end
|
||||
|
||||
tests("#delete_key") do
|
||||
returns(204 , "returns status code 204") do
|
||||
Fog::Compute[:joyent].delete_key(@test_key_name).status
|
||||
end
|
||||
|
||||
raises(Excon::Errors::NotFound, "when a key no longer exists") do
|
||||
Fog::Compute[:joyent].delete_key(@test_key_name)
|
||||
Fog::Compute[:joyent].delete_key(@test_key_name)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,66 +0,0 @@
|
|||
Shindo.tests("Fog::Compute[:joyent] | machine requests", ["joyent"]) do
|
||||
|
||||
@machine_format = {
|
||||
"id" => String,
|
||||
"name" => String,
|
||||
"type" => String,
|
||||
"state" => String,
|
||||
"dataset" => String,
|
||||
"memory" => Integer,
|
||||
"disk" => Integer,
|
||||
"ips" => Array,
|
||||
"metadata" => Hash,
|
||||
"created" => Time,
|
||||
"updated" => Time
|
||||
}
|
||||
|
||||
if Fog.mock?
|
||||
@machines = Fog::Compute[:joyent].data[:machines] = {
|
||||
"15080eca-3786-4bb8-a4d0-f43e1981cd72" => {
|
||||
"id" => "15080eca-3786-4bb8-a4d0-f43e1981cd72",
|
||||
"name" => "getting-started",
|
||||
"type" => "smartmachine",
|
||||
"state" => "running",
|
||||
"dataset" => "sdc:sdc:smartos:1.3.15",
|
||||
"memory" => 256,
|
||||
"disk" => 5120,
|
||||
"ips" => ["10.88.88.50"],
|
||||
"metadata" => {},
|
||||
"created" => Time.parse("2011-06-03T00:02:31+00:00"),
|
||||
"updated" => Time.parse("2011-06-03T00:02:31+00:00")
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
@provider = Fog::Compute[:joyent]
|
||||
|
||||
#
|
||||
# https://us-west-1.api.joyentcloud.com/docs#ListMachines
|
||||
#
|
||||
tests("#list_machines") do
|
||||
if Fog.mock?
|
||||
returns(@machines.length, "correct number of machines") do
|
||||
@provider.list_machines.body.length
|
||||
end
|
||||
end
|
||||
|
||||
returns(Array, "returns an Array of machines") do
|
||||
@provider.list_machines.body.class
|
||||
end
|
||||
|
||||
formats([@machine_format]) do
|
||||
@provider.list_machines.body
|
||||
end
|
||||
end
|
||||
|
||||
# https://us-west-1.api.joyentcloud.com/docs#GetMachine
|
||||
tests("#get_machine") do
|
||||
machines = @provider.list_machines.body
|
||||
unless machines.empty?
|
||||
formats(@machine_format) do
|
||||
id = machines.first["id"]
|
||||
@provider.get_machine(id).body
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,39 +0,0 @@
|
|||
Shindo.tests("Fog::Compute[:joyent] | network requests", ["joyent"]) do
|
||||
@provider = Fog::Compute[:joyent]
|
||||
@network_format = {
|
||||
"id" => String,
|
||||
"name" => String,
|
||||
"public" => Fog::Boolean
|
||||
}
|
||||
|
||||
if Fog.mock?
|
||||
@networks = Fog::Compute[:joyent].data[:networks] = {
|
||||
"193d6804-256c-4e89-a4cd-46f045959993" => {
|
||||
"id" => "193d6804-256c-4e89-a4cd-46f045959993",
|
||||
"name" => "Joyent-SDC-Private",
|
||||
"public" => false
|
||||
},
|
||||
"1e7bb0e1-25a9-43b6-bb19-f79ae9540b39" => {
|
||||
"id" => "1e7bb0e1-25a9-43b6-bb19-f79ae9540b39",
|
||||
"name" => "Joyent-SDC-Public",
|
||||
"public" => true
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
tests("#list_networks") do
|
||||
if Fog.mock?
|
||||
returns(@networks.length, "correct number of networks") do
|
||||
@provider.list_networks.body.length
|
||||
end
|
||||
end
|
||||
|
||||
returns(Array, "returns an Array of networks") do
|
||||
@provider.list_networks.body.class
|
||||
end
|
||||
|
||||
formats([@network_format]) do
|
||||
@provider.list_networks.body
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,68 +0,0 @@
|
|||
Shindo.tests("Fog::Compute[:joyent] | package requests", ["joyent"]) do
|
||||
@package_format = {
|
||||
'name' => String,
|
||||
'vcpus' => Integer,
|
||||
'memory' => Integer,
|
||||
'disk' => Integer,
|
||||
'swap' => Integer,
|
||||
'default' => Fog::Boolean
|
||||
}
|
||||
|
||||
if Fog.mock?
|
||||
@data = Fog::Compute[:joyent].data
|
||||
|
||||
@data[:packages] = {
|
||||
"regular_128" => {
|
||||
"name" => "regular_128",
|
||||
"memory" => 128,
|
||||
"disk" => 5120,
|
||||
"vcpus" => 1,
|
||||
"swap" => 256,
|
||||
"default" => true
|
||||
},
|
||||
"regular_256" => {
|
||||
"name" => "regular_256",
|
||||
"memory" => 256,
|
||||
"disk" => 5120,
|
||||
"vcpus" => 1,
|
||||
"swap" => 512,
|
||||
"default" => false
|
||||
},
|
||||
"regular_512" => {
|
||||
"name" => "regular_512",
|
||||
"memory" => 512,
|
||||
"disk" => 10240,
|
||||
"vcpus" => 1,
|
||||
"swap" => 1024,
|
||||
"default" => false
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
tests("#list_packages") do
|
||||
formats([@package_format]) do
|
||||
Fog::Compute[:joyent].list_packages.body
|
||||
end
|
||||
end
|
||||
|
||||
if Fog.mock?
|
||||
tests("#list_packages") do
|
||||
actual = @data[:packages].values.length
|
||||
returns(actual, "has correct number of packages") do
|
||||
Fog::Compute[:joyent].list_packages.body.length
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tests("#get_package") do
|
||||
pkgid = if Fog.mock?
|
||||
@data[:packages].keys.first
|
||||
else
|
||||
Fog::Compute[:joyent].list_packages.body.first["name"]
|
||||
end
|
||||
|
||||
formats(@package_format) do
|
||||
Fog::Compute[:joyent].get_package(pkgid).body
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue