You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by mf...@redhat.com on 2010/08/10 17:26:15 UTC
Load balancers (rev2)
Hi,
This patch add Load Balancing support for GoGrid and also
fixes some minor issues with load balancing under EC2.
There are still some issues with GoGrid driver. I get almost all
functionality to be same in both drivers.
For GoGrid there is some difficulties with additing Instances to LB.
In GoGrid you don't assign an Instance to Load Balancer but instead
you use IP address of Instance you want to assign.
So to match functionality with EC2 I need to lookup for instances
which have IP address I want to assign.
At this point everything is working. Trouble starts when I want
to assign more instances to one load balancer.
When you use their 'realips.N.ip' variable in 'grid/loadbalancer/edit',
you need to increate number (N) in that list to assign more instances.
Unfortunatelly when you do this, you need to wait at least 2-3 minutes
for next API request. So I asked GoGrid support and response was:
"For each request through API needs at least 2-3 minute intervals"
So long story short: Load balancing for GoGrid is working, but it's limited
by this 'sad' thing.
-- Michal
PS: In both GoGrid and Amazon, Load balancers are free to use, so anyone ca try
this patch, without starting 'real' instances. (except you want to test instance assign :)
[PATCH core 2/2] Load Balancers for GoGrid (rev 1)
Posted by mf...@redhat.com.
---
server/lib/deltacloud/drivers/ec2/ec2_driver.rb | 22 ++++-
.../lib/deltacloud/drivers/gogrid/gogrid_client.rb | 9 +-
.../lib/deltacloud/drivers/gogrid/gogrid_driver.rb | 116 +++++++++++++++++++-
server/lib/deltacloud/drivers/gogrid/test.rb | 13 --
.../lib/deltacloud/helpers/application_helper.rb | 4 +-
server/lib/deltacloud/helpers/conversion_helper.rb | 6 +-
server/lib/deltacloud/models/base_model.rb | 2 +-
server/public/javascripts/application.js | 12 ++
server/server.rb | 21 ++++
server/views/load_balancers/new.html.haml | 16 ++-
server/views/load_balancers/show.html.haml | 23 +++-
server/views/load_balancers/show.xml.haml | 1 +
12 files changed, 207 insertions(+), 38 deletions(-)
delete mode 100644 server/lib/deltacloud/drivers/gogrid/test.rb
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index d15a198..aba42b1 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -190,7 +190,7 @@ class EC2Driver < Deltacloud::BaseDriver
:instance_initiated_shutdown_behavior => 'terminate'
)
instance = convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
- if opts[:load_balancer_id]
+ if opts[:load_balancer_id] and opts[:load_balancer_id]!=""
elb = new_client(credentials, :elb)
elb.register_instances_with_load_balancer({
:instances => [instance.id],
@@ -365,6 +365,24 @@ class EC2Driver < Deltacloud::BaseDriver
end
end
+ def lb_register_instance(credentials, opts={})
+ ec2 = new_client( credentials, :elb)
+ safely do
+ ec2.register_instances_with_load_balancer(:instances => [opts[:instance_id]],
+ :load_balancer_name => opts[:id])
+ load_balancer(credentials, :id => opts[:id])
+ end
+ end
+
+ def lb_unregister_instance(credentials, opts={})
+ ec2 = new_client( credentials, :elb)
+ safely do
+ ec2.deregister_instances_from_load_balancer(:instances => [opts[:instance_id]],
+ :load_balancer_name => opts[:id])
+ load_balancer(credentials, :id => opts[:id])
+ end
+ end
+
private
def new_client(credentials, type = :ec2)
@@ -404,7 +422,7 @@ class EC2Driver < Deltacloud::BaseDriver
end
loadbalancer.Instances.member.each do |instance|
balancer.instances << instances(credentials, :id => instance['InstanceId']).first
- end
+ end if loadbalancer.Instances
balancer
end
diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_client.rb b/server/lib/deltacloud/drivers/gogrid/gogrid_client.rb
index c37f061..5492170 100644
--- a/server/lib/deltacloud/drivers/gogrid/gogrid_client.rb
+++ b/server/lib/deltacloud/drivers/gogrid/gogrid_client.rb
@@ -9,7 +9,7 @@ class GoGridClient
apikey='YOUR API KEY',
secret='YOUR SHARED SECRET',
format='json',
- version='1.5')
+ version='1.6')
@server = server
@secret = secret
@default_params = {'format'=>format, 'v'=>version,'api_key' => apikey}
@@ -36,11 +36,8 @@ class GoGridClient
else
@default_params['v'] = '1.5'
end
- begin
- JSON::parse(sendAPIRequest(method, params))
- rescue Exception => e
- STDERR.puts("ERROR: #{e.message}")
- end
+ request = sendAPIRequest(method, params)
+ JSON::parse(request)
end
def encode_params(params)
diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
index e6c99c5..343102f 100644
--- a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
+++ b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
@@ -36,6 +36,7 @@ module Deltacloud
class GogridDriver < Deltacloud::BaseDriver
feature :instances, :authentication_password
+ feature :instances, :register_to_load_balancer
define_hardware_profile 'server' do
cpu 2
@@ -45,7 +46,7 @@ class GogridDriver < Deltacloud::BaseDriver
def supported_collections
DEFAULT_COLLECTIONS.reject! { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
- DEFAULT_COLLECTIONS + [ :keys ]
+ DEFAULT_COLLECTIONS + [ :keys, :load_balancers ]
end
def images(credentials, opts=nil)
@@ -107,6 +108,24 @@ class GogridDriver < Deltacloud::BaseDriver
end
end
+ def lb_register_instance(credentials, opts={})
+ client = new_client(credentials)
+ instance = instance(credentials, :id => opts[:instance_id])
+ balancer = client.request('grid/loadbalancer/get', { 'name' => opts[:id]})['list'].first
+ safely do
+ convert_load_balancer(credentials, client.request('grid/loadbalancer/edit', {
+ "id" => balancer['id'],
+ "realiplist.#{balancer['realiplist'].size}.ip" => instance.public_addresses.first,
+ "realiplist.#{balancer['realiplist'].size}.port" => balancer['virtualip']['port']
+ }))
+ end
+ end
+
+ def lb_unregister_instance(credentials, opts={})
+ raise Deltacloud::BackendFeatureUnsupported.new('501',
+ 'Unregistering instances from load balancer is not supported in GoGrid')
+ end
+
def list_instances(credentials, id)
instances = []
safely do
@@ -192,6 +211,67 @@ class GogridDriver < Deltacloud::BaseDriver
return creds
end
+
+ def create_load_balancer(credentials, opts={})
+ gogrid = new_client(credentials)
+ balancer, l_instance = nil, nil
+ safely do
+ virtip = get_free_ip_from_realm(credentials, opts['realm_id'])
+ if opts['instance_id']
+ l_instance = instance(credentials, :id => opts['instance_id'])
+ real_ip = {
+ 'realiplist.0.port' => opts['listener_inst_port'],
+ 'realiplist.0.ip' => l_instance ? l_instance.public_addresses.first : ""
+ }
+ else
+ real_ip = false
+ end
+ request = {
+ 'name' => opts['name'],
+ 'virtualip.ip' => virtip,
+ 'virtualip.port' => opts['listener_lbr_port'],
+ }
+ request.merge!(real_ip) if real_ip
+ balancer = gogrid.request('grid/loadbalancer/add', request)['list'].first
+ end
+ balancer = convert_load_balancer(credentials, balancer)
+ balancer.instances = [l_instance] if l_instance
+ balancer
+ end
+
+ def destroy_load_balancer(credentials, id)
+ gogrid = new_client(credentials)
+ balancer = nil
+ safely do
+ balancer = gogrid.request('grid/loadbalancer/delete', { 'name' => id })
+ balancer = load_balancer(credentials, :id => id) unless balancer
+ end
+ convert_load_balancer(credentials, balancer)
+ end
+
+ def load_balancers(credentials, opts={})
+ gogrid = new_client(credentials)
+ balancers = []
+ safely do
+ balancer = gogrid.request('grid/loadbalancer/list', opts || {})['list'].each do |balancer|
+ balancers << balancer
+ end
+ end
+ balancers.collect { |b| convert_load_balancer(credentials, b) }
+ end
+
+ def load_balancer(credentials, opts={})
+ gogrid = new_client(credentials)
+ balancer = nil
+ begin
+ balancer = gogrid.request('grid/loadbalancer/get', { 'name' => opts[:id] })['list'].first
+ balancer['instances'] = instances(credentials)
+ return convert_load_balancer(credentials, balancer)
+ rescue OpenURI::HTTPError
+ balancer = load_balancers(credentials, :id => opts[:id]).first
+ end
+ end
+
define_instance_states do
start.to( :pending ) .automatically
pending.to( :running ) .automatically
@@ -205,7 +285,37 @@ class GogridDriver < Deltacloud::BaseDriver
def new_client(credentials)
GoGridClient.new('https://api.gogrid.com/api', credentials.user, credentials.password)
+ end
+
+ def convert_load_balancer(credentials, loadbalancer)
+ if loadbalancer['datacenter']
+ b_realm = realm(credentials, :id => loadbalancer['datacenter']['id'])
+ else
+ # Report first Realm until loadbalancer become ready
+ b_realm = realm(credentials, :id => 1)
+ end
+ balancer = LoadBalancer.new({
+ :id => loadbalancer['name'],
+ :realms => [b_realm]
+ })
+ balancer.public_addresses = [loadbalancer['virtualip']['ip']['ip']] if loadbalancer['virtualip'] and loadbalancer['virtualip']['ip']
+ balancer.listeners = []
+ balancer.instances = []
+ instance_ips = []
+ loadbalancer['realiplist'].each do |instance_ip|
+ balancer.add_listener({
+ :protocol => 'TCP',
+ :load_balancer_port => loadbalancer['virtualip']['port'],
+ :instance_port => instance_ip['port']
+ })
+ instance_ips << instance_ip['ip']['ip']
+ end if loadbalancer['realiplist']
+ balancer.instances = get_load_balancer_instances(instance_ips, loadbalancer['instances'])
+ return balancer
+ end
+ def get_load_balancer_instances(instance_ips, instances)
+ instances.select { |i| instance_ips.include?(i.public_addresses.first) } if instances
end
def get_login_data(client, instance_id)
@@ -305,11 +415,11 @@ class GogridDriver < Deltacloud::BaseDriver
state.eql?('Off') ? 'STOPPED' : 'RUNNING'
end
- def get_free_ip_from_realm(credentials, realm_id)
+ def get_free_ip_from_realm(credentials, realm_id, ip_type=1)
ip = ""
safely do
ip = new_client(credentials).request('grid/ip/list', {
- 'ip.type' => '1',
+ 'ip.type' => ip_type,
'ip.state' => '1',
'datacenter' => realm_id
})['list'].first['ip']
diff --git a/server/lib/deltacloud/drivers/gogrid/test.rb b/server/lib/deltacloud/drivers/gogrid/test.rb
deleted file mode 100644
index 809081d..0000000
--- a/server/lib/deltacloud/drivers/gogrid/test.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require 'gogrid_client'
-require 'ap'
-
-user='fbb1de3897597ccf'
-password='ngieth10'
-
-client=GoGridClient.new('https://api.gogrid.com/api', user, password)
-
-ap client.request('grid/ip/list', {
- 'ip.type' => '1',
- 'ip.state' => '1',
- 'datacenter' => '1'
-})
diff --git a/server/lib/deltacloud/helpers/application_helper.rb b/server/lib/deltacloud/helpers/application_helper.rb
index 9a9dfdc..ab96f0c 100644
--- a/server/lib/deltacloud/helpers/application_helper.rb
+++ b/server/lib/deltacloud/helpers/application_helper.rb
@@ -41,8 +41,8 @@ module ApplicationHelper
collections[:instances].operations[action.to_sym].method
end
- def driver_has_feature?(feature_name)
- not driver.features(:instances).select{ |f| f.name.eql?(feature_name) }.empty?
+ def driver_has_feature?(feature_name, collection=:instances)
+ not driver.features(collection).select{ |f| f.name.eql?(feature_name) }.empty?
end
def driver_has_auth_features?
diff --git a/server/lib/deltacloud/helpers/conversion_helper.rb b/server/lib/deltacloud/helpers/conversion_helper.rb
index e96f9b7..7b0c57e 100644
--- a/server/lib/deltacloud/helpers/conversion_helper.rb
+++ b/server/lib/deltacloud/helpers/conversion_helper.rb
@@ -22,17 +22,17 @@ require 'deltacloud/base_driver'
module ConversionHelper
def convert_to_json(type, obj)
- if ( [ :flavor, :account, :image, :realm, :instance, :storage_volume, :storage_snapshot, :hardware_profile ].include?( type ) )
+ if ( [ :account, :image, :realm, :instance, :storage_volume, :storage_snapshot, :hardware_profile ].include?( type ) )
if Array.eql?(obj.class)
data = obj.collect do |o|
- o.to_hash.merge({ :href => self.send(:"#{type}_url", type.eql?(:hardware_profile) ? o.name : o.id ) })
+ o.to_hash.merge({ :href => self.send(:"#{type}_url", type.eql?(:instance_profile) ? o.name : o.id ) })
end
type = type.to_s.pluralize
else
data = obj.to_hash
data.merge!({ :href => self.send(:"#{type}_url", data[:id]) })
end
- return { :"#{type}" => data }.to_json
+ return JSON.generate(Hash[{ :"#{type}" => data }], :allow_nan => true )
end
end
diff --git a/server/lib/deltacloud/models/base_model.rb b/server/lib/deltacloud/models/base_model.rb
index aa997a5..13c65d6 100644
--- a/server/lib/deltacloud/models/base_model.rb
+++ b/server/lib/deltacloud/models/base_model.rb
@@ -48,7 +48,7 @@ class BaseModel
def to_hash
out = {}
- self.attributes.each { |attribute| out.merge!({ attribute => self.send(:"#{attribute}") } ) }
+ self.attributes.each { |attribute| out.merge!({ attribute => self.send(:"#{attribute}").to_s } ) }
out
end
diff --git a/server/public/javascripts/application.js b/server/public/javascripts/application.js
index 80e1d1c..e2a2751 100644
--- a/server/public/javascripts/application.js
+++ b/server/public/javascripts/application.js
@@ -29,4 +29,16 @@ $(document).ready(function() {
return false;
})
+ if ($('select#list_instances').length) {
+ $('select#list_instances').html("<option>Loading instances...</option>");
+ $.getJSON("/api/instances.json?state=RUNNING",
+ function(data){
+ $('select#list_instances').empty();
+ $.each(data.instances, function(i,item){
+ $('select#list_instances').append('<option value="'+item.id+'">'+item.id+'</option>');
+ });
+ }
+ );
+ }
+
})
diff --git a/server/server.rb b/server/server.rb
index e0e8155..55791a9 100644
--- a/server/server.rb
+++ b/server/server.rb
@@ -358,6 +358,7 @@ end
get '/api/load_balancers/new' do
@realms = driver.realms(credentials)
+ @instances = driver.instances(credentials) if driver_has_feature?(:register_instance, :load_balancers)
respond_to do |format|
format.html { haml :"load_balancers/new" }
end
@@ -404,4 +405,24 @@ collection :load_balancers do
end
end
+ operation :register, :method => :post, :member => true do
+ description "Add instance to loadbalancer"
+ param :id, :string, :required
+ param :instance_id, :string, :required
+ control do
+ driver.lb_register_instance(credentials, params)
+ redirect(load_balancer_url(params[:id]))
+ end
+ end
+
+ operation :unregister, :method => :post, :member => true do
+ description "Remove instance from loadbalancer"
+ param :id, :string, :required
+ param :instance_id, :string, :required
+ control do
+ driver.lb_unregister_instance(credentials, params)
+ redirect(load_balancer_url(params[:id]))
+ end
+ end
+
end
diff --git a/server/views/load_balancers/new.html.haml b/server/views/load_balancers/new.html.haml
index 734dc44..3d734b1 100644
--- a/server/views/load_balancers/new.html.haml
+++ b/server/views/load_balancers/new.html.haml
@@ -5,25 +5,33 @@
%label
Name:
%input{ :name => 'name', :size => 30 }/
+ -if @instances
+ %p
+ %label
+ Running instance:
+ %select{ :name => 'instance_id'}
+ - @instances.select{|i| i.state=="RUNNING"}.each do |instance|
+ %option{ :value => instance.id } #{instance.id}
%p
%label
Realm:
%select{ :name => 'realm_id'}
- @realms.each do |realm|
- %option{ :value => realm.id } #{realm.id}
+ %option{ :value => realm.id } #{realm.id} - #{realm.name}
+ %hr
%p
%label
- Listener protocol:
+ Protocol:
%select{ :name => 'listener_protocol'}
%option{ :value => 'HTTP'} HTTP
%option{ :value => 'TCP'} TCP
%p
%label
- Listener load balancer port:
+ Load balancer port:
%input{ :name => "listener_lbr_port", :size => 30}
%p
%label
- Listener instance port:
+ Instances port:
%input{ :name => "listener_inst_port", :size => 30}
%p
%input{ :type => :submit, :name => "commit", :value => "create" }/
diff --git a/server/views/load_balancers/show.html.haml b/server/views/load_balancers/show.html.haml
index a8ceb87..615bd78 100644
--- a/server/views/load_balancers/show.html.haml
+++ b/server/views/load_balancers/show.html.haml
@@ -6,12 +6,13 @@
%dt Public addresses
%dd
= @load_balancer.public_addresses.join(',')
- %dt Created at
- %dd
- = @load_balancer.created_at
+ - if @load_balancer.created_at
+ %dt Created at
+ %dd
+ = @load_balancer.created_at
%dt Realms
%dd
- = @load_balancer.realms.collect { |r| r.id }.join(',')
+ = @load_balancer.realms.collect { |r| "#{r.id} - #{r.name}" }.join(',')
%dt Listeners
%dd
- @load_balancer.listeners.each do |listener|
@@ -19,3 +20,17 @@
%br
="Instance port: #{listener.instance_port}"
%br
+ - if @load_balancer.instances.class.eql?(Array)
+ %dt Instances
+ - @load_balancer.instances.each do |inst|
+ %dd
+ =inst.id
+ %a{:class => :post, :href => unregister_load_balancer_url(@load_balancer.id, :instance_id => inst.id)} Delete
+
+%form{:action => url_for("/api/load_balancers/#{@load_balancer.id}/register"), :method => :post}
+ %p
+ %strong Assign instance to this load balancer
+ %p
+ %label Instance
+ %select{:name => :instance_id, :id => "list_instances"}
+ %input{:type => :submit, :value => "Assign"}
diff --git a/server/views/load_balancers/show.xml.haml b/server/views/load_balancers/show.xml.haml
index c012699..1e50ff9 100644
--- a/server/views/load_balancers/show.xml.haml
+++ b/server/views/load_balancers/show.xml.haml
@@ -17,3 +17,4 @@
%instances
- @load_balancer.instances.each do |instance|
%instance{:href => instance_url(instance.id), :id => instance.id}
+ %link{:rel => "unregister", :href => unregister_load_balancer_url(@load_balancer.id, { :instance_id => instance.id})}
--
1.7.2
[PATCH core 1/2] Load Balancers for EC2 (rev 2)
Posted by mf...@redhat.com.
---
server/deltacloud.rb | 1 +
server/lib/deltacloud/base_driver/features.rb | 7 ++
server/lib/deltacloud/drivers/ec2/ec2_driver.rb | 95 +++++++++++++++++++++-
server/lib/deltacloud/models/load_balancer.rb | 38 +++++++++
server/server.rb | 53 +++++++++++++
server/views/instances/new.html.haml | 8 ++
server/views/load_balancers/index.html.haml | 32 ++++++++
server/views/load_balancers/index.xml.haml | 5 +
server/views/load_balancers/new.html.haml | 29 +++++++
server/views/load_balancers/show.html.haml | 21 +++++
server/views/load_balancers/show.xml.haml | 19 +++++
11 files changed, 303 insertions(+), 5 deletions(-)
create mode 100644 server/lib/deltacloud/models/load_balancer.rb
create mode 100644 server/views/load_balancers/index.html.haml
create mode 100644 server/views/load_balancers/index.xml.haml
create mode 100644 server/views/load_balancers/new.html.haml
create mode 100644 server/views/load_balancers/show.haml.haml
create mode 100644 server/views/load_balancers/show.html.haml
create mode 100644 server/views/load_balancers/show.xml.haml
diff --git a/server/deltacloud.rb b/server/deltacloud.rb
index 6799b2f..f6e9ada 100644
--- a/server/deltacloud.rb
+++ b/server/deltacloud.rb
@@ -10,6 +10,7 @@ require 'deltacloud/models/realm'
require 'deltacloud/models/image'
require 'deltacloud/models/instance'
require 'deltacloud/models/key'
+require 'deltacloud/models/load_balancer'
require 'deltacloud/models/instance_profile'
require 'deltacloud/models/storage_snapshot'
require 'deltacloud/models/storage_volume'
diff --git a/server/lib/deltacloud/base_driver/features.rb b/server/lib/deltacloud/base_driver/features.rb
index 3ed4085..c3fc3ba 100644
--- a/server/lib/deltacloud/base_driver/features.rb
+++ b/server/lib/deltacloud/base_driver/features.rb
@@ -162,5 +162,12 @@ module Deltacloud
description "Size instances according to changes to a hardware profile"
# The parameters are filled in from the hardware profiles
end
+
+ declare_feature :instances, :register_to_load_balancer do
+ description "Register instance to load balancer"
+ operation :create do
+ param :load_balancer_id, :string, :optional
+ end
+ end
end
end
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index 909eca3..d15a198 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -36,12 +36,13 @@ module Deltacloud
class EC2Driver < Deltacloud::BaseDriver
def supported_collections
- DEFAULT_COLLECTIONS + [ :keys ]
+ DEFAULT_COLLECTIONS + [ :keys, :load_balancers ]
end
feature :instances, :user_data
feature :instances, :authentication_key
feature :images, :owner_id
+ feature :instances, :register_to_load_balancer
define_hardware_profile('m1.small') do
cpu 1
@@ -188,7 +189,15 @@ class EC2Driver < Deltacloud::BaseDriver
:disable_api_termination => false,
:instance_initiated_shutdown_behavior => 'terminate'
)
- return convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
+ instance = convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
+ if opts[:load_balancer_id]
+ elb = new_client(credentials, :elb)
+ elb.register_instances_with_load_balancer({
+ :instances => [instance.id],
+ :load_balancer_name => opts[:load_balancer_id]
+ })
+ end
+ return instance
end
end
@@ -284,9 +293,9 @@ class EC2Driver < Deltacloud::BaseDriver
def keys(credentials, opts=nil)
ec2 = new_client( credentials )
opts[:key_name] = opts[:id] if opts and opts[:id]
- keypairs = ec2.describe_keypairs(opts || {})
result = []
safely do
+ keypairs = ec2.describe_keypairs(opts || {})
keypairs.keySet.item.each do |keypair|
result << convert_key(keypair)
end
@@ -310,17 +319,93 @@ class EC2Driver < Deltacloud::BaseDriver
end
end
+ def load_balancer(credentials, opts={})
+ load_balancers(credentials, {
+ :load_balancer_names => [opts[:id]]
+ }).first
+ end
+
+ def load_balancers(credentials, opts=nil)
+ ec2 = new_client( credentials, :elb )
+ result = []
+ safely do
+ loadbalancers = ec2.describe_load_balancers(opts || {})
+ return [] unless loadbalancers.DescribeLoadBalancersResult.LoadBalancerDescriptions
+ loadbalancers.DescribeLoadBalancersResult.LoadBalancerDescriptions.member.each do |loadbalancer|
+ result << convert_load_balancer(credentials, loadbalancer)
+ end
+ end
+ return result
+ end
+
+ def create_load_balancer(credentials, opts={})
+ ec2 = new_client( credentials, :elb )
+ safely do
+ ec2.create_load_balancer({
+ :load_balancer_name => opts['name'],
+ # TODO: Add possibility to push more listeners/realms in one request
+ # Something like 'Hash' in 'Array' parameter
+ :availability_zones => [opts['realm_id']],
+ :listeners => [{
+ :protocol => opts['listener_protocol'],
+ :load_balancer_port => opts['listener_lbr_port'],
+ :instance_port => opts['listener_inst_port']
+ }]
+ })
+ return load_balancer(credentials, opts['name'])
+ end
+ end
+
+ def destroy_load_balancer(credentials, id)
+ ec2 = new_client( credentials, :elb )
+ safely do
+ ec2.delete_load_balancer({
+ :load_balancer_name => id
+ })
+ end
+ end
+
private
- def new_client(credentials)
+ def new_client(credentials, type = :ec2)
opts = {
:access_key_id => credentials.user,
:secret_access_key => credentials.password
}
opts[:server] = ENV['DCLOUD_EC2_URL'] if ENV['DCLOUD_EC2_URL']
safely do
- AWS::EC2::Base.new(opts)
+ case type
+ when :ec2
+ AWS::EC2::Base.new(opts)
+ when :elb
+ AWS::ELB::Base.new(opts)
+ end
+ end
+ end
+
+ def convert_load_balancer(credentials, loadbalancer)
+ balancer_realms = loadbalancer.AvailabilityZones.member.collect do |m|
+ realm(credentials, m)
+ end
+ balancer = LoadBalancer.new({
+ :id => loadbalancer['LoadBalancerName'],
+ :created_at => loadbalancer['CreatedTime'],
+ :public_addresses => [loadbalancer['DNSName']],
+ :realms => balancer_realms
+ })
+ balancer.listeners = []
+ balancer.instances = []
+ loadbalancer.Listeners.member.each do |listener|
+ balancer.add_listener({
+ :protocol => listener['Protocol'],
+ :load_balancer_port => listener['LoadBalancerPort'],
+ :instance_port => listener['InstancePort']
+ })
+ end
+ loadbalancer.Instances.member.each do |instance|
+ balancer.instances << instances(credentials, :id => instance['InstanceId']).first
end
+ balancer
end
def convert_key(key)
diff --git a/server/lib/deltacloud/models/load_balancer.rb b/server/lib/deltacloud/models/load_balancer.rb
new file mode 100644
index 0000000..2900004
--- /dev/null
+++ b/server/lib/deltacloud/models/load_balancer.rb
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2009 Red Hat, Inc.
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class LoadBalancer < BaseModel
+
+ attr_accessor :realms
+ attr_accessor :listeners
+ attr_accessor :instances
+ attr_accessor :public_addresses
+ attr_accessor :created_at
+
+ def add_listener(opts)
+ @listeners << Listener.new(opts)
+ end
+
+ class Listener < BaseModel
+ attr_accessor :protocol
+ attr_accessor :load_balancer_port
+ attr_accessor :instance_port
+ end
+
+end
diff --git a/server/server.rb b/server/server.rb
index 1373fa3..e0e8155 100644
--- a/server/server.rb
+++ b/server/server.rb
@@ -155,6 +155,9 @@ get "/api/instances/new" do
@image = driver.image( credentials, :id => params[:image_id] )
@hardware_profiles = driver.hardware_profiles(credentials, :architecture => @image.architecture )
@realms = driver.realms(credentials)
+ if driver_has_feature?(:register_to_load_balancer)
+ @load_balancers = driver.load_balancers(credentials)
+ end
respond_to do |format|
format.html { haml :"instances/new" }
end
@@ -352,3 +355,53 @@ collection :keys do
end
end
+
+get '/api/load_balancers/new' do
+ @realms = driver.realms(credentials)
+ respond_to do |format|
+ format.html { haml :"load_balancers/new" }
+ end
+end
+
+collection :load_balancers do
+ description "Load balancers"
+
+ operation :index do
+ description "List of all active load balancers"
+ control do
+ filter_all :load_balancers
+ end
+ end
+
+ operation :show do
+ description "Show details about given load balancer"
+ param :id, :string, :required
+ control { show :load_balancer }
+ end
+
+ operation :create do
+ description "Create a new load balancer"
+ param :name, :string, :required
+ param :realm_id, :string, :required
+ param :listener_protocol, :string, :required, ['HTTP', 'TCP']
+ param :listener_lbr_port, :string, :required
+ param :listener_inst_port, :string, :required
+ control do
+ @load_balancer = driver.create_load_balancer(credentials, params)
+ respond_to do |format|
+ format.xml { haml :"load_balancers/show" }
+ format.html { haml :"load_balancers/show" }
+ end
+ end
+ end
+
+ operation :destroy do
+ description "Destroy given load balancer"
+ param :id, :string, :required
+ control do
+ driver.destroy_load_balancer(credentials, params[:id])
+ redirect(load_balancers_url)
+ end
+ end
+
+end
diff --git a/server/views/instances/new.html.haml b/server/views/instances/new.html.haml
index 6d67c2d..3547707 100644
--- a/server/views/instances/new.html.haml
+++ b/server/views/instances/new.html.haml
@@ -14,6 +14,14 @@
%label
Instance Keyname:
%input{:name => 'keyname', :size => 30 }
+ -if driver_has_feature?(:register_to_load_balancer)
+ %p
+ %label
+ Load Balancer:
+ %select{:name => 'load_balancer_id'}
+ %option{:value => ""}
+ - @load_balancers.each do |load_balancer|
+ %option{:value => load_balancer.id} #{load_balancer.id}
- if !@hardware_profiles.empty?
%h3 What size machine?
- for hwp in @hardware_profiles
diff --git a/server/views/load_balancers/index.html.haml b/server/views/load_balancers/index.html.haml
new file mode 100644
index 0000000..877ca07
--- /dev/null
+++ b/server/views/load_balancers/index.html.haml
@@ -0,0 +1,32 @@
+%h1 Load Balancers
+
+%table.display
+ %thead
+ %tr
+ %th ID
+ %th Hostname
+ %th Realm
+ %th Balancer port
+ %th Instances port
+ %th Actions
+ %tbody
+ - @elements.each do |balancer|
+ %tr
+ %td
+ = link_to balancer.id, load_balancer_url( balancer.id )
+ %td
+ = balancer.public_addresses.first
+ %td
+ = link_to balancer.realms.first.id, realm_url( balancer.realms.first.id )
+ %td
+ - balancer.listeners.each do |listener|
+ ="#{listener.protocol}[#{listener.load_balancer_port}]<br/>"
+ %td
+ - balancer.listeners.each do |listener|
+ ="#{listener.protocol}[#{listener.load_balancer_port}]<br/>"
+ %td
+ =link_to 'Destroy', destroy_load_balancer_url(balancer.id), :class => 'delete'
+ %tfoot
+ %tr
+ %td{:colspan => 6, :style => "text-align:right;"}
+ =link_to 'Create »', "#{url_for('/api/load_balancers/new')}", :class => 'button'
diff --git a/server/views/load_balancers/index.xml.haml b/server/views/load_balancers/index.xml.haml
new file mode 100644
index 0000000..22c6911
--- /dev/null
+++ b/server/views/load_balancers/index.xml.haml
@@ -0,0 +1,5 @@
+
+!!!XML
+%load_balancers
+ - @elements.each do |c|
+ = haml :'load_balancers/show', :locals => { :@load_balancer => c, :partial => true }
diff --git a/server/views/load_balancers/new.html.haml b/server/views/load_balancers/new.html.haml
new file mode 100644
index 0000000..734dc44
--- /dev/null
+++ b/server/views/load_balancers/new.html.haml
@@ -0,0 +1,29 @@
+%h1 New Load Balancer
+
+%form{ :action => '/api/load_balancers', :method => :post }
+ %p
+ %label
+ Name:
+ %input{ :name => 'name', :size => 30 }/
+ %p
+ %label
+ Realm:
+ %select{ :name => 'realm_id'}
+ - @realms.each do |realm|
+ %option{ :value => realm.id } #{realm.id}
+ %p
+ %label
+ Listener protocol:
+ %select{ :name => 'listener_protocol'}
+ %option{ :value => 'HTTP'} HTTP
+ %option{ :value => 'TCP'} TCP
+ %p
+ %label
+ Listener load balancer port:
+ %input{ :name => "listener_lbr_port", :size => 30}
+ %p
+ %label
+ Listener instance port:
+ %input{ :name => "listener_inst_port", :size => 30}
+ %p
+ %input{ :type => :submit, :name => "commit", :value => "create" }/
diff --git a/server/views/load_balancers/show.haml.haml b/server/views/load_balancers/show.haml.haml
new file mode 100644
index 0000000..e69de29
diff --git a/server/views/load_balancers/show.html.haml b/server/views/load_balancers/show.html.haml
new file mode 100644
index 0000000..a8ceb87
--- /dev/null
+++ b/server/views/load_balancers/show.html.haml
@@ -0,0 +1,21 @@
+%h1
+ = @load_balancer.id
+
+%dl
+ %di
+ %dt Public addresses
+ %dd
+ = @load_balancer.public_addresses.join(',')
+ %dt Created at
+ %dd
+ = @load_balancer.created_at
+ %dt Realms
+ %dd
+ = @load_balancer.realms.collect { |r| r.id }.join(',')
+ %dt Listeners
+ %dd
+ - @load_balancer.listeners.each do |listener|
+ ="Load balancer port: #{listener.load_balancer_port}"
+ %br
+ ="Instance port: #{listener.instance_port}"
+ %br
diff --git a/server/views/load_balancers/show.xml.haml b/server/views/load_balancers/show.xml.haml
new file mode 100644
index 0000000..c012699
--- /dev/null
+++ b/server/views/load_balancers/show.xml.haml
@@ -0,0 +1,19 @@
+- unless defined?(partial)
+ !!! XML
+%load_balancer{ :href => key_url(@load_balancer.id), :id => @load_balancer.id}
+ %actions
+ %link{ :rel => "destroy", :method => "delete", :href => destroy_load_balancer_url(@load_balancer.id)}
+ %public_addresses
+ - @load_balancer.public_addresses.each do |address|
+ %address #{address}
+ %created_at<
+ = @load_balancer.created_at
+ %realm{ :href => realm_url(@load_balancer.realms.first.id), :id => @load_balancer.realms.first.id}
+ %listeners
+ - @load_balancer.listeners.each do |listener|
+ %listener{ :protocol => listener.protocol}
+ %load_balancer_port #{listener.load_balancer_port}
+ %instance_port #{listener.instance_port}
+ %instances
+ - @load_balancer.instances.each do |instance|
+ %instance{:href => instance_url(instance.id), :id => instance.id}
--
1.7.2