Fork me on GitHub

An elegantly designed OpenStack SDK for Ruby


require 'aviator'

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

session.authenticate

keystone = session.identity_service
response = keystone.request(:list_tenants)
puts response.body

Configure for multiple environments

The configuration file is a simple YAML file that can have one or more environment definitions.

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:
    token_id: 2c963f5512d067b24fdc312707c80c7a6d3d261b
    tenant_name: admin

development:
  provider: openstack
  auth_service:
    name: identity
    host_uri: 'http://devstack:5000/v2.0'
    request: create_token
    validator: list_tenants
  auth_credentials:
    username: myusername
    password: mypassword
    tenant_name: myproject

The auth_credentials in the config file are optional or can be overridden during authentication:

session.authenticate do |params|
  params.username    = 'myusername'
  params.password    = 'mypassword'
  params.tenant_name = 'mytenant'
end

Browse the available requests

Aviator comes with a handy dandy command line interface called describe that allows you to inspect the available requests in the library:

$ aviator describe openstack
Available services for openstack:
  compute
  identity
  image
  metering
  volume

$ aviator describe openstack compute
Available requests for openstack compute_service:
  v2 admin confirm_server_resize
  v2 admin get_host_details
  v2 admin list_hosts
  v2 admin resize_server
  v2 admin revert_server_resize
  v2 public change_admin_password
  v2 public create_image
  v2 public create_server
  ...

$ aviator describe openstack compute v2 public create_server
Request: create_server

Parameters:
 +-------------+----------+-------------+
 | NAME        | REQUIRED | ALIAS       |
 +-------------+----------+-------------+
 | accessIPv4  |    N     | access_ipv4 |
 | accessIPv6  |    N     | access_ipv6 |
 | adminPass   |    N     | admin_pass  |
 | flavorRef   |    Y     | flavor_ref  |
 | imageRef    |    Y     | image_ref   |
 | metadata    |    N     |             |
 | name        |    Y     |             |
 | networks    |    N     |             |
 | personality |    N     |             |
 +-------------+----------+-------------+

Sample Code:
  session.compute_service.request(:create_server) do |params|
    params.access_ipv4 = value
    params.access_ipv6 = value
    params.admin_pass = value
    params.metadata = value
    params.networks = value
    params.personality = value
    params.image_ref = value
    params.flavor_ref = value
    params.name = value
  end

Links:
  documentation:
    http://docs.openstack.org/api/openstack-compute/2/content/CreateServers.html

TIP: On OS X, command click on the link to open it in a browser.

...Or Read the Code Directly

We designed a DSL for the request definition files so that they are easy to read, easy to add to, and pretty much be self documenting (in fact, the same code is used by the describe CLI tool). For instance, here is the actual code for the create_server request:

define_request :create_server, inherit: [:openstack, :common, :v2, :public, :base] do

  meta :service, :compute

  link 'documentation',
       'http://docs.openstack.org/api/openstack-compute/2/content/CreateServers.html'

  param :accessIPv4,  required: false, alias: :access_ipv4
  param :accessIPv6,  required: false, alias: :access_ipv6
  param :adminPass,   required: false, alias: :admin_pass
  param :imageRef,    required: true,  alias: :image_ref
  param :flavorRef,   required: true,  alias: :flavor_ref
  param :metadata,    required: false
  param :name,        required: true
  param :networks,    required: false
  param :personality, required: false


  def body
    p = {
      server: {
        flavorRef: params[:flavorRef],
        imageRef:  params[:imageRef],
        name:      params[:name]
      }
    }

    [:adminPass, :metadata, :personality, :networks, :accessIPv4, :accessIPv6].each do |key|
      p[:server][key] = params[key] if params[key]
    end

    p
  end

  def headers
    super
  end

  def http_method
    :post
  end

  def url
    "#{ base_url }/servers"
  end

end

Browse the rest of the request files here.

Session Management API

Serialize the session information for caching. The output is in plaintext JSON which contains sensitive information. You are responsible for securing that.

str = session.dump

Creating a new Session object from a session dump is just as easy.

session = Aviator::Session.load(str)

This DOES NOT create a new token in the backend. If you employed any form of encryption on the string, make sure to decrypt it first!

Depending on how old the loaded session dump is, its session data may already be expired. Check if it's still current by calling Session#validate and reauthenticate as needed.

session.authenticate unless session.validate

IMPORTANT: The validator must be defined in the config file and it must refer to the name of a request that is known to Aviator (list_tenants usually will do). See the configuration example above.

If you want the newly deserialized session to log its output, make sure to indicate it on load

session = Aviator::Session.load(
            session_dump_str, 
            log_file: 'path/to/aviator.log'
          )

Need a way to persist session dumps? Give Aviator::SessionPool a try!


Install It Now!

Add this line to your application's Gemfile:

gem 'aviator'

Or if you want to live on the edge:

gem 'aviator', :git => 'git@github.com:aviator/aviator.git', :branch => 'master'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install aviator

Need Some Samples?

Check out the demo project for a quick sampling of how you can use Aviator.


Good to Know

In some instances, Session::load is inefficient because it creates a new session object each time. If object re-use is important to you, use Session#load (instance method, as opposed to class method). This will 'infect' an already existing session object with the supplied session dump and return itself instead of creating a brand new session object.

session.load(other_session_dump)

You can choose to be explicit about the endpoint type. Useful in those rare instances when the same request name means differently depending on the endpoint type. For example, in OpenStack, :list_tenants will return only the tenants the user is a member of in the public endpoint whereas the admin endpoint will return all tenants in the system.

response = keystone.request(:list_tenants, endpoint_type: 'admin')

In the configuration file, the validator can be any request name as long as:

  • It is defined in Aviator
  • 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.


Useful Links


Project Stats

Build Status Coverage Status Code Climate Gem Version Dependency Status