From 9a3b74b0dbb655a3afcbc8bdee442f2143420b72 Mon Sep 17 00:00:00 2001 From: Aimon Bustardo Date: Sun, 14 Dec 2014 19:50:03 -0800 Subject: [PATCH] Aviator 0.2.1 - Update to Aviator 0.2.1 - Update example is README --- Modulefile | 2 +- README | 15 +- .../feature/aviator/core/cli/describer.rb | 4 +- lib/puppet/feature/aviator/core/response.rb | 14 +- lib/puppet/feature/aviator/core/service.rb | 21 ++- lib/puppet/feature/aviator/core/session.rb | 149 +++++++++++++----- .../requests/v3/public/create_token.rb | 5 +- .../feature/aviator/openstack/provider.rb | 15 +- lib/puppet/feature/aviator/version.rb | 2 +- 9 files changed, 158 insertions(+), 69 deletions(-) diff --git a/Modulefile b/Modulefile index cd152bd8a..133a66cb9 100644 --- a/Modulefile +++ b/Modulefile @@ -1,5 +1,5 @@ name 'aimonb-aviator' -version '0.5.0' +version '0.5.1' source 'https://github.com/aimonb/puppet_aviator' author 'aimonb' license 'MIT License' diff --git a/README b/README index d5ef1a00d..db81dbee9 100644 --- a/README +++ b/README @@ -37,12 +37,9 @@ Example Usage: } } - session = Aviator::Session.new( - :config => configuration, - :log_file => '/var/log/aviator.log' - ) - - session.authenticate - keystone = session.identity_service - response = keystone.request(:list_tenants, :endpoint_type => -'admin') + openstack = Aviator::Session.new(:config => configuration) + + openstack.authenticate + response = openstack.request :identity_service, :list_tenants, :endpoint_type => 'admin' + + puts response[:body] diff --git a/lib/puppet/feature/aviator/core/cli/describer.rb b/lib/puppet/feature/aviator/core/cli/describer.rb index 13e11de0b..a6ad8507a 100644 --- a/lib/puppet/feature/aviator/core/cli/describer.rb +++ b/lib/puppet/feature/aviator/core/cli/describer.rb @@ -36,7 +36,7 @@ def self.describe_request(provider_name, service_name, api_version, endpoint_typ request_class = "Aviator::#{ provider_name.camelize }::#{ service_name.camelize }::Requests::"\ "#{ api_version.camelize }::#{ endpoint_type.camelize }::#{ request_name.camelize }".constantize - display = ":Request => #{ request_name }\n" + display = "Request: #{ request_name }\n" # Build the parameters @@ -83,7 +83,7 @@ def self.describe_request(provider_name, service_name, api_version, endpoint_typ # Build the sample code display << "\nSample Code:\n" - display << " session.#{ service_name }_service.request(:#{ request_name })" + display << " session.request(:#{ service_name }_service, :#{ request_name })" if params && params.length > 0 display << " do |params|\n" diff --git a/lib/puppet/feature/aviator/core/response.rb b/lib/puppet/feature/aviator/core/response.rb index 43fad0b99..12c9561af 100644 --- a/lib/puppet/feature/aviator/core/response.rb +++ b/lib/puppet/feature/aviator/core/response.rb @@ -14,7 +14,7 @@ def initialize(response, request) def body - if raw_body.length > 0 + @body ||= if raw_body.length > 0 if Aviator::Compatibility::RUBY_1_8_MODE clean_body = raw_body.gsub(/\\ /, ' ') else @@ -29,14 +29,22 @@ def body def headers - Hashish.new(@response.headers) + @headers ||= Hashish.new(@response.headers) end + def to_hash + Hashish.new({ + :status => status, + :headers => headers, + :body => body + }) + end + private def raw_body - @response.body + @raw_body ||= @response.body end end diff --git a/lib/puppet/feature/aviator/core/service.rb b/lib/puppet/feature/aviator/core/service.rb index 01d9fe70e..f31645549 100644 --- a/lib/puppet/feature/aviator/core/service.rb +++ b/lib/puppet/feature/aviator/core/service.rb @@ -1,5 +1,8 @@ module Aviator + # + # Manages a service + # class Service class AccessDetailsNotDefinedError < StandardError @@ -35,7 +38,6 @@ def initialize(service_name, request_name) end end - class UnknownRequestError < StandardError def initialize(request_name, options) super "Unknown request #{ request_name } #{ options }." @@ -75,7 +77,9 @@ def initialize(opts={}) load_requests end - + # + # No longer recommended for public use. Use Aviator::Session#request instead + # def request(request_name, options={}, ¶ms) if options[:api_version].nil? && @default_options[:api_version] options[:api_version] = @default_options[:api_version] @@ -93,6 +97,19 @@ def request(request_name, options={}, ¶ms) raise UnknownRequestError.new(request_name, options) unless request_class + # Always use :params over ¶ms if provided + if options[:params] + params = lambda do |params| + options[:params].each do |key, value| + begin + params[key] = value + rescue NameError => e + raise NameError.new("Unknown param name '#{key}'") + end + end + end + end + request = request_class.new(session_data, ¶ms) response = http_connection.send(request.http_method) do |r| diff --git a/lib/puppet/feature/aviator/core/session.rb b/lib/puppet/feature/aviator/core/session.rb index f7ec05fab..f93db097c 100644 --- a/lib/puppet/feature/aviator/core/session.rb +++ b/lib/puppet/feature/aviator/core/session.rb @@ -1,12 +1,14 @@ +# +# Author:: Mark Maglana (mmaglana@gmail.com) +# Copyright:: Copyright (c) 2014 Mark Maglana +# License:: Distributed under the MIT license +# Homepage:: http://aviator.github.io/www/ +# module Aviator # - # Manages a provider (e.g. OpenStack) session. - # - # Author:: Mark Maglana (mmaglana@gmail.com) - # Copyright:: Copyright (c) 2014 Mark Maglana - # License:: Distributed under the MIT license - # Homepage:: http://aviator.github.io/www/ + # Manages a provider (e.g. OpenStack) session and serves as the entry point + # for a consumer class/object. See Session::new for notes on usage. # class Session @@ -51,8 +53,7 @@ def initialize end # - # Create a new Session instance with options provided in opts which can - # have many forms discussed below. + # Create a new Session instance. # # Initialize with a config file # @@ -73,17 +74,20 @@ def initialize # password: mypassword # tenant_name: myproject # + # SIDENOTE: For more information about the validator member, see Session#validate. + # # Once the session has been instantiated, you may authenticate against the # provider as follows: # # session.authenticate # - # Note that the required items under auth_credentials in the config - # file depends on the required parameters of the request class declared under - # auth_service. If writing the auth_credentials in the config - # file is not acceptable, you may omit it and just supply the credentials at - # runtime. For instance, assume that the auth_credentials section in the - # config file above is missing. You would then authenticate as follows: + # The members you put under auth_credentials will depend on the request + # class you declare under auth_service:request and what parameters it + # accepts. To know more about a request class and its parameters, you can use + # the CLI tool aviator describe or view the request definition file directly. + # + # If writing the auth_credentials in the config file is not acceptable, + # you may omit it and just supply the credentials at runtime. For example: # # session.authenticate do |params| # params.username = ARGV[0] @@ -91,7 +95,7 @@ def initialize # params.tenant_name = ARGV[2] # end # - # Please see Session#authenticate for more info. + # See Session#authenticate for more info. # # Note that while the example config file above only has one environment (production), # you can declare an arbitrary number of environments in your config file. Shifting @@ -100,8 +104,8 @@ def initialize # # Initialize with an in-memory hash # - # You can create an in-memory hash which is similar in structure to the config file except - # that you don't need to specify an environment name. For example: + # You can create an in-memory hash with a structure similar to the config file but without + # the environment name. For example: # # configuration = { # :provider => 'openstack', @@ -150,12 +154,14 @@ def initialize(opts={}) end # - # Authenticates against the auth_service request class declared in the session's - # configuration during initialization. Please see Session.new for more information + # Authenticates against the backend provider using the auth_service request class + # declared in the session's configuration. Please see Session.new for more information # on declaring the request class to use for authentication. # - # If the auth_service request class accepts a parameter block, you may also supply that - # when calling this method and it will be directly passed to the request. For example: + # Request params block + # + # If the auth_service request class accepts parameters, you may supply that + # as a block and it will be directly passed to the request. For example: # # session = Aviator::Session.new(:config => config) # session.authenticate do |params| @@ -164,9 +170,12 @@ def initialize(opts={}) # params.tenant_name = project # end # - # Expects an HTTP status 200 or 201. Any other status is treated as a failure. + # If your configuration happens to have an auth_credentials in it, those + # will be overridden by this block. # - # Note that you can also treat the block's argument like a hash with the attribute + # Treat parameters as a hash + # + # You can also treat the params struct like a hash with the attribute # names as the keys. For example, we can rewrite the above as: # # session = Aviator::Session.new(:config => config) @@ -178,7 +187,29 @@ def initialize(opts={}) # # Keys can be symbols or strings. # - def authenticate(&block) + # Use a hash argument instead of a block + # + # You may also provide request params as an argument instead of a block. This is + # especially useful if you want to mock Aviator as it's easier to specify ordinary + # argument expectations over blocks. Further rewriting the example above, + # we end up with: + # + # session = Aviator::Session.new(:config => config) + # session.authenticate :params => { + # :username => username, + # :password => password, + # :tenant_name => project + # } + # + # If both :params and a block are provided, the :params + # values will be used and the block ignored. + # + # Success requirements + # + # Expects an HTTP status 200 or 201 response from the backend. Any other + # status is treated as a failure. + # + def authenticate(opts={}, &block) block ||= lambda do |params| config[:auth_credentials].each do |key, value| begin @@ -189,7 +220,7 @@ def authenticate(&block) end end - response = auth_service.request config[:auth_service][:request].to_sym, &block + response = auth_service.request(config[:auth_service][:request].to_sym, opts, &block) if [200, 201].include? response.status @auth_response = Hashish.new({ @@ -204,7 +235,10 @@ def authenticate(&block) end # - # Returns true if the session has been authenticated. + # Returns true if the session has been authenticated. Note that this relies on + # cached response from a previous run of Session#authenticate if one was made. + # If you want to check against the backend provider if the session is still valid, + # use Session#validate instead. # def authenticated? !auth_response.nil? @@ -247,7 +281,7 @@ def load(session_dump) end - def method_missing(name, *args, &block) + def method_missing(name, *args, &block) # :nodoc: service_name_parts = name.to_s.match(/^(\w+)_service$/) if service_name_parts @@ -262,7 +296,8 @@ def method_missing(name, *args, &block) # Creates a new Session object from a previous session's dump. See Session#dump for # more information. # - # If you want the newly deserialized session to log its output, make sure to indicate it on load + # If you want the newly deserialized session to log its output, add a :log_file + # option. # # Aviator::Session.load(session_dump_str, :log_file => 'path/to/aviator.log') # @@ -301,37 +336,77 @@ def log_file # # Keys can be symbols or strings. # + # You may also provide parameters as an argument instead of a block. This is + # especially useful when mocking Aviator as it's easier to specify ordinary + # argument expectations over blocks. Further rewriting the example above, + # we end up with: + # + # session.request :compute_service, :create_server, :params => { + # :name => "My Server", + # :image_ref => "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29", + # :flavor_ref => "fa283da1-59a5-4245-8569-b6eadf69f10b" + # } + # + # If both :params and a block are provided, the values in :params + # will be used and the block ignored. + # + # Return Value + # + # The return value will be an instance of Hashish, a lightweight replacement for + # activesupport's HashWithIndifferentAccess, with the following structure: + # + # { + # :status => 200, + # :headers => { + # 'X-Auth-Token' => 'd9186f45ce5446eaa0adc9def1c46f5f', + # 'Content-Type' => 'application/json' + # }, + # :body => { + # :some_key => :some_value + # } + # } + # + # Note that the members in :headers and :body will vary depending + # on the provider and the request that was made. + # # --- # # Request Options # - # You can further customize how the request is fulfilled by providing one or more - # options to the method call. For example, the following ensures that the request - # will call the :create_server request for the v1 API. + # You can further customize how the method behaves by providing one or more + # options to the call. For example, assuming you are using the openstack + # provider, the following will call the :create_server request of the + # v1 API of :compute_service. # - # session.request :compute_service, :create_server, :api_version => v1 + # session.request :compute_service, :create_server, :api_version => v1, :params => params # # The available options vary depending on the provider. See the documentation - # on the provider's Provider class for more information (e.g. Aviator::OpenStack::Provider) + # on the provider's Provider class for more information (e.g. Aviator::Openstack::Provider) # - def request(service_name, request_name, opts={}, ¶ms) + def request(service_name, request_name, opts={}, &block) service = send("#{service_name.to_s}_service") - service.request(request_name, opts, ¶ms) + response = service.request(request_name, opts, &block) + response.to_hash end # - # Returns true if the session is still valid in the underlying provider. This method does this - # by calling the validator request class declared declared under auth_service in the + # Returns true if the session is still valid in the underlying provider. This method calls + # the validator request class declared under auth_service in the # configuration. The validator can be any request class as long as: # # * The request class exists! + # * Is not an anonymous request. Otherwise it will always return true. # * Does not require any parameters # * It returns an HTTP status 200 or 203 to indicate auth info validity. # * It returns any other HTTP status to indicate that the auth info is invalid. # # See Session::new for an example on how to specify the request class to use for session validation. # + # Note that this method requires the session to be previously authenticated otherwise a + # NotAuthenticatedError will be raised. If you just want to check if the session was previously + # authenticated, use Session#authenticated? instead. + # def validate raise NotAuthenticatedError.new unless authenticated? raise ValidatorNotDefinedError.new unless config[:auth_service][:validator] diff --git a/lib/puppet/feature/aviator/openstack/identity/requests/v3/public/create_token.rb b/lib/puppet/feature/aviator/openstack/identity/requests/v3/public/create_token.rb index 12f66a10f..17d8bb078 100644 --- a/lib/puppet/feature/aviator/openstack/identity/requests/v3/public/create_token.rb +++ b/lib/puppet/feature/aviator/openstack/identity/requests/v3/public/create_token.rb @@ -1,7 +1,6 @@ -# Original work by Stephen Paul Suarez -# https://github.com/musashi-dev/aviator/blob/develop/lib/aviator/openstack/identity/v3/public/create_token.rb - module Aviator + # Original work by Stephen Paul Suarez + # https://github.com/musashi-dev/aviator/blob/develop/lib/aviator/openstack/identity/v3/public/create_token.rb define_request :create_token, :inherit => [:openstack, :common, :v3, :public, :base] do diff --git a/lib/puppet/feature/aviator/openstack/provider.rb b/lib/puppet/feature/aviator/openstack/provider.rb index 17fd0cbf7..a4c64e806 100644 --- a/lib/puppet/feature/aviator/openstack/provider.rb +++ b/lib/puppet/feature/aviator/openstack/provider.rb @@ -1,13 +1,6 @@ module Aviator module Openstack - # - # Manages a provider (e.g. OpenStack) session. - # - # Author:: Mark Maglana (mmaglana@gmail.com) - # Copyright:: Copyright (c) 2014 Mark Maglana - # License:: Distributed under the MIT license - # Homepage:: http://aviator.github.io/www/ # # Request Options # @@ -16,10 +9,10 @@ module Openstack # # :api_version => :v2:: # Forces Aviator to use the request class for the v2 API. For any other - # version, replace Note that this may throw an error if no such request - # class exists. If you want to globally specify the API version to use for - # a specific service, declare it in your config file under the correct - # environment. For example: + # version, replace :v2 with the desired one. Note that this may throw an + # error if no such request class for the given api version exists. If you + # want to globally specify the API version to use for a specific service, + # declare it in your config file under the correct environment. For example: # # production: # provider: openstack diff --git a/lib/puppet/feature/aviator/version.rb b/lib/puppet/feature/aviator/version.rb index 231ac0afa..faa1543f9 100644 --- a/lib/puppet/feature/aviator/version.rb +++ b/lib/puppet/feature/aviator/version.rb @@ -1,3 +1,3 @@ module Aviator - VERSION = "0.1.0" + VERSION = "0.2.1" end