1
0
Fork 0
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:
Philip Mark M. Deazeta 2013-04-05 11:39:45 +08:00
parent 4fb0522361
commit d37d2e802a
15 changed files with 585 additions and 0 deletions

View file

@ -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
View 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

View file

@ -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 = {})

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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