mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
[openstack|metering] Added metering service for Ceilometer
This commit is contained in:
parent
4fb0522361
commit
d37d2e802a
15 changed files with 585 additions and 0 deletions
|
@ -15,6 +15,8 @@ class OpenStack < Fog::Bin
|
|||
Fog::Storage::OpenStack
|
||||
when :volume
|
||||
Fog::Volume::OpenStack
|
||||
when :metering
|
||||
Fog::Metering::OpenStack
|
||||
else
|
||||
raise ArgumentError, "Unrecognized service: #{key}"
|
||||
end
|
||||
|
@ -41,6 +43,9 @@ class OpenStack < Fog::Bin
|
|||
when :volume
|
||||
Fog::Logger.warning("OpenStack[:volume] is not recommended, use Volume[:openstack] for portability")
|
||||
Fog::Volume.new(:provider => 'OpenStack')
|
||||
when :metering
|
||||
Fog::Logger.warning("OpenStack[:metering] is not recommended, use Metering[:openstack] for portability")
|
||||
Fog::Metering.new(:provider => 'OpenStack')
|
||||
else
|
||||
raise ArgumentError, "Unrecognized service: #{key.inspect}"
|
||||
end
|
||||
|
|
25
lib/fog/metering.rb
Normal file
25
lib/fog/metering.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
module Fog
|
||||
module Metering
|
||||
|
||||
def self.[](provider)
|
||||
self.new(:provider => provider)
|
||||
end
|
||||
|
||||
def self.new(attributes)
|
||||
attributes = attributes.dup # Prevent delete from having side effects
|
||||
provider = attributes.delete(:provider).to_s.downcase.to_sym
|
||||
if self.providers.include?(provider)
|
||||
require "fog/#{provider}/metering"
|
||||
return Fog::Metering.const_get(Fog.providers[provider]).new(attributes)
|
||||
end
|
||||
|
||||
raise ArgumentError.new("#{provider} has no identity service")
|
||||
end
|
||||
|
||||
def self.providers
|
||||
Fog.services[:metering]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -47,6 +47,7 @@ module Fog
|
|||
service(:network, 'openstack/network', 'Network')
|
||||
service(:storage, 'openstack/storage', 'Storage')
|
||||
service(:volume, 'openstack/volume', 'Volume')
|
||||
service(:metering, 'openstack/metering', 'Metering')
|
||||
|
||||
# legacy v1.0 style auth
|
||||
def self.authenticate_v1(options, connection_options = {})
|
||||
|
|
215
lib/fog/openstack/metering.rb
Normal file
215
lib/fog/openstack/metering.rb
Normal file
|
@ -0,0 +1,215 @@
|
|||
require 'fog/metering'
|
||||
require 'fog/openstack'
|
||||
|
||||
module Fog
|
||||
module Metering
|
||||
class OpenStack < Fog::Service
|
||||
|
||||
requires :openstack_auth_url
|
||||
recognizes :openstack_auth_token, :openstack_management_url, :persistent,
|
||||
:openstack_service_type, :openstack_service_name, :openstack_tenant,
|
||||
:openstack_api_key, :openstack_username,
|
||||
:current_user, :current_tenant,
|
||||
:openstack_endpoint_type
|
||||
|
||||
model_path 'fog/openstack/models/metering'
|
||||
|
||||
model :resource
|
||||
collection :resources
|
||||
|
||||
|
||||
request_path 'fog/openstack/requests/metering'
|
||||
|
||||
# Metering
|
||||
request :get_resource
|
||||
request :get_samples
|
||||
request :get_statistics
|
||||
request :list_meters
|
||||
request :list_resources
|
||||
|
||||
|
||||
class Mock
|
||||
def self.data
|
||||
@data ||= Hash.new do |hash, key|
|
||||
hash[key] = {
|
||||
:users => {},
|
||||
:tenants => {}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.reset
|
||||
@data = nil
|
||||
end
|
||||
|
||||
def initialize(options={})
|
||||
require 'multi_json'
|
||||
@openstack_username = options[:openstack_username]
|
||||
@openstack_tenant = options[:openstack_tenant]
|
||||
@openstack_auth_uri = URI.parse(options[:openstack_auth_url])
|
||||
|
||||
@auth_token = Fog::Mock.random_base64(64)
|
||||
@auth_token_expiration = (Time.now.utc + 86400).iso8601
|
||||
|
||||
management_url = URI.parse(options[:openstack_auth_url])
|
||||
management_url.port = 8776
|
||||
management_url.path = '/v1'
|
||||
@openstack_management_url = management_url.to_s
|
||||
|
||||
@data ||= { :users => {} }
|
||||
unless @data[:users].find {|u| u['name'] == options[:openstack_username]}
|
||||
id = Fog::Mock.random_numbers(6).to_s
|
||||
@data[:users][id] = {
|
||||
'id' => id,
|
||||
'name' => options[:openstack_username],
|
||||
'email' => "#{options[:openstack_username]}@mock.com",
|
||||
'tenantId' => Fog::Mock.random_numbers(6).to_s,
|
||||
'enabled' => true
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def data
|
||||
self.class.data[@openstack_username]
|
||||
end
|
||||
|
||||
def reset_data
|
||||
self.class.data.delete(@openstack_username)
|
||||
end
|
||||
|
||||
def credentials
|
||||
{ :provider => 'openstack',
|
||||
:openstack_auth_url => @openstack_auth_uri.to_s,
|
||||
:openstack_auth_token => @auth_token,
|
||||
:openstack_management_url => @openstack_management_url }
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
attr_reader :current_user
|
||||
attr_reader :current_tenant
|
||||
|
||||
def initialize(options={})
|
||||
require 'multi_json'
|
||||
|
||||
@openstack_auth_token = options[:openstack_auth_token]
|
||||
|
||||
unless @openstack_auth_token
|
||||
missing_credentials = Array.new
|
||||
@openstack_api_key = options[:openstack_api_key]
|
||||
@openstack_username = options[:openstack_username]
|
||||
|
||||
missing_credentials << :openstack_api_key unless @openstack_api_key
|
||||
missing_credentials << :openstack_username unless @openstack_username
|
||||
raise ArgumentError, "Missing required arguments: #{missing_credentials.join(', ')}" unless missing_credentials.empty?
|
||||
end
|
||||
|
||||
@openstack_tenant = options[:openstack_tenant]
|
||||
@openstack_auth_uri = URI.parse(options[:openstack_auth_url])
|
||||
@openstack_management_url = options[:openstack_management_url]
|
||||
@openstack_must_reauthenticate = false
|
||||
@openstack_service_type = options[:openstack_service_type] || ['metering']
|
||||
@openstack_service_name = options[:openstack_service_name]
|
||||
|
||||
@openstack_endpoint_type = options[:openstack_endpoint_type] || 'adminURL'
|
||||
@connection_options = options[:connection_options] || {}
|
||||
|
||||
@current_user = options[:current_user]
|
||||
@current_tenant = options[:current_tenant]
|
||||
|
||||
authenticate
|
||||
|
||||
@persistent = options[:persistent] || false
|
||||
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
|
||||
end
|
||||
|
||||
def credentials
|
||||
{ :provider => 'openstack',
|
||||
:openstack_auth_url => @openstack_auth_uri.to_s,
|
||||
:openstack_auth_token => @auth_token,
|
||||
:openstack_management_url => @openstack_management_url,
|
||||
:current_user => @current_user,
|
||||
:current_tenant => @current_tenant }
|
||||
end
|
||||
|
||||
def reload
|
||||
@connection.reset
|
||||
end
|
||||
|
||||
def request(params)
|
||||
begin
|
||||
response = @connection.request(params.merge({
|
||||
:headers => {
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'X-Auth-Token' => @auth_token
|
||||
}.merge!(params[:headers] || {}),
|
||||
:host => @host,
|
||||
:path => "#{@path}/v2/#{params[:path]}"#,
|
||||
# Causes errors for some requests like tenants?limit=1
|
||||
# :query => ('ignore_awful_caching' << Time.now.to_i.to_s)
|
||||
}))
|
||||
rescue Excon::Errors::Unauthorized => error
|
||||
if error.response.body != 'Bad username or password' # token expiration
|
||||
@openstack_must_reauthenticate = true
|
||||
authenticate
|
||||
retry
|
||||
else # bad credentials
|
||||
raise error
|
||||
end
|
||||
rescue Excon::Errors::HTTPStatusError => error
|
||||
raise case error
|
||||
when Excon::Errors::NotFound
|
||||
Fog::Compute::OpenStack::NotFound.slurp(error)
|
||||
else
|
||||
error
|
||||
end
|
||||
end
|
||||
unless response.body.empty?
|
||||
response.body = MultiJson.decode(response.body)
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticate
|
||||
if !@openstack_management_url || @openstack_must_reauthenticate
|
||||
options = {
|
||||
:openstack_tenant => @openstack_tenant,
|
||||
:openstack_api_key => @openstack_api_key,
|
||||
:openstack_username => @openstack_username,
|
||||
:openstack_auth_uri => @openstack_auth_uri,
|
||||
:openstack_auth_token => @openstack_auth_token,
|
||||
:openstack_service_type => @openstack_service_type,
|
||||
:openstack_service_name => @openstack_service_name,
|
||||
:openstack_endpoint_type => @openstack_endpoint_type
|
||||
}
|
||||
|
||||
credentials = Fog::OpenStack.authenticate_v2(options, @connection_options)
|
||||
|
||||
@current_user = credentials[:user]
|
||||
@current_tenant = credentials[:tenant]
|
||||
|
||||
@openstack_must_reauthenticate = false
|
||||
@auth_token = credentials[:token]
|
||||
@openstack_management_url = credentials[:server_management_url]
|
||||
uri = URI.parse(@openstack_management_url)
|
||||
else
|
||||
@auth_token = @openstack_auth_token
|
||||
uri = URI.parse(@openstack_management_url)
|
||||
end
|
||||
|
||||
@host = uri.host
|
||||
@path = uri.path
|
||||
@path.sub!(/\/$/, '')
|
||||
@port = uri.port
|
||||
@scheme = uri.scheme
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
0
lib/fog/openstack/models/metering/meter.rb
Normal file
0
lib/fog/openstack/models/metering/meter.rb
Normal file
0
lib/fog/openstack/models/metering/meters.rb
Normal file
0
lib/fog/openstack/models/metering/meters.rb
Normal file
24
lib/fog/openstack/models/metering/resource.rb
Normal file
24
lib/fog/openstack/models/metering/resource.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Metering
|
||||
class OpenStack
|
||||
|
||||
class Resource < Fog::Model
|
||||
|
||||
identity :resource_id
|
||||
|
||||
attribute :project_id
|
||||
attribute :user_id
|
||||
attribute :metadata
|
||||
|
||||
def initialize(attributes)
|
||||
prepare_service_value(attributes)
|
||||
super
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
25
lib/fog/openstack/models/metering/resources.rb
Normal file
25
lib/fog/openstack/models/metering/resources.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/openstack/models/metering/resource'
|
||||
|
||||
module Fog
|
||||
module Metering
|
||||
class OpenStack
|
||||
|
||||
class Resources < Fog::Collection
|
||||
model Fog::Metering::OpenStack::Resource
|
||||
|
||||
def all(detailed=true)
|
||||
load(service.list_resources.body)
|
||||
end
|
||||
|
||||
def find_by_id(resource_id)
|
||||
resource = service.get_resource(resource_id).body
|
||||
new(resource)
|
||||
rescue Fog::Metering::OpenStack::NotFound
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
32
lib/fog/openstack/requests/metering/get_resource.rb
Normal file
32
lib/fog/openstack/requests/metering/get_resource.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module Metering
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def get_resource(resource_id)
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => "resources/#{resource_id}"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_resource(resource_id)
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = {
|
||||
'resource_id'=>'glance',
|
||||
'project_id'=>'d646b40dea6347dfb8caee2da1484c56',
|
||||
'user_id'=>'1d5fd9eda19142289a60ed9330b5d284',
|
||||
'metadata'=>{}}
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
53
lib/fog/openstack/requests/metering/get_samples.rb
Normal file
53
lib/fog/openstack/requests/metering/get_samples.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
module Fog
|
||||
module Metering
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def get_samples(meter_id, options = {})
|
||||
|
||||
data = {
|
||||
'q' => Array.new
|
||||
}
|
||||
|
||||
filters = ['field', 'op', 'value']
|
||||
filter = {}
|
||||
filters.select{|o| options[o]}.each do |key|
|
||||
filter[key] = options[key]
|
||||
end
|
||||
|
||||
data['q'] << filter unless filter.empty?
|
||||
|
||||
request(
|
||||
:body => Fog::JSON.encode(data),
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => "meters/#{meter_id}"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_samples(meter_id)
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = [{
|
||||
'counter_name'=>'image.size',
|
||||
'user_id'=>'1d5fd9eda19142289a60ed9330b5d284',
|
||||
'resource_id'=>'glance',
|
||||
'timestamp'=>'2013-04-03T23:44:21',
|
||||
'resource_metadata'=>{},
|
||||
'source'=>'artificial',
|
||||
'counter_unit'=>'bytes',
|
||||
'counter_volume'=>10.0,
|
||||
'project_id'=>'d646b40dea6347dfb8caee2da1484c56',
|
||||
'message_id'=>'14e4a902-9cf3-11e2-a054-003048f5eafc',
|
||||
'counter_type'=>'gauge'}]
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
54
lib/fog/openstack/requests/metering/get_statistics.rb
Normal file
54
lib/fog/openstack/requests/metering/get_statistics.rb
Normal file
|
@ -0,0 +1,54 @@
|
|||
module Fog
|
||||
module Metering
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def get_statistics(meter_id, options={})
|
||||
|
||||
data = {
|
||||
'period' => options['period'],
|
||||
'q' => Array.new
|
||||
}
|
||||
|
||||
filters = ['field', 'op', 'value']
|
||||
filter = {}
|
||||
filters.select{|o| options[o]}.each do |key|
|
||||
filter[key] = options[key]
|
||||
end
|
||||
|
||||
data['q'] << filter unless filter.empty?
|
||||
|
||||
request(
|
||||
:body => Fog::JSON.encode(data),
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => "meters/#{meter_id}/statistics"
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_statistics(meter_id)
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = [{
|
||||
'count'=>143,
|
||||
'duration_start'=>'2013-04-03T23:44:21',
|
||||
'min'=>10.0,
|
||||
'max'=>10.0,
|
||||
'duration_end'=>'2013-04-04T23:24:21',
|
||||
'period'=>0,
|
||||
'period_end'=>'2013-04-04T23:24:21',
|
||||
'duration'=>85200.0,
|
||||
'period_start'=>'2013-04-03T23:44:21',
|
||||
'avg'=>10.0,
|
||||
'sum'=>1430.0}]
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
48
lib/fog/openstack/requests/metering/list_meters.rb
Normal file
48
lib/fog/openstack/requests/metering/list_meters.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
module Fog
|
||||
module Metering
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_meters(options={})
|
||||
|
||||
data = {
|
||||
'q' => Array.new
|
||||
}
|
||||
|
||||
filters = ['field', 'op', 'value']
|
||||
filter = {}
|
||||
filters.select{|o| options[o]}.each do |key|
|
||||
filter[key] = options[key]
|
||||
end
|
||||
|
||||
data['q'] << filter unless filter.empty?
|
||||
|
||||
request(
|
||||
:body => Fog::JSON.encode(data),
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => 'meters'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_meters(options={})
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = [{
|
||||
'user_id'=>'1d5fd9eda19142289a60ed9330b5d284',
|
||||
'name'=>'image.size',
|
||||
'resource_id'=>'glance',
|
||||
'project_id'=>'d646b40dea6347dfb8caee2da1484c56',
|
||||
'type'=>'gauge',
|
||||
'unit'=>'bytes'}]
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
32
lib/fog/openstack/requests/metering/list_resources.rb
Normal file
32
lib/fog/openstack/requests/metering/list_resources.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module Metering
|
||||
class OpenStack
|
||||
class Real
|
||||
|
||||
def list_resources(options = {})
|
||||
request(
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => 'resources'
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def list_resources(options = {})
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.body = [{
|
||||
'resource_id'=>'glance',
|
||||
'project_id'=>'d646b40dea6347dfb8caee2da1484c56',
|
||||
'user_id'=>'1d5fd9eda19142289a60ed9330b5d284',
|
||||
'metadata'=>{}}]
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
52
tests/openstack/requests/metering/meter_tests.rb
Normal file
52
tests/openstack/requests/metering/meter_tests.rb
Normal file
|
@ -0,0 +1,52 @@
|
|||
Shindo.tests('Fog::Metering[:openstack] | meter requests', ['openstack']) do
|
||||
|
||||
@sample_format = {
|
||||
'counter_name' => String,
|
||||
'user_id' => String,
|
||||
'resource_id' => String,
|
||||
'timestamp' => String,
|
||||
'resource_metadata' => Hash,
|
||||
'source' => String,
|
||||
'counter_unit' => String,
|
||||
'counter_volume' => Float,
|
||||
'project_id' => String,
|
||||
'message_id' => String,
|
||||
'counter_type' => String
|
||||
}
|
||||
|
||||
@meter_format = {
|
||||
'user_id' => String,
|
||||
'name' => String,
|
||||
'resource_id' => String,
|
||||
'project_id' => String,
|
||||
'type' => String,
|
||||
'unit' => String
|
||||
}
|
||||
|
||||
@statistics_format = {
|
||||
'count' => Integer,
|
||||
'duration_start' => String,
|
||||
'min' => Float,
|
||||
'max' => Float,
|
||||
'duration_end' => String,
|
||||
'period' => Integer,
|
||||
'period_end' => String,
|
||||
'duration' => Float,
|
||||
'period_start' => String,
|
||||
'avg' => Float,
|
||||
'sum' => Float
|
||||
}
|
||||
tests('success') do
|
||||
tests('#list_meters').formats([@meter_format]) do
|
||||
Fog::Metering[:openstack].list_meters.body
|
||||
end
|
||||
|
||||
tests('#get_samples').formats([@sample_format]) do
|
||||
Fog::Metering[:openstack].get_samples('test').body
|
||||
end
|
||||
|
||||
tests('#get_statistics').formats([@statistics_format]) do
|
||||
Fog::Metering[:openstack].get_statistics('test').body
|
||||
end
|
||||
end
|
||||
end
|
19
tests/openstack/requests/metering/resource_tests.rb
Normal file
19
tests/openstack/requests/metering/resource_tests.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
Shindo.tests('Fog::Metering[:openstack] | resource requests', ['openstack']) do
|
||||
|
||||
@resource_format = {
|
||||
'resource_id' => String,
|
||||
'project_id' => String,
|
||||
'user_id' => String,
|
||||
'metadata' => Hash,
|
||||
}
|
||||
|
||||
tests('success') do
|
||||
tests('#list_resource').formats([@resource_format]) do
|
||||
Fog::Metering[:openstack].list_resources.body
|
||||
end
|
||||
|
||||
tests('#get_resource').formats(@resource_format) do
|
||||
Fog::Metering[:openstack].get_resource('test').body
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue