diff --git a/server/libexec/config/environment.rb b/server/libexec/config/environment.rb index ae62985..8ac7a89 100644 --- a/server/libexec/config/environment.rb +++ b/server/libexec/config/environment.rb @@ -104,4 +104,6 @@ case DRIVER DRIVER_CLASS_NAME = "Deltacloud::Drivers::RHEVM::RHEVMDriver" when :rimu DRIVER_CLASS_NAME = "Deltacloud::Drivers::Rimu::RimuHostingDriver" + when :gogrid + DRIVER_CLASS_NAME = "Deltacloud::Drivers::Gogrid::GogridDriver" end diff --git a/server/libexec/lib/deltacloud/drivers/gogrid/gogrid_driver.rb b/server/libexec/lib/deltacloud/drivers/gogrid/gogrid_driver.rb new file mode 100644 index 0000000..72cbe4c --- /dev/null +++ b/server/libexec/lib/deltacloud/drivers/gogrid/gogrid_driver.rb @@ -0,0 +1,227 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +require 'deltacloud/base_driver' +require 'right_gogrid' + +module Deltacloud + module Drivers + module Gogrid + +class GogridDriver < Deltacloud::BaseDriver + + # Storage capacity is same on all machines (10gb), it could be extended using 'Cloud Storage' + define_hardware_profile('server-with-512mb-ram') do + cpu 2 + memory 0.5 + storage 10 + architecture 'i386' + end + + define_hardware_profile('server-with-1gb-ram') do + cpu 2 + memory 1 + storage 10 + architecture 'i386' + end + + define_hardware_profile('server-with-2gb-ram') do + cpu 2 + memory 2 + storage 10 + architecture 'i386' + end + + define_hardware_profile('server-with-4gb-ram') do + cpu 2 + memory 4 + storage 10 + architecture 'i386' + end + + define_hardware_profile('server-with-8gb-ram') do + cpu 2 + memory 8 + storage 10 + architecture 'i386' + end + + # The only valid option for flavors is server RAM for now + def flavors(credentials, opts=nil) + results = [] + safely do + gg=new_client(credentials) + results = gg.list_common_lookup('server.ram').collect do |sr| + Flavor.new(:id => sr['description'].downcase.tr(' ', '-'), :memory => sr['name'], :architecture => 'i386') + end + end + return results if ( opts.nil? ) + results = filter_on( results, :id, opts ) + results = filter_on( results, :architecture, opts ) + results + end + + def images(credentials, opts=nil) + images = [] + safely do + gg=new_client(credentials) + images = gg.list_images.collect { |image| convert_image(image, credentials[:name]) } + end + images = filter_on( images, :architecture, opts ) + images.sort_by{|e| [e.owner_id,e.description]} + end + + # gogrid doesn't supports realm yet (it's US/CA from whois) + def realms(credentials, opts=nil) + [Realm.new({ + :id => "us", + :name => "United States", + :state => "AVAILABLE" + } )] + end + + # Name consist from credentials name and timestamp + # + def create_instance(credentials, image_id, opts=nil) + flavor_id =(opts && opts[:flavor_id]) ? opts[:flavor_id] : 'server-with-512mb-ram' + # TODO: Fix naming here (IDEA: add 'name' to instance model) + name = 'Node '+Time.now.to_i.to_s + safely do + grid = new_client(credentials) + flavor = flavors(credentials).select { |f| f.id.eql?(flavor_id) }.first + image = images(credentials).select { |i| i.id.eql?(image_id) }.first + return convert_srv_to_instance(grid.add_server(name, image.name, flavor.memory, get_free_ip(credentials), image.description), flavor_id) + end + end + + def instances(credentials, opts=nil) + safely do + gg = new_client(credentials) + instances = gg.list_servers.collect { |server| convert_srv_to_instance(server, convert_ram_to_flavor(server['ram']['name']))} + instances = filter_on( instances, :id, opts ) + return instances + end + end + + def reboot_instance(credentials, id) + safely do + gg = new_client(credentials) + return gg.gogrid_power_server(:power => 'restart', :name => id) + end + end + + def stop_instance(credentials, id) + safely do + gg = new_client(credentials) + return gg.gogrid_power_server(:power => 'off', :name => id) + end + end + + def destroy_instance(credentials, id) + safely do + gg = new_client(credentials) + gg.gogrid_delete_server(:name => id) + end + end + + + define_instance_states do + start.to( :off ) .on( :create ) + pending.to( :on ) .automatically + running.to( :off ) .on( :reboot ) + running.to( :off ) .on( :stop ) + shutting_down.to( :off ) .automatically + stopped.to( :off ) .automatically + end + + private + + def convert_image(gg_image, owner_id=nil) + Image.new( { + :id=>gg_image['id'], + :name => gg_image['name'], + :description=>gg_image['friendlyName'], + :owner_id=>owner_id, + :architecture=>convert_arch(gg_image['description']), + } ) + end + + def new_client(credentials) + if ( credentials[:name].nil? || credentials[:password].nil? || credentials[:name] == '' || credentials[:password] == '' ) + raise Deltacloud::AuthException.new + end + Rightscale::Gogrid.new(credentials[:name], credentials[:password]) + end + + # Determine architecture from description + def convert_arch(description) + return 'x86_64' if description.include?('64-bit') + return 'i386' + end + + # NOTE: GoGrid doesn't use an ID for your instances. Instead they using a 'friendly name' + def convert_srv_to_instance(srv, flavor_id) + server = srv.kind_of?(Hash) ? srv : srv.first + Instance.new({ + :id => server['name'], + :state => server['state']['name'], + :name => server['description'], + :image_id => server['image']['id'], + :owner_id => 'root', + :realm => 'us', + :public_addresses => server['ip']['ip'], + :private_addresses => nil, + :flavor_id => flavor_id, + :actions => instance_actions_for(server['state']['name']) + }) + end + + # We produce flavors from RAM + def convert_ram_to_flavor(ram) + 'server-with-'+ram.downcase+'-ram' + end + + # You need a free IP from subnet you have assigned in case you want to start an instance + def get_free_ip(credentials) + gg=new_client(credentials) + # TODO: I'm not sure about this, they changed API recently and right_gogrid doesn't work well there + ip=gg.list_ips('Unassigned').select {|i| i['public'] }.last + return ip['ip'] if ip and ip['ip'] + return nil + end + + def safely(&block) + begin + block.call + rescue Rightscale::GogridError => e + if ( e.include?( /Forbidden/ ) ) + raise Deltacloud::AuthException.new + else + e.errors.each do |error| + puts "ERROR #{error.inspect}" + end + end + end + end + +end + + end + end +end + + diff --git a/server/libexec/lib/deltacloud/drivers/gogrid/gogrid_test.rb b/server/libexec/lib/deltacloud/drivers/gogrid/gogrid_test.rb new file mode 100644 index 0000000..c31b559 --- /dev/null +++ b/server/libexec/lib/deltacloud/drivers/gogrid/gogrid_test.rb @@ -0,0 +1,76 @@ +require 'config/environment' +require 'lib/deltacloud/drivers/gogrid/gogrid_driver' + +require 'test/unit' + +CREDS = { :name => '', :password => '' } + + +class GoGridTest < Test::Unit::TestCase + + def test_valid_flavors + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + assert_kind_of Array, gd.flavors(CREDS) + assert_kind_of Flavor, gd.flavors(CREDS).first + end + + def test_valid_images + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + assert_kind_of Array, gd.images(CREDS) + assert_kind_of Image, gd.images(CREDS).first + end + + def test_create_instance + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + images = gd.images(CREDS) + assert_kind_of Array, images + instance = gd.create_instance(CREDS, images.first.id) + assert_kind_of Instance, instance + end + + def test_list_instances + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + instances = gd.instances(CREDS) + assert_kind_of Array, instances + assert_kind_of Instance, instances.first + end + + def test_get_instance + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + instances = gd.instances(CREDS) + if instances.kind_of?(Array) + assert_kind_of Instance, gd.instance(CREDS, { :id => instances.first.id }) + end + end + + def test_list_realms + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + assert_kind_of Array, gd.realms(CREDS) + assert_kind_of Realm, gd.realms(CREDS).first + end + + # This tests fails anyway, because created instance isn't ready for it. + # If you want to really test, if these actions work properly, you could create an instance + # first and change instances.last.id to ID of your instance. In this way tests will work. + + def test_reboot_instance + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + instances = gd.instances(CREDS) + assert_kind_of Hash, gd.reboot_instance(CREDS, instances.last.id) + end + + def test_stop_instance + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + instances = gd.instances(CREDS) + assert_kind_of Hash, gd.stop_instance(CREDS, instances.last.id) + end + + def test_destroy_instance + gd=Deltacloud::Drivers::Gogrid::GogridDriver.new + instances = gd.instances(CREDS) + assert_kind_of Hash, gd.destroy_instance(CREDS, instances.last.id) + end + + + +end -- 1.6.5.2