From: marios marios@redhat.com
Current operations are list (index), create and delete a firewall rule. Also these patches contain only the html haml (not yet xml - want to decide if this is the model before doing this). --- server/deltacloud.rb | 1 + server/lib/deltacloud/base_driver/base_driver.rb | 16 +++ .../drivers/terremark/terremark_driver.rb | 100 +++++++++++++++++++- server/lib/deltacloud/models/firewall_rule.rb | 9 ++ server/server.rb | 88 ++++++++++++++++-- server/views/firewall_rules/index.html.haml | 37 +++++++ server/views/firewall_rules/new.html.haml | 22 +++++ server/views/firewall_rules/show.html.haml | 21 ++++ 8 files changed, 285 insertions(+), 9 deletions(-) create mode 100644 server/lib/deltacloud/models/firewall_rule.rb create mode 100644 server/views/firewall_rules/index.html.haml create mode 100644 server/views/firewall_rules/new.html.haml create mode 100644 server/views/firewall_rules/show.html.haml
diff --git a/server/deltacloud.rb b/server/deltacloud.rb index 1c19a5d..561fdfb 100644 --- a/server/deltacloud.rb +++ b/server/deltacloud.rb @@ -12,3 +12,4 @@ require 'deltacloud/models/instance' require 'deltacloud/models/instance_profile' require 'deltacloud/models/storage_snapshot' require 'deltacloud/models/storage_volume' +require 'deltacloud/models/firewall_rule' diff --git a/server/lib/deltacloud/base_driver/base_driver.rb b/server/lib/deltacloud/base_driver/base_driver.rb index a2b3bbe..b334db1 100644 --- a/server/lib/deltacloud/base_driver/base_driver.rb +++ b/server/lib/deltacloud/base_driver/base_driver.rb @@ -154,6 +154,22 @@ module Deltacloud def reboot_instance(credentials, id) end
+ def firewall_rules(credentials, opts) + [] + end + + def firewall_rule(credentials, opts) + rules = firewall_rules(credentials, opts) + return rules.first unless rules.empty? + nil + end + + def create_firewall_rule(credentials, opts) + end + def delete_firewall_rule(credentials, opts) + end + + def storage_volume(credentials, opts) volumes = storage_volumes(credentials, opts) return volumes.first unless volumes.empty? diff --git a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb index ae3c554..d464052 100644 --- a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb +++ b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb @@ -32,7 +32,7 @@ module Deltacloud
class TerremarkDriver < Deltacloud::BaseDriver
- feature :instances, :user_name +# feature :instances, :user_name
#-- # Vapp State Map... for use with convert_instance (get an integer back from terremark) @@ -50,6 +50,89 @@ VAPP_STATE_MAP = { "0" => "PENDING", "1" => "PENDING", "2" => "STOPPED", "4" #storage_disks [1..15]
#-- +# FIREWALL RULES +#-- + def firewall_rules(credentials, opts=nil) + firewall_rules = [] + terremark_client = new_client(credentials) + services = terremark_client.get_internet_services(terremark_client.default_vdc_id).body['InternetServices'].each do |service| + s_id = service['Id'].to_s + public_ip = service['PublicIpAddress']['Name'] + public_port = service['Port'] + protocol = service['Protocol'] + nodes = terremark_client.get_node_services(s_id).body['NodeServices'] + unless nodes.empty? + nodes.each do |node| + #puts "Id is #{node['Id']}, public_ip is #{public_ip}, public_port is #{public_port}, Private IP is #{node['IpAddress']}, private port is #{node['Port']} and protocol is #{protocol}" + firewall_rules << FirewallRule.new({ :id => s_id, + :public_address => public_ip, + :public_port => public_port, + :private_address => node['IpAddress'], + :private_port => node['Port'], + :protocol => protocol + }) + end #nodes.each do + end #unless nodes empty + end #services.each do + firewall_rules = filter_on( firewall_rules, :id, opts ) + firewall_rules + end + +#-- +# DELETE FIREWALL RULE +#--can expect that the service ID is passed in the opts... + def delete_firewall_rule(credentials, opts=nil) + service_id = opts[:id].to_s + 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 FIREWALL RULE +#--expected input: private and public ip address, private and public ports, protocol +#--opts['public_address'] +#--pts['service_protocol'] +#--opts['public_port'] +#--opts['private_port'] +#--opts['private_address'] +#--opts['service_name'] - OPTIONAL +#--opts['node_name'] - OPTIONAL + def create_firewall_rule(credentials, opts=nil) + terremark_client = new_client(credentials) + public_address = opts['public_address'] + public_port = opts['public_port'] + protocol = opts['service_protocol'] + #check if internet service exists or creating a new one + service_id = internet_service_exists(terremark_client, public_address, public_port, protocol) + unless service_id + ip_id = nil + #need to deduce the ip id to create a new internet service + ips = terremark_client.get_public_ips(terremark_client.default_vdc_id).body['PublicIpAddresses'] + ips.each do |ip| + if (ip['name'] == public_address) + ip_id = ip['id'].to_s + break + end + end #end ips.each + 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, public_port).body['Id'].to_s + end + #it adds the node service to the internet service... + node_name ||= opts['node_name'] + node_name ||= "nod" + (rand(1000)*Time.now.to_i).to_s.slice(0,7) + private_address = opts['private_address'] + private_port = opts['private_port'] + terremark_client.add_node_service(service_id, private_address, node_name, private_port) + end + +#-- # IMAGES #-- #aka "vapp_templates" @@ -183,6 +266,21 @@ end 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_firewall_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 +end + +#-- # CONVERT IMAGE #-- #gets a vapp_template from a catalog and makes it a Image diff --git a/server/lib/deltacloud/models/firewall_rule.rb b/server/lib/deltacloud/models/firewall_rule.rb new file mode 100644 index 0000000..390ede3 --- /dev/null +++ b/server/lib/deltacloud/models/firewall_rule.rb @@ -0,0 +1,9 @@ +class FirewallRule < BaseModel + + attr_accessor :public_address + attr_accessor :public_port + attr_accessor :private_address + attr_accessor :private_port + attr_accessor :protocol + +end \ No newline at end of file diff --git a/server/server.rb b/server/server.rb index b5bdfac..cb15bdf 100644 --- a/server/server.rb +++ b/server/server.rb @@ -65,6 +65,8 @@ def show(model) end
+ + # # Error handlers # @@ -108,7 +110,60 @@ get '/api/?' do end end
+get '/api/firewall_rules/:id/destroy' do + method = "delete_firewall_rule" + not_found unless driver.respond_to?(method) + opts = {} + opts[:id] = params[:id] + driver.send(method, credentials, opts) + redirect firewall_rules_url +end + +get '/api/firewall_rules/new' do + respond_to do |format| + format.html { haml :"firewall_rules/new" } + end +end + + +def delete_firewall_rule(service_id) + driver.send(delete_firewall_rule, credentials, {:id => params[:id]}) +end + # Rabbit DSL +collection :firewall_rules do + + description "Allow user to expose a public IP address/port and map these onto an internal IP address/port. eg expose ssh access [port 22, tcp]." + operation :index do + description 'Show all available network services' + control { filter_all(:firewall_rules) } + end + + operation :show do + description 'Show a firewall rule identified by its id' + param :id, :string, :required + control { show(:firewall_rule) } + end + + operation :create do + description 'Create a new firewall rule' + param :public_address, :string, :required + param :public_port, :string, :required + param :private_address, :string, :required + param :private_port, :string, :required + param :service_protocol, :string, :required + control do + driver.create_firewall_rule(credentials, params ) + filter_all(:firewall_rules) + end + end + + operation :destroy, :method => :post do + description 'destroy given firewall rule' + param :id, :string, :required + control { delete_firewall_rule(:id) } + end +end
collection :realms do description "Within a cloud provider a realm represents a boundary containing resources. The exact definition of a realm is left to the cloud provider. In some cases, a realm may represent different datacenters, different continents, or different pools of resources within a single datacenter. A cloud provider may insist that resources must all exist within a single realm in order to cooperate. For instance, storage volumes may only be allowed to be mounted to instances within the same realm." @@ -186,6 +241,22 @@ collection :instance_states do end end
+# Special instance get operations that we only allow for HTML +get "/api/instances/:id/:action" do + meth = :"#{params[:action]}_instance" + not_found unless driver.respond_to?(meth) + respond_to do |format| + format.html do + driver.send(meth, credentials, params[:id]) + if ( (params[:action] == 'destroy') or (params[:action] == 'stop') ) + redirect instances_url + else + redirect instance_url(params[:id]) + end + end + end +end + get "/api/instances/new" do @instance = Instance.new( { :id=>params[:id], :image_id=>params[:image_id] } ) @image = driver.image( credentials, :id => params[:image_id] ) @@ -197,14 +268,15 @@ get "/api/instances/new" do end
def instance_action(name) - @instance = driver.send(:"#{name}_instance", credentials, params["id"]) - - return redirect(instances_url) if name.eql?(:destroy) or @instance.class!=Instance - - respond_to do |format| - format.html { haml :"instances/show" } - format.xml { haml :"instances/show" } - format.json {convert_to_json(:instance, @instance) } + @instance = driver.send(:"#{name}_instance", credentials, params[:id]) + if name==:destroy + redirect instances_url + else + respond_to do |format| + format.html { haml :"instances/show" } + format.xml { haml :"instances/show" } + format.json {convert_to_json(:instance, @instance) } + end end end
diff --git a/server/views/firewall_rules/index.html.haml b/server/views/firewall_rules/index.html.haml new file mode 100644 index 0000000..47990b0 --- /dev/null +++ b/server/views/firewall_rules/index.html.haml @@ -0,0 +1,37 @@ +%h1 + Firewall Rules +%h3 + = link_to("Create new firewall rule", firewall_rules_url() + "/new") +%table.display + %thead + %tr + %th + ID + %th + Public Address + %th + Public Port + %th + Private Address + %th + Private Port + %th + Protocol + %tbody + - if @firewall_rules + - for rule in @firewall_rules + %tr + %td + = link_to rule.id, firewall_rules_url()+"/#{rule.id}" + %td + = rule.public_address + %td + = rule.public_port + %td + = rule.private_address + %td + = rule.private_port + %td + = rule.protocol + %td + = link_to("destroy", firewall_rules_url()+"/#{rule.id}/destroy", {:method => :post}) \ No newline at end of file diff --git a/server/views/firewall_rules/new.html.haml b/server/views/firewall_rules/new.html.haml new file mode 100644 index 0000000..9c6f0a0 --- /dev/null +++ b/server/views/firewall_rules/new.html.haml @@ -0,0 +1,22 @@ +%h1 New Firewall Rule + +%form{ :action => firewall_rules_url, :method => :post } + %p + %label + Public Address: + %input{ :name => 'public_address', :size => 16 } + %label + Public Port: + %input{ :name => 'public_port', :size => 6} + %label + Protocol: + %input{ :name => 'service_protocol', :size => 5} + %p + %label + Private Address: + %input{ :name => 'private_address', :size => 16 } + %label + Private Port: + %input{ :name => 'private_port', :size => 6} + %p + %input{ :type => :submit, :name => 'commit', :value => "create" } \ No newline at end of file diff --git a/server/views/firewall_rules/show.html.haml b/server/views/firewall_rules/show.html.haml new file mode 100644 index 0000000..8ec81c2 --- /dev/null +++ b/server/views/firewall_rules/show.html.haml @@ -0,0 +1,21 @@ +%h1 Firewall Rule +%h2 + = @firewall_rule.id + +%dl + %di + %dt Public IP + %dd + = @firewall_rule.public_address + %dt Public Port + %dd + = @firewall_rule.public_port + %dt Private IP + %dd + = @firewall_rule.private_address + %dt Private Port + %dd + = @firewall_rule.private_port + %dt Protocol + %dd + = @firewall_rule.protocol \ No newline at end of file