openstack_activeresource

OpenStack Ruby and RoR bindings implemented with ActiveResource

Supported API:

Tested on Folsom and Essex release.

Installation

Command line:

~# gem install openstack_activeresource

Or in bundler Gemfile:

gem "openstack_activeresource", "~> 0.7.1"

Sample usages

List available tenants (requires the ‘admin’ role)

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "adminuser", :password => "adminpassword", :tenant_id => "admintenant_ID"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

OpenStack::Keystone::Public::Tenant.all.each { |tenant|
    printf "Name: %s (id: %s, enabled? %s) - %s\n",
        tenant.name.center(15), tenant.id.center(20), tenant.enabled.to_s.center(6), tenant.description
}

Creating a new tenant and a new user (requires the ‘admin’ role)

require 'openstack_activeresource'

# Set Keystone Public and Admin API endpoints
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"
OpenStack::Keystone::Admin::Base.site = "https://my.keystone.api.server:35357/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "adminuser", :password => "adminpassword", :tenant_id => "admintenant_ID"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Create a new tenant
new_tenant = OpenStack::Keystone::Admin::Tenant.create :enabled => true, :name => "TestTenant", :description => "My new tenant" 

# Create a new user in new_tenant
new_user = OpenStack::Keystone::Admin::User.create :tenant => new_tenant, :name => "TestUser", :password => "testpassword", :email => "test@user.com", :enabled => true

# Assign the "memberRole" in new_tenant to new_user
member_role = OpenStack::Keystone::Admin::Role.find_by_name "memberRole"
new_tenant.add_role_to_user member_role, new_user

Image index from Nova

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Compute API endpoint from the received service catalog
OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL

OpenStack::Nova::Compute::Image.all.each { |image|
  printf "Name: %s (%s), minDisk: %3i, minRam: %5i, Status: %s, Progress: %3i\n",
         image.name.center(40),
         image.image_type.center(8),
         image.min_disk || 0,
         image.min_ram || 0,
         image.status(7),
         image.progress
}

List virtual servers for a tenant

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Compute API endpoint from the received service catalog
OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL

# Get all the servers
servers = OpenStack::Nova::Compute::Server.all

# To get only active server: OpenStack::Compute::Server.find :all, :params => {:status => "ACTIVE"}

servers.each { |s|
  printf "Name: %s, Status: %s, Image: %s, Flavor: %s, Created: %s, Updated: %s\n",
         s.name.center(20),
         s.status.center(10),
         (s.image.name rescue 'not found').center(40),
         (s.flavor.name rescue 'not found').center(40),
         s.created_at.to_time.localtime,
         s.updated_at.to_time.localtime
}

List available flavors

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Compute API endpoint from the received service catalog
OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL

# Get available flavors
flavors = OpenStack::Nova::Compute::Flavor.all

flavors.each { |f|
  printf "Name: %s, Id: %s, Ram: %5i, Disk: %3i (Ephemeral: %3i), vCPU: %2i\n", f.name.center(15), f.id.center(20), f.ram, f.disk, f.ephemeral_disk, f.vcpus
}

# Get flavors that meet the given constraints
flavors = OpenStack::Nova::Compute::Flavor.find_by_constraints( :ram => 2048, :vcpus => 4, :disk => 20 )

flavors.each { |f|
  printf "Name: %s, Id: %s, Ram: %5i, Disk: %3i (Ephemeral: %3i), vCPU: %2i\n", f.name.center(15), f.id.center(20), f.ram, f.disk, f.ephemeral_disk, f.vcpus
}

# Get available flavors that can be used for a given image
flavors = OpenStack::Nova::Compute::Flavor.applicable_for_image( OpenStack::Nova::Compute::Image.all.last )

flavors.each { |f|
  printf "Name: %s, Id: %s, Ram: %5i, Disk: %3i (Ephemeral: %3i), vCPU: %2i\n", f.name.center(15), f.id.center(20), f.ram, f.disk, f.ephemeral_disk, f.vcpus
}

Create a flavor (requires ‘admin’ role)

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "adminuser", :password => "adminpassword", :tenant_id => "admintenant_ID"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Compute API endpoint from the received service catalog
OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL

# Create a flavor
flavors = OpenStack::Nova::Compute::Flavor.create :name => 'my_new_flavor', :ram => 1024, :disk => 20, :ephemeral_disk => 0

List available security groups

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Compute API endpoint from the received service catalog
OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL

# Get available security groups
security_groups = OpenStack::Nova::Compute::SecurityGroup.all

security_groups.each { |sg|
  printf "Name: %s, Description: %s\n", sg.name.center(20), sg.description.center(50)

  sg.rules.each { |r|
    printf "Protocol: %s, From port: %5i, To port: %5i, Addresses: %s\n",
           r.ip_protocol.center(4),
           r.from_port,
           r.to_port,
           r.cidr.present? ? r.cidr.center(18) : ''.center(18)
  }
  puts "\n"
}

List available Floating IPs

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Compute API endpoint from the received service catalog
OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL

# Get available floating IPs
floatings = OpenStack::Nova::Compute::FloatingIp.all

floatings.each { |floating|
  printf "IP: %s, Fixed IP: %s, Pool: %s, Instance: %s (%s)\n",
         floating.ip.center(20),
         floating.fixed_ip.present? ? floating.fixed_ip.center(20) : "".center(20),
         floating.pool.center(20),
         floating.instance_id.present? ? floating.instance_id.center(40) : "".center(40),
         floating.instance.present? ? floating.instance.name.center(15) : "".center(15)

}

Start a new virtual server and play with it

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Compute API endpoint from the received service catalog
OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL

# Generate a new keypair
new_keypair = OpenStack::Nova::Compute::KeyPair.create :name => 'my_new_keypair'

# Prints out keypair info (!)
printf "Public key: %s\nPrivate key: %s\nKeypair Fingerprint: %s\n",
    new_keypair.public_key,
    new_keypair.private_key,
    new_keypair.fingerprint

# Start a new virtual server
new_server = OpenStack::Nova::Compute::Server.create(
    :name => 'my_new_server',
    :flavor => OpenStack::Nova::Compute::Flavor.find_by_name('m1.tiny'),
    :image => OpenStack::Nova::Compute::Image.find_by_name('Ubuntu Server 12.04 LTS amd64')
    :key_pair => new_keypair,
    :security_groups => OpenStack::Nova::Compute::SecurityGroup.all
)

# ... time passes...
sleep 5
# ... time passes...
new_server.refresh_status!
# Get server status
puts new_server.status

# Pause/unpause the server
new_server.pause
# ... time passes...
sleep 5
# ... time passes...
new_server.unpause

# Suspend/resume the server
new_server.suspend
# ... time passes...
sleep 5
# ... time passes...
new_server.resume

# Reboot the server
# new_server.reboot(:type => [:soft|:hard]) default :hard
new_server.reboot

# Get the server console output (last 10 row, default 50)
puts new_server.console_output(10)

# Get the server noVNC console URL
puts new_server.vnc_console

# ...code for floating IP retrieval... save the floating IP in my_floating_IP
# Add a floating IP to the server
new_server.add_floating_ip my_floating_IP

# ...code for volume retrieval... save the volume in my_volume
# Attach a volume to new_server
new_server.attach_volume! my_volume, '/dev/vdb'

List available volumes

require 'openstack_activeresource'

# Set Keystone Public API endpoint
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "user", :password => "password", :tenant_id => "tenant_id"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Volume API endpoint from the received service catalog
OpenStack::Nova::Volume::Base.site = auth.endpoint_for('volume').publicURL

# Get available volumes
volumes = OpenStack::Nova::Volume::Volume.all

volumes.each { |volume|
  printf "Name: %s, Status: %s\n", volume.display_name.center(20), volume.status.center(50)
}

Simple tenant usage (requires ‘admin’ role)

require 'openstack_activeresource'

# Set Keystone Public and Admin API endpoints
OpenStack::Keystone::Public::Base.site = "https://my.keystone.api.server:5000/v2.0/"

# Authentication
auth = OpenStack::Keystone::Public::Auth.create :username => "adminuser", :password => "adminpassword", :tenant_id => "admintenant_ID"

# Set the auth token for next API requests
OpenStack::Base.token = auth.token

# Set the Nova Compute API endpoint from the received service catalog
OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL

# Get the tenant
tenant = OpenStack::Keystone::Admin::Tenant.find_by_name "the_tenant"

# Get usage for a single tenant
simple_usage = OpenStack::Nova::Compute::SimpleTenantUsage.find tenant.id, :params => {:start => '1998-07-29T00:00:01', :end => '2012-07-09T00:00:00'}
# Or:
#past_month_start = (DateTime.now - 1.month).at_beginning_of_month
#past_month_end = (DateTime.now - 1.month).at_end_of_month
#simple_usage = OpenStack::Nova::Compute::SimpleTenantUsage.find_between_dates tenant.id, past_month_start, past_month_end

# get usage for all tenants
simple_usages = OpenStack::Nova::Compute::SimpleTenantUsage.find_from_date(:all, days.days.ago)

simple_usages.each { |usage|
  printf "Tenant: %s, Total hours: %3.3f, Total memory: %8.3f, Total vcpus: %4.3f, Total disk: %5.3f\n",
         usage.tenant_id.center(30),
         usage.total_hours,
         usage.total_memory_mb_usage,
         usage.total_vcpus_usage,
         usage.total_local_gb_usage

  usage.server_usages.each { |su|
    printf "\tName: %s, state: %s, vCPU: %2i, RAM: %5i, Disk: %3i, Started: %31s, Ended: %31s, Hours: %10.5f\n",
           su.name.center(15),
           su.state.center(15),
           su.vcpus,
           su.memory_mb,
           su.local_gb,
           su.started_at.to_time.localtime,
           su.ended_at.nil? ? '' : su.ended_at.to_time.localtime,
           su.hours
  }
  puts "\n"
}

Using OpenStack-ActiveResource with Ruby on Rails (sample usage)

Create an helper method in your application controller

class ApplicationController < ActionController::Base

    ...

    private

    def require_openstack_login
      if OpenStack::Base.token.nil? or OpenStack::Base.token.expired?
        OpenStack::Keystone::Public::Base.site = <keystone_public_api_uri>
        # Admin API, if needed
        OpenStack::Keystone::Admin::Base.site = <keystone_admin_api_uri>

        auth = OpenStack::Keystone::Public::Auth.create :username => <username>, :password => <password>, :tenant_id => <tenant_id>

        OpenStack::Base.token = auth.token

        OpenStack::Nova::Compute::Base.site = auth.endpoint_for('compute').publicURL
        # Set other endpoints if needed ...
        # For instance:
        #   OpenStack::Nova::Volume::Base.site = auth.endpoint_for('volume').publicURL

      end
    end

    ...

end

In controllers which need to access the openstack API,

class OpenStackConsumerController < ApplicationController

    ...

    # "Enable" openstack API only in methods where it is needed
    before_filter :require_openstack_login, :only => [ :index, :show ]

    ...

end

Contributing to openstack_activeresource

Copyright © 2012 Unidada S.p.A. (Davide Guerri - d.guerri@unidata.it). See LICENSE.txt for further details.