openstack_activeresource
OpenStack Ruby and RoR bindings implemented with ActiveResource
Supported API:
-
Glance
-
Keystone (admin and public)
-
Nova
Tested on Folsom and Essex release.
Installation
Command line:
~# gem install openstack_activeresource
Or in bundler Gemfile:
gem "openstack_activeresource", "~> 0.6.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 => "[email protected]", :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
-
Check out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet.
-
Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it.
-
Fork the project.
-
Start a feature/bugfix branch.
-
Commit and push until you are happy with your contribution.
-
Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.
-
Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
Copyright
Copyright © 2012 Unidada S.p.A. (Davide Guerri - [email protected]). See LICENSE.txt for further details.