From: marios <marios(a)redhat.com>
---
server/lib/deltacloud/drivers/ec2/ec2_driver.rb | 92 ++++++++++++++++-
.../drivers/terremark/terremark_driver.rb | 112 ++++++++++++++++++--
2 files changed, 195 insertions(+), 9 deletions(-)
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index 076bfc4..6ced942 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -36,6 +36,7 @@ class EC2Driver < Deltacloud::BaseDriver
feature :instances, :user_data
feature :instances, :authentication_key
+ feature :access_rules, :show
define_hardware_profile('m1.small') do
cpu 1
@@ -230,7 +231,6 @@ class EC2Driver < Deltacloud::BaseDriver
#
# Storage Snapshots
#
-
def storage_snapshots(credentials, opts=nil)
ec2 = new_client( credentials )
snapshots = []
@@ -250,6 +250,70 @@ class EC2Driver < Deltacloud::BaseDriver
snapshots
end
+#--
+# ACCESS RULES
+#--
+ def access_rules(credentials, opts={})
+ rules = []
+ ec2 = new_client(credentials)
+ ec2.describe_security_groups().securityGroupInfo.item.each do |group|
+ group_name = group['groupName']
+ unless group.ipPermissions.nil?
+ group.ipPermissions.item.each do |rule|
+ if rule['ipRanges'] #i.e. with cidr address - not interested in
access to groups
+ protocol = rule['ipProtocol']
+ port_start = rule['fromPort']
+ port_end = rule['toPort']
+ ports = (protocol.downcase == 'icmp') ? '' : ((port_start
== port_end) ? port_start : "#{port_start}-#{port_end}")
+ id = "#{group_name}_#{protocol}:#{ports}"
+ rules << AccessRule.new({ :id => id,
+ :port => ports,
+ :protocol => protocol,
+ :instance_group => group_name
+ })
+ end #if
+ end #ipPermissions.item.each do
+ end #unless
+ end #securityGroupInfo.item.each do
+ rules
+ end
+
+#--
+# CREATE_ACCESS_RULE
+#--
+ def create_access_rule(credentials, opts={})
+ #at minimum can expect: opts['protocol'] and opts['port']
+ ec2 = new_client(credentials)
+ protocol = opts['protocol'].downcase
+ icmp = (protocol.downcase == 'icmp') #if icmp, ports should be -1
+ port = (icmp ? '-1' : opts['port'])
+ instance_group = opts['instance_group']
+ cidr_ip = '0.0.0.0/0' #open to all
+ opts = { :ip_protocol => protocol, :from_port => port,
+ :to_port => port, :cidr_ip => cidr_ip, :group_name =>
instance_group }
+ ec2.authorize_security_group_ingress(opts)
+ end
+
+#--
+# DELETE_ACCESS_RULE
+#--
+ def delete_access_rule(credentials, opts={})
+ ec2 = new_client(credentials)
+ #opts['id'] eg "default_tcp:22"
+ instance_group = opts[:id].to_s.split("_").first
+ protocol = opts[:id].to_s.split("_").last.split(":").first
+ icmp = (protocol.downcase == 'icmp') #if icmp, ports should be -1
+ port = (icmp ? '-1' :
opts[:id].to_s.split("_").last.split(":").last)
+ options = { :group_name => instance_group,
+ :ip_protocol => protocol,
+ :from_port => port,
+ :to_port => port,
+ :cidr_ip => "0.0.0.0/0",
+ }
+ ec2.revoke_security_group_ingress(options)
+ end
+
+
private
def new_client(credentials)
@@ -338,3 +402,29 @@ end
end
end
end
+
+
+#(13:15:54) mfojtik_: i'll write a notes about features here, because it will look
messy on channel ;-)
+#(13:16:41) mfojtik_: so first of all you need to define a new feature in
"lib/deltacloud/base_driver/features.rb"
+#(13:16:55) mfojtik_: fir example:
+#(13:16:56) mfojtik_: declare_feature :instances, :authentication_password do
+#(13:16:56) mfojtik_: operation :create do
+#(13:16:56) mfojtik_: param :password, :string, :optional
+#(13:16:56) mfojtik_: end
+#(13:16:58) mfojtik_: end
+#(13:17:32) mfojtik_: so now, this feature is accessible to all drivers
+#(13:17:47) mfojtik_: then you open ec2_driver and declare that feature here:
+#(13:17:49) mfojtik_: feature :instances, :authentication_key
+#(13:18:39) mfojtik_: that's all, now this feature will be advertised in /api
+#(13:18:46) marios: great... thats very cool
+#(13:18:56) mfojtik_: then next, if you want add a new fields into Instance class
+#(13:19:06) mfojtik_: you can do this in driver:
+#(13:19:14) mfojtik_: class Instance attr_accessor :keyname attr_accessor :authn_error
+#(13:19:16) mfojtik_: err.
+#(13:19:19) mfojtik_: again:
+#(13:19:21) mfojtik_: class Instance
+#(13:19:29) mfojtik_: attr_accessor :security_group
+#(13:19:30) mfojtik_: end
+
+
+
diff --git a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
index ae3c554..fe27eb3 100644
--- a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
+++ b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
@@ -32,8 +32,8 @@ module Deltacloud
class TerremarkDriver < Deltacloud::BaseDriver
- feature :instances, :user_name
-
+feature :instances, :user_name
+feature :access_rules, :show
#--
# Vapp State Map... for use with convert_instance (get an integer back from terremark)
#--
@@ -95,7 +95,7 @@ VAPP_STATE_MAP = { "0" => "PENDING",
"1" => "PENDING", "2" => "STOPPED",
"4"
if(current_item['type'] ==
'application/vnd.vmware.vcloud.vApp+xml')
vapp_id = current_item['href'].split('/').last
vapp = terremark_client.get_vapp(vapp_id)
- instances << convert_instance(vapp, terremark_client,
credentials.user)
+ instances << convert_instance(vapp, terremark_client,
{'account_name' => credentials.user})
end
}#end vdc_items.each
instances = filter_on( instances, :id, opts )
@@ -140,7 +140,7 @@ VAPP_STATE_MAP = { "0" => "PENDING",
"1" => "PENDING", "2" => "STOPPED",
"4"
#######
vapp_id = terremark_client.instantiate_vapp_template(name, image_id,
vapp_opts).body['href'].split('/').last
new_vapp = terremark_client.get_vapp(vapp_id)
- return convert_instance(new_vapp, terremark_client, credentials.user) #return an
Instance object
+ return convert_instance(new_vapp, terremark_client, {'account_name' =>
credentials.user}) #return an Instance object
end
#--
@@ -148,15 +148,19 @@ VAPP_STATE_MAP = { "0" => "PENDING",
"1" => "PENDING", "2" => "STOPPED",
"4"
#--
def reboot_instance(credentials, id)
terremark_client = new_client(credentials)
+ vapp = terremark_client.get_vapp(id)
terremark_client.power_reset(id)
+ return convert_instance(vapp, terremark_client, {'vapp_status' =>
'4', 'account_name' => credentials.user})
end
-
+#status == 0/1->BEING_CREATED 2->OFF 4->ON
#--
# START INSTANCE
#--
def start_instance(credentials, id)
terremark_client = new_client(credentials)
+ vapp = terremark_client.get_vapp(id)
terremark_client.power_on(id)
+ return convert_instance(vapp, terremark_client, {'vapp_status' =>
'4', 'account_name' => credentials.user})
end
#--
@@ -164,7 +168,9 @@ end
#--
def stop_instance(credentials, id)
terremark_client = new_client(credentials)
+ vapp = terremark_client.get_vapp(id)
terremark_client.power_shutdown(id)
+ return convert_instance(vapp, terremark_client, {'vapp_status' =>
'2', 'account_name' => credentials.user})
end
#--
@@ -177,12 +183,99 @@ def destroy_instance(credentials, id)
end
#--
+# ACCESS RULES
+#--
+ def access_rules(credentials, opts=nil)
+ access_rules = []
+ terremark_client = new_client(credentials)
+ services =
terremark_client.get_internet_services(terremark_client.default_vdc_id).body['InternetServices'].each
do |service|
+ port = service['Port']
+ s_id = service['Id'].to_s
+ protocol = service['Protocol']
+ nodes = terremark_client.get_node_services(s_id).body['NodeServices']
+ unless nodes.empty?
+ nodes.each do |node|
+ rule_id = "#{s_id}_#{node['IpAddress']}"
+ access_rules << AccessRule.new({ :id => rule_id,
+ :port => port,
+ :instance_group =>
"#{service['PublicIpAddress']['Name']}",
+ :protocol => protocol
+ })
+ end #nodes.each do
+ end #unless nodes empty
+ end #services.each do
+ access_rules = filter_on( access_rules, :id, opts )
+ access_rules
+ end
+
+#--
+# DELETE ACCESS RULE
+#--
+ def delete_access_rule(credentials, opts=nil)
+ service_id = opts[:id].to_s.split("_").first #
"xxx_111.222.111.222" where xxx is tmark service Id
+ terremark_client = new_client(credentials)
+ nodes = terremark_client.get_node_services(service_id).body['NodeServices']
+ unless nodes.empty?
+ nodes.each do |node|
+ terremark_client.delete_node_service(node['Id'])
+ end
+ end
+ terremark_client.delete_internet_service(service_id)
+ end
+
+#--
+# CREATE NEW ACCESS RULE
+#--
+#--expects opts['port'], opts['protocol'],
opts['instance_group']
+ def create_access_rule(credentials, opts={})
+ terremark_client = new_client(credentials)
+ port = opts['port']
+ protocol = opts['protocol']
+ instance_group = opts['instance_group']
+ #need the public ip address for the internet service
+ ip_id = nil #id of the IP address (from terremark)
+ service_id=nil
+ ip_addresses =
terremark_client.get_public_ips(terremark_client.default_vdc_id).body['PublicIpAddresses']
+ ip_addresses.each do |ip_address|
+ ip_id = ip_address['id'].to_s
+ service_id = internet_service_exists(terremark_client, ip_address['name'],
port, protocol)
+ if service_id
+ break
+ end
+ end #ip_addresses.each
+ unless service_id #in which case we create a new internet service
+ service_name ||= opts['service_name']
+ service_name ||= "svc" + (rand(1000)*Time.now.to_i).to_s.slice(0,7)
+ service_id = terremark_client.add_internet_service(ip_id, service_name, protocol,
port).body['Id'].to_s
+ end
+ node_name ||= opts['node_name']
+ node_name ||= "nod" + (rand(1000)*Time.now.to_i).to_s.slice(0,7)
+ private_port = port #use same private port as public one...?
+ terremark_client.add_node_service(service_id, instance_group, node_name,
private_port)
+ end
+
+#--
# PRIVATE METHODS:
#--
private
#--
+# INTERNET_SERVICE_EXISTS
+#-- helper to check if a given public IP/Port combination are defined as an existing
internet service
+#-- used by the create_access_rule method
+def internet_service_exists(terremark_client, public_address, public_port, protocol)
+ services = terremark_client.get_internet_services(terremark_client.default_vdc_id)
+ services.body['InternetServices'].each do |current_service|
+ if ( (current_service['PublicIpAddress']['Name'] == public_address)
&& (current_service['Port'].to_s == public_port) &&
+ (current_service['Protocol'].upcase == protocol.upcase) )
+ return current_service['Id']
+ end
+ end
+ nil #either return the service id or nil
+end
+
+#--
# CONVERT IMAGE
#--
#gets a vapp_template from a catalog and makes it a Image
@@ -204,10 +297,13 @@ end
#--
# CONVERT INSTANCE
#--
- def convert_instance(vapp, terremark_client, account_name)
+ def convert_instance(vapp, terremark_client, opts={})
vapp_private_ip = vapp.body['IpAddress']
vapp_public_ip =
terremark_client.get_public_ips(terremark_client.default_vdc_id).body['PublicIpAddresses'].first['name']#get_public_address(terremark_client,
vapp_private_ip)
- vapp_status = vapp.body['status']
+ unless opts['vapp_status']
+ vapp_status = vapp.body['status']
+ end
+ vapp_status ||= opts['vapp_status']
current_state = VAPP_STATE_MAP[vapp_status] #status == 0->BEING_CREATED
2->OFF 4->ON
profile = InstanceProfile.new("default")
name = vapp.body['name']
@@ -226,7 +322,7 @@ end
end
Instance.new( {
:id => vapp.body['href'].split('/').last,
- :owner_id => "#{account_name}",
+ :owner_id => "#{opts['account_name']}",
#:image_id => "n/a", #cant get this... see
https://community.vcloudexpress.terremark.com/en-us/discussion_forums/f/6...
:name => name,
:realm_id => "US-Miami",
--
1.6.6.1