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/11/08 12:38:21 UTC
Support for load_balancer collection
Hi,
I found some unpushed load_balancer patch from Aug/2010, so I revamped
it to work with latest core.
So what are basicly load balancers ? It's simple, you create an load_balancer
object, set port for this object and then set port for instance objects.
After you create load_balancer, you can assign multiple instances into this
object and all traffic will be routed through this load balancer.
There are more articles about Amazon Elastic Load Balancing:
http://aws.amazon.com/elasticloadbalancing/
GoGrid also offer their F5 load balancers, more reading here:
http://wiki.gogrid.com/wiki/index.php/API:Load_Balancer_%28Object%29
http://wiki.gogrid.com/wiki/index.php/Network_Devices#f5
-- Michal
[PATCH core 2/4] Added support for load_balancer collection
Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>
---
server/lib/deltacloud/base_driver/features.rb | 8 ++
.../lib/deltacloud/helpers/application_helper.rb | 4 +-
server/public/javascripts/application.js | 12 +++
server/server.rb | 76 ++++++++++++++++++++
server/views/instances/new.html.haml | 8 ++
server/views/load_balancers/index.html.haml | 33 +++++++++
server/views/load_balancers/index.xml.haml | 5 ++
server/views/load_balancers/new.html.haml | 38 ++++++++++
server/views/load_balancers/show.html.haml | 37 ++++++++++
server/views/load_balancers/show.xml.haml | 21 ++++++
10 files changed, 240 insertions(+), 2 deletions(-)
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.html.haml
create mode 100644 server/views/load_balancers/show.xml.haml
diff --git a/server/lib/deltacloud/base_driver/features.rb b/server/lib/deltacloud/base_driver/features.rb
index 3b19ca2..2d79f4b 100644
--- a/server/lib/deltacloud/base_driver/features.rb
+++ b/server/lib/deltacloud/base_driver/features.rb
@@ -169,5 +169,13 @@ module Deltacloud
param :location, :string, :optional
end
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/helpers/application_helper.rb b/server/lib/deltacloud/helpers/application_helper.rb
index 189148c..00e8bc9 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_name = :instances)
+ not driver.features(collection_name).select{ |f| f.name.eql?(feature_name) }.empty?
end
def driver_has_auth_features?
diff --git a/server/public/javascripts/application.js b/server/public/javascripts/application.js
index 80e1d1c..509768b 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?state=RUNNING&format=json",
+ 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 b8720a9..7044cd1 100644
--- a/server/server.rb
+++ b/server/server.rb
@@ -175,11 +175,87 @@ 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
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
+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 :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
+
+ 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
+
+
collection :instances do
description <<END
An instance is a concrete machine realized from an image.
diff --git a/server/views/instances/new.html.haml b/server/views/instances/new.html.haml
index 6d67c2d..558582d 100644
--- a/server/views/instances/new.html.haml
+++ b/server/views/instances/new.html.haml
@@ -9,6 +9,14 @@
%label
Instance Name:
%input{ :name => 'name', :size => 30 }/
+ -if driver_has_feature?(:register_to_load_balancer)
+ %p
+ %label
+ Assign to load balancer:
+ %select{:name => 'load_balancer_id'}
+ %option{:value => ""}
+ - @load_balancers.each do |load_balancer|
+ %option{:value => load_balancer.id} #{load_balancer.id}
-if driver_has_feature?(:authentication_key)
%p
%label
diff --git a/server/views/load_balancers/index.html.haml b/server/views/load_balancers/index.html.haml
new file mode 100644
index 0000000..65b109c
--- /dev/null
+++ b/server/views/load_balancers/index.html.haml
@@ -0,0 +1,33 @@
+%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..561caa4
--- /dev/null
+++ b/server/views/load_balancers/new.html.haml
@@ -0,0 +1,38 @@
+%h1 New Load Balancer
+
+%form{ :action => '/api/load_balancers', :method => :post }
+ %p
+ %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} - #{realm.name}
+ %hr
+ %p
+ %label
+ Protocol:
+ %select{ :name => 'listener_protocol'}
+ %option{ :value => 'HTTP'} HTTP
+ %option{ :value => 'TCP'} TCP
+ %p
+ %label
+ Load balancer port:
+ %input{ :name => "listener_lbr_port", :size => 30}
+ %p
+ %label
+ 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
new file mode 100644
index 0000000..7b6f40b
--- /dev/null
+++ b/server/views/load_balancers/show.html.haml
@@ -0,0 +1,37 @@
+%h1
+ = @load_balancer.id
+
+%dl
+ %di
+ %dt Public addresses
+ %dd
+ = @load_balancer.public_addresses.join(',')
+ - if @load_balancer.created_at
+ %dt Created at
+ %dd
+ = @load_balancer.created_at
+ %dt Realms
+ %dd
+ = @load_balancer.realms.collect { |r| "#{r.id} - #{r.name}" }.join(',')
+ %dt Listeners
+ %dd
+ - @load_balancer.listeners.each do |listener|
+ ="Load balancer port: #{listener.load_balancer_port}"
+ %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 Add instances to 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
new file mode 100644
index 0000000..e36f79f
--- /dev/null
+++ b/server/views/load_balancers/show.xml.haml
@@ -0,0 +1,21 @@
+- 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}
+ %link{:rel => "unregister", :href => unregister_load_balancer_url(@load_balancer.id, { :instance_id => instance.id})}
+
--
1.7.3.2
Re: Support for load_balancer collection
Posted by Michal Fojtik <mf...@redhat.com>.
On 08/11/10 12:38 +0100, mfojtik@redhat.com wrote:
>Hi,
>
>I found some unpushed load_balancer patch from Aug/2010, so I revamped
>it to work with latest core.
>
>So what are basicly load balancers ? It's simple, you create an load_balancer
>object, set port for this object and then set port for instance objects.
>After you create load_balancer, you can assign multiple instances into this
>object and all traffic will be routed through this load balancer.
>
>There are more articles about Amazon Elastic Load Balancing:
>http://aws.amazon.com/elasticloadbalancing/
>
>GoGrid also offer their F5 load balancers, more reading here:
>http://wiki.gogrid.com/wiki/index.php/API:Load_Balancer_%28Object%29
>http://wiki.gogrid.com/wiki/index.php/Network_Devices#f5
>
Damn, send-email screwed up something. Sending all patches again.
-- Michal
--
--------------------------------------------------------
Michal Fojtik, mfojtik@redhat.com
Deltacloud API: http://deltacloud.org
--------------------------------------------------------
[PATCH core 3/3] Added XML and HTML representation of 405 error code
Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>
---
server/views/errors/not_allowed.html.haml | 6 ++++++
server/views/errors/not_allowed.xml.haml | 2 ++
2 files changed, 8 insertions(+), 0 deletions(-)
create mode 100644 server/views/errors/not_allowed.html.haml
create mode 100644 server/views/errors/not_allowed.xml.haml
diff --git a/server/views/errors/not_allowed.html.haml b/server/views/errors/not_allowed.html.haml
new file mode 100644
index 0000000..59e9fe9
--- /dev/null
+++ b/server/views/errors/not_allowed.html.haml
@@ -0,0 +1,6 @@
+%h1 Method Not Allowed
+
+%dl
+ %di
+ %dt Request URL
+ %dd= request.env['REQUEST_URI']
diff --git a/server/views/errors/not_allowed.xml.haml b/server/views/errors/not_allowed.xml.haml
new file mode 100644
index 0000000..3bad335
--- /dev/null
+++ b/server/views/errors/not_allowed.xml.haml
@@ -0,0 +1,2 @@
+%error{:url => "#{request.env['REQUEST_URI']}", :status => "#{response.status}"}
+ %message Method not allowed for this resource
--
1.7.2.3
[PATCH core 1/4] Added LoadBalancer object
Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>
---
server/deltacloud.rb | 1 +
server/lib/deltacloud/models/load_balancer.rb | 39 +++++++++++++++++++++++++
2 files changed, 40 insertions(+), 0 deletions(-)
create mode 100644 server/lib/deltacloud/models/load_balancer.rb
diff --git a/server/deltacloud.rb b/server/deltacloud.rb
index 82e5780..02d6c2e 100644
--- a/server/deltacloud.rb
+++ b/server/deltacloud.rb
@@ -15,6 +15,7 @@ require 'deltacloud/models/storage_snapshot'
require 'deltacloud/models/storage_volume'
require 'deltacloud/models/bucket'
require 'deltacloud/models/blob'
+require 'deltacloud/models/load_balancer'
require 'deltacloud/validation'
require 'deltacloud/helpers'
diff --git a/server/lib/deltacloud/models/load_balancer.rb b/server/lib/deltacloud/models/load_balancer.rb
new file mode 100644
index 0000000..546a25f
--- /dev/null
+++ b/server/lib/deltacloud/models/load_balancer.rb
@@ -0,0 +1,39 @@
+#
+# 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
+
--
1.7.3.2
[PATCH core 4/4] Added support for F5 load_balancer collection in GoGrid
Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>
---
.../lib/deltacloud/drivers/gogrid/gogrid_client.rb | 11 +-
.../lib/deltacloud/drivers/gogrid/gogrid_driver.rb | 119 +++++++++++++++++++-
2 files changed, 120 insertions(+), 10 deletions(-)
diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_client.rb b/server/lib/deltacloud/drivers/gogrid/gogrid_client.rb
index c37f061..c463fa6 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}
@@ -35,12 +35,9 @@ class GoGridClient
@default_params['v'] = version
else
@default_params['v'] = '1.5'
- end
- begin
- JSON::parse(sendAPIRequest(method, params))
- rescue Exception => e
- STDERR.puts("ERROR: #{e.message}")
- end
+ 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 0e25530..fd8e756 100644
--- a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
+++ b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
@@ -45,7 +45,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)
@@ -176,6 +176,88 @@ class GogridDriver < Deltacloud::BaseDriver
end
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
+
+
+ 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
+
+ # Move this to capabilities
+ def lb_unregister_instance(credentials, opts={})
+ raise Deltacloud::BackendFeatureUnsupported.new('501',
+ 'Unregistering instances from load balancer is not supported in GoGrid')
+ end
+
+
+
def key(credentials, opts=nil)
keys(credentials, opts).first
end
@@ -213,8 +295,39 @@ 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)
login_data = {}
@@ -316,11 +429,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']
--
1.7.3.2
[PATCH core 1/3] Added 405 HTTP code when calling invalid instance action
Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>
---
.../lib/deltacloud/helpers/application_helper.rb | 8 ++++++++
server/lib/deltacloud/models/instance.rb | 20 +++++++++++++++-----
2 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/server/lib/deltacloud/helpers/application_helper.rb b/server/lib/deltacloud/helpers/application_helper.rb
index c7fa481..189148c 100644
--- a/server/lib/deltacloud/helpers/application_helper.rb
+++ b/server/lib/deltacloud/helpers/application_helper.rb
@@ -102,6 +102,14 @@ module ApplicationHelper
end
def instance_action(name)
+ original_instance = driver.instance(credentials, :id => params[:id])
+
+ # If original instance doesn't include called action
+ # return with 405 error (Method is not Allowed)
+ unless driver.instance_actions_for(original_instance.state).include?(name.to_sym)
+ return report_error(405, 'not_allowed')
+ end
+
@instance = driver.send(:"#{name}_instance", credentials, params["id"])
return redirect(instances_url) if name.eql?(:destroy) or @instance.class!=Instance
diff --git a/server/lib/deltacloud/models/instance.rb b/server/lib/deltacloud/models/instance.rb
index 9cf69b8..0167331 100644
--- a/server/lib/deltacloud/models/instance.rb
+++ b/server/lib/deltacloud/models/instance.rb
@@ -29,10 +29,20 @@ class Instance < BaseModel
attr_accessor :private_addresses
attr_accessor :instance_profile
attr_accessor :launch_time
- def initialize(init=nil)
- super(init)
- self.actions = [] if self.actions.nil?
- self.public_addresses = [] if self.public_addresses.nil?
- self.private_addresses = [] if self.private_addresses.nil?
+
+ def initialize(init=nil)
+ super(init)
+ self.actions = [] if self.actions.nil?
+ self.public_addresses = [] if self.public_addresses.nil?
+ self.private_addresses = [] if self.private_addresses.nil?
end
+
+ def method_missing(name, *args)
+ if name =~ /is_(\w+)\?/
+ return true if self.state.downcase.eql?($1)
+ else
+ raise NoMethodError
+ end
+ end
+
end
--
1.7.2.3
[PATCH core 2/3] Fix Mock driver speed in case you have a lot of YAML files
Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>
---
server/lib/deltacloud/drivers/mock/mock_driver.rb | 13 ++++++++++++-
1 files changed, 12 insertions(+), 1 deletions(-)
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb b/server/lib/deltacloud/drivers/mock/mock_driver.rb
index 847319b..52c63b7 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb
@@ -130,12 +130,23 @@ class MockDriver < Deltacloud::BaseDriver
#
# Instances
#
+ require 'ruby-prof'
+
+ def instance(credentials, opts={})
+ check_credentials( credentials )
+ instance_filename = File.join(@storage_root, 'instances', "#{opts[:id]}.yml")
+ return nil unless File.exists?(instance_filename)
+ instance = YAML::load_file(instance_filename)
+ instance[:actions] = instance_actions_for( instance[:state] )
+ instance[:id] = File::basename(instance_filename, ".yml")
+ Instance.new(instance)
+ end
def instances(credentials, opts=nil)
check_credentials( credentials )
instances = []
Dir[ "#{@storage_root}/instances/*.yml" ].each do |instance_file|
- instance = YAML.load( File.read( instance_file ) )
+ instance = YAML::load_file(instance_file)
if ( instance[:owner_id] == credentials.user )
instance[:id] = File.basename( instance_file, ".yml" )
instance[:actions] = instance_actions_for( instance[:state] )
--
1.7.2.3
[PATCH core 3/4] Implemented Load Balancers to EC2 driver
Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>
---
server/lib/deltacloud/drivers/ec2/ec2_driver.rb | 112 ++++++++++++++++++++++-
1 files changed, 108 insertions(+), 4 deletions(-)
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index 9b37069..9003b6d 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -38,13 +38,14 @@ module Deltacloud
class EC2Driver < Deltacloud::BaseDriver
def supported_collections
- DEFAULT_COLLECTIONS + [ :keys, :buckets ]
+ DEFAULT_COLLECTIONS + [ :keys, :buckets, :load_balancers ]
end
feature :instances, :user_data
feature :instances, :authentication_key
feature :images, :owner_id
feature :buckets, :bucket_location
+ feature :instances, :register_to_load_balancer
define_hardware_profile('m1.small') do
cpu 1
@@ -194,7 +195,15 @@ class EC2Driver < Deltacloud::BaseDriver
:disable_api_termination => false,
:instance_initiated_shutdown_behavior => 'terminate'
)
- return convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
+ new_instance = convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
+ if opts[:load_balancer_id] and opts[:load_balancer_id]!=""
+ elb = new_client(credentials, :elb)
+ elb.register_instances_with_load_balancer({
+ :instances => [new_instance.id],
+ :load_balancer_name => opts[:load_balancer_id]
+ })
+ end
+ return new_instance
end
end
@@ -402,19 +411,114 @@ 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
+
+ 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)
+ def new_client(credentials, provider_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 provider_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 if loadbalancer.Instances
+ balancer
end
+
def convert_key(key)
Key.new({
:id => key['keyName'],
--
1.7.3.2