class Aviator::Session

Manages a provider (e.g. OpenStack) session and serves as the entry point for a consumer class/object. See ::new for notes on usage.

Public Class Methods

load(session_dump, opts={}) click to toggle source

Creates a new Session object from a previous session's dump. See #dump for more information.

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')
# File lib/aviator/core/session.rb, line 304
def self.load(session_dump, opts={})
  opts[:session_dump] = session_dump

  new(opts)
end
new(opts={}) click to toggle source

Create a new Session instance.

Initialize with a config file

Aviator::Session.new(:config_file => 'path/to/aviator.yml', :environment => :production)

In the above example, the config file must have the following form:

production:
  provider: openstack
  auth_service:
    name: identity
    host_uri: 'http://my.openstackenv.org:5000'
    request: create_token
    validator: list_tenants
    api_version: v2
  auth_credentials:
    username: myusername
    password: mypassword
    tenant_name: myproject

SIDENOTE: For more information about the validator member, see #validate.

Once the session has been instantiated, you may authenticate against the provider as follows:

session.authenticate

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]
  params.password    = ARGV[1]
  params.tenant_name = ARGV[2]
end

See #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 between environments is as simple as changing the :environment to refer to that.

Initialize with an in-memory hash

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',
  :auth_service => {
    :name      => 'identity',
    :host_uri  => 'http://devstack:5000/v2.0',
    :request   => 'create_token',
    :validator => 'list_tenants'
  }
}

Supply this to the initializer using the :config option. For example:

Aviator::Session.new(:config => configuration)

Initialize with a session dump

You can create a new Session instance using a dump from another instance. For example:

session_dump = session1.dump
session2 = Aviator::Session.new(:session_dump => session_dump)

However, #load is cleaner and recommended over this method.

Optionally supply a log file

In all forms above, you may optionally add a :log_file option to make Aviator write all HTTP calls to the given path. For example:

Aviator::Session.new(:config_file => 'path/to/aviator.yml', :environment => :production, :log_file => 'path/to/log')
# File lib/aviator/core/session.rb, line 142
def initialize(opts={})
  if opts.has_key? :session_dump
    initialize_with_dump(opts[:session_dump])
  elsif opts.has_key? :config_file
    initialize_with_config(opts[:config_file], opts[:environment])
  elsif opts.has_key? :config
    initialize_with_hash(opts[:config])
  else
    raise InitializationError.new
  end

  @log_file = opts[:log_file]
end

Public Instance Methods

authenticate(opts={}, &block) click to toggle source

Authenticates against the backend provider using the auth_service request class declared in the session's configuration. Please see ::new for more information on declaring the request class to use for authentication.

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|
  params.username    = username
  params.password    = password
  params.tenant_name = project
end

If your configuration happens to have an auth_credentials in it, those will be overridden by this block.

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)
session.authenticate do |params|
  params[:username]    = username
  params[:password]    = password
  params[:tenant_name] = project
end

Keys can be symbols or strings.

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.

# File lib/aviator/core/session.rb, line 212
def authenticate(opts={}, &block)
  block ||= lambda do |params|
    config[:auth_credentials].each do |key, value|
      begin
        params[key] = value
      rescue NameError => e
        raise NameError.new("Unknown param name '#{key}'")
      end
    end
  end

  response = auth_service.request(config[:auth_service][:request].to_sym, opts, &block)

  if [200, 201].include? response.status
    @auth_response = Hashish.new({
      :headers => response.headers,
      :body    => response.body
    })
    update_services_session_data
  else
    raise AuthenticationError.new(response.body)
  end
  self
end
authenticated?() click to toggle source

Returns true if the session has been authenticated. Note that this relies on cached response from a previous run of #authenticate if one was made. If you want to check against the backend provider if the session is still valid, use #validate instead.

# File lib/aviator/core/session.rb, line 243
def authenticated?
  !auth_response.nil?
end
config() click to toggle source

Returns its configuration.

# File lib/aviator/core/session.rb, line 250
def config
  @config
end
dump() click to toggle source

Returns a JSON string of its configuration and auth_data. This string can be streamed or stored and later re-loaded in another Session instance. For example:

session = Aviator::Session.new(:config => configuration)
str = session.dump

# time passes...

session = Aviator::Session.load(str)
# File lib/aviator/core/session.rb, line 265
def dump
  JSON.generate({
    :config        => config,
    :auth_response => auth_response
  })
end
load(session_dump) click to toggle source

Same as ::load but re-uses the Session instance this method is called on instead of creating a new one.

# File lib/aviator/core/session.rb, line 277
def load(session_dump)
  initialize_with_dump(session_dump)
  update_services_session_data
  self
end
log_file() click to toggle source

Returns the log file path. May be nil if none was provided during initialization.

# File lib/aviator/core/session.rb, line 314
def log_file
  @log_file
end
request(service_name, request_name, opts={}, &block) click to toggle source

Calls the given request of the given service. An example call might look like:

session.request :compute_service, :create_server do |p|
  p.name       = "My Server"
  p.image_ref  = "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29"
  p.flavor_ref = "fa283da1-59a5-4245-8569-b6eadf69f10b"
end

Note that you can also treat the block's argument like a hash with the attribute names as the keys. For example, we can rewrite the above as:

session.request :compute_service, :create_server do |p|
  p[:name]       = "My Server"
  p[:image_ref]  = "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29"
  p[:flavor_ref] = "fa283da1-59a5-4245-8569-b6eadf69f10b"
end

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 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, :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)

# File lib/aviator/core/session.rb, line 386
def request(service_name, request_name, opts={}, &block)
  service = send("#{service_name.to_s}_service")
  response = service.request(request_name, opts, &block)
  response.to_hash
end
validate() click to toggle source

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 ::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 #authenticated? instead.

# File lib/aviator/core/session.rb, line 410
def validate
  raise NotAuthenticatedError.new unless authenticated?
  raise ValidatorNotDefinedError.new unless config[:auth_service][:validator]

  auth_with_bootstrap = auth_response.merge({ :auth_service  => config[:auth_service] })

  response = auth_service.request config[:auth_service][:validator].to_sym, :session_data => auth_with_bootstrap
  response.status == 200 || response.status == 203
end