vcloud-network-configurator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
 - data/Gemfile +4 -0
 - data/README.md +116 -0
 - data/Rakefile +25 -0
 - data/bin/vcloud_configure_edge_gateway +5 -0
 - data/docs/find_network_url.md +56 -0
 - data/docs/find_organisation_edgegateway_uuid.md +58 -0
 - data/jenkins.sh +6 -0
 - data/lib/component/firewall.rb +82 -0
 - data/lib/component/load_balancer.rb +181 -0
 - data/lib/component/nat.rb +73 -0
 - data/lib/vcloud_network_configurator.rb +64 -0
 - data/lib/vcloud_network_configurator/configure_task.rb +22 -0
 - data/lib/vcloud_network_configurator/edge_gateway.rb +51 -0
 - data/lib/vcloud_network_configurator/vcloud_auth_request.rb +39 -0
 - data/lib/vcloud_network_configurator/vcloud_check_for_configure_task_request.rb +26 -0
 - data/lib/vcloud_network_configurator/vcloud_configure_request.rb +51 -0
 - data/lib/vcloud_network_configurator/vcloud_settings.rb +22 -0
 - data/lib/vcloud_network_configurator/version.rb +1 -0
 - data/spec/component/firewall.xml +45 -0
 - data/spec/component/firewall_spec.rb +115 -0
 - data/spec/component/lb.xml +567 -0
 - data/spec/component/load_balancer_spec.rb +67 -0
 - data/spec/component/nat.xml +146 -0
 - data/spec/component/nat_spec.rb +28 -0
 - data/spec/integration/authorization_failed_spec.rb +26 -0
 - data/spec/integration/happy_path_firewall_spec.rb +74 -0
 - data/spec/integration/happy_path_loadbalancer_spec.rb +173 -0
 - data/spec/integration/happy_path_nat_spec.rb +78 -0
 - data/spec/integration/test_data/happy_path_auth_response.xml +30 -0
 - data/spec/integration/test_data/rules_dir/common_firewall.rb +6 -0
 - data/spec/integration/test_data/rules_dir/common_lb.rb +10 -0
 - data/spec/integration/test_data/rules_dir/common_nat.rb +0 -0
 - data/spec/integration/test_data/rules_dir/preview/firewall.rb +0 -0
 - data/spec/integration/test_data/rules_dir/preview/interfaces.yaml +2 -0
 - data/spec/integration/test_data/rules_dir/preview/lb.rb +0 -0
 - data/spec/integration/test_data/rules_dir/preview/nat.rb +4 -0
 - data/spec/spec_helper.rb +9 -0
 - data/spec/vcloud_network_configurator/configure_task_spec.rb +59 -0
 - data/spec/vcloud_network_configurator/edge_gateway_spec.rb +41 -0
 - data/spec/vcloud_network_configurator/vcloud_auth_request_spec.rb +20 -0
 - data/spec/vcloud_network_configurator/vcloud_settings_spec.rb +19 -0
 - data/vcloud-network-configurator.gemspec +33 -0
 - metadata +212 -0
 
| 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'nokogiri'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Component
         
     | 
| 
      
 5 
     | 
    
         
            +
              class NAT
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :rules
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @rules = []
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @count = 65537
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def dnat(options)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  rule(options.merge(:type => 'DNAT'))
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def snat(options)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  rule(options.merge(:type => 'SNAT'))
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def rule(options)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @count += 1;
         
     | 
| 
      
 23 
     | 
    
         
            +
                  defaults = { :enabled => true, :protocol => 'tcp', :id=>@count}
         
     | 
| 
      
 24 
     | 
    
         
            +
                  options = defaults.merge(options)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  rules << options
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def self.instance
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @nat ||= NAT.new
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def self.generate_xml interfaces
         
     | 
| 
      
 33 
     | 
    
         
            +
                  Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
         
     | 
| 
      
 34 
     | 
    
         
            +
                    xml.EdgeGatewayServiceConfiguration('xmlns' => "http://www.vmware.com/vcloud/v1.5", 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", 'xsi:schemaLocation' => "http://www.vmware.com/vcloud/v1.5 http://vendor-api-url.net/v1.5/schema/master.xsd") {
         
     | 
| 
      
 35 
     | 
    
         
            +
                      xml.NatService {
         
     | 
| 
      
 36 
     | 
    
         
            +
                        xml.IsEnabled "true"
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                        NAT.instance.rules.each do |rule|
         
     | 
| 
      
 39 
     | 
    
         
            +
                          xml.NatRule {
         
     | 
| 
      
 40 
     | 
    
         
            +
                            xml.RuleType rule[:type]
         
     | 
| 
      
 41 
     | 
    
         
            +
                            xml.IsEnabled rule[:enabled]
         
     | 
| 
      
 42 
     | 
    
         
            +
                            xml.Id rule[:id]
         
     | 
| 
      
 43 
     | 
    
         
            +
                            xml.GatewayNatRule {
         
     | 
| 
      
 44 
     | 
    
         
            +
                              xml.Interface('type' => "application/vnd.vmware.admin.network+xml", 'name' => rule[:interface], 'href' => interfaces[rule[:interface]])
         
     | 
| 
      
 45 
     | 
    
         
            +
                              xml.OriginalIp rule[:original][:ip]
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                              if rule[:original][:port]
         
     | 
| 
      
 48 
     | 
    
         
            +
                                xml.OriginalPort rule[:original][:port]
         
     | 
| 
      
 49 
     | 
    
         
            +
                              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                              xml.TranslatedIp rule[:translated][:ip]
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                              if rule[:translated][:port]
         
     | 
| 
      
 54 
     | 
    
         
            +
                                xml.TranslatedPort rule[:translated][:port]
         
     | 
| 
      
 55 
     | 
    
         
            +
                              end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                              if rule[:type] == "DNAT"
         
     | 
| 
      
 58 
     | 
    
         
            +
                                xml.Protocol rule[:protocol]
         
     | 
| 
      
 59 
     | 
    
         
            +
                              end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                            }
         
     | 
| 
      
 62 
     | 
    
         
            +
                          }
         
     | 
| 
      
 63 
     | 
    
         
            +
                        end
         
     | 
| 
      
 64 
     | 
    
         
            +
                      }
         
     | 
| 
      
 65 
     | 
    
         
            +
                    }
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
            end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            def nat (&block)
         
     | 
| 
      
 72 
     | 
    
         
            +
              Component::NAT.instance.instance_eval(&block)
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,64 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'optparse'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'component/firewall'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'component/load_balancer'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'component/nat'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'vcloud_network_configurator/edge_gateway'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            class VcloudNetworkConfigurator
         
     | 
| 
      
 8 
     | 
    
         
            +
              def initialize args
         
     | 
| 
      
 9 
     | 
    
         
            +
                @args = args
         
     | 
| 
      
 10 
     | 
    
         
            +
                @options = {}
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def execute
         
     | 
| 
      
 14 
     | 
    
         
            +
                parse @args
         
     | 
| 
      
 15 
     | 
    
         
            +
                EdgeGateway.new(@options).apply_configuration
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              private
         
     | 
| 
      
 19 
     | 
    
         
            +
              def parse args
         
     | 
| 
      
 20 
     | 
    
         
            +
                optparser = OptionParser.new do |o|
         
     | 
| 
      
 21 
     | 
    
         
            +
                  o.banner = "Usage: vcloud_configure_edge_gateway [options] API_URL"
         
     | 
| 
      
 22 
     | 
    
         
            +
                  o.summary_width = 40
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  o.on("-u", "--username=U", String, "Vcloud Username") do |v|
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @options[:username] = v
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  o.on("-p", "--password=P", String, "Vcloud Password") do |v|
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @options[:password] = v
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  o.on("-e", "--env=E", String, "Environment: name by which you would refer your environment as (also used for tree structure)") do |v|
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @options[:environment] = v
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  o.on("-U", "--organization-edgegateway-uuid=U",
         
     | 
| 
      
 37 
     | 
    
         
            +
                       "UID: This is required to configure edgegateway services. For more info refer to docs/find_organisation_edgegateway_uuid") do |v|
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @options[:org_edgegateway_uuid] = v
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  o.on("-c", "--component=c", ["lb", "firewall", "nat"], "Environment: lb|firewall|nat") do |v|
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @options[:component] = v
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  o.on("-o", "--organization=o", "Organization: optional. Will default to environment") do |v|
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @options[:organization] = v
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  o.on("-d", "--rule-directory=d", "Rules Directory: From where to read the NAT/Firewal/LB rules") do |v|
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @options[:rules_directory] = v
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                optparser.parse!(@args)
         
     | 
| 
      
 55 
     | 
    
         
            +
                if !args.empty?
         
     | 
| 
      
 56 
     | 
    
         
            +
                  @options[:api_url] = args[0]
         
     | 
| 
      
 57 
     | 
    
         
            +
                else
         
     | 
| 
      
 58 
     | 
    
         
            +
                  raise Exception.new("No API_URL provided. See help for more details")
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                @options[:organization] ||= @options[:environment]
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'nokogiri'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class ConfigureTask
         
     | 
| 
      
 4 
     | 
    
         
            +
              def initialize configure_xml
         
     | 
| 
      
 5 
     | 
    
         
            +
                @configure_xml =  Nokogiri::XML(configure_xml)
         
     | 
| 
      
 6 
     | 
    
         
            +
                @configure_xml.remove_namespaces!
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              def url
         
     | 
| 
      
 10 
     | 
    
         
            +
                @configure_xml.xpath("//Task/@href").to_s
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def complete?
         
     | 
| 
      
 14 
     | 
    
         
            +
                @configure_xml.xpath("//Task/@status").to_s == "success"
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              def error?
         
     | 
| 
      
 18 
     | 
    
         
            +
                puts @configure_xml.xpath("//Task/Error/@majorErrorCode")
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                !@configure_xml.xpath("//Task/Error/@majorErrorCode").empty?
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'vcloud_network_configurator/vcloud_auth_request'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'vcloud_network_configurator/vcloud_configure_request'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'vcloud_network_configurator/vcloud_check_for_configure_task_request'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'vcloud_network_configurator/configure_task'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class EdgeGateway
         
     | 
| 
      
 7 
     | 
    
         
            +
              def initialize options
         
     | 
| 
      
 8 
     | 
    
         
            +
                @options = options
         
     | 
| 
      
 9 
     | 
    
         
            +
                @vcloud_settings = VcloudSettings.new( { url: @options[:api_url], edge_gateway_uuid: @options[:org_edgegateway_uuid] } )
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def apply_configuration
         
     | 
| 
      
 13 
     | 
    
         
            +
                auth_header = authorize_request
         
     | 
| 
      
 14 
     | 
    
         
            +
                configure_request = VcloudConfigureRequest.new(@vcloud_settings, auth_header, @options[:environment], @options[:component], @options[:rules_directory])
         
     | 
| 
      
 15 
     | 
    
         
            +
                configure_request.submit
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                if configure_request.success?
         
     | 
| 
      
 18 
     | 
    
         
            +
                  check_for_success auth_header, ConfigureTask.new(configure_request.response_body)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 20 
     | 
    
         
            +
                else
         
     | 
| 
      
 21 
     | 
    
         
            +
                  puts "Failed to configure the edge gateway"
         
     | 
| 
      
 22 
     | 
    
         
            +
                  return false
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              private
         
     | 
| 
      
 27 
     | 
    
         
            +
              def authorize_request
         
     | 
| 
      
 28 
     | 
    
         
            +
                auth_request = VcloudAuthRequest.new(@vcloud_settings, "#{@options[:username]}@#{@options[:organization]}", @options[:password])
         
     | 
| 
      
 29 
     | 
    
         
            +
                auth_request.submit
         
     | 
| 
      
 30 
     | 
    
         
            +
                abort("Could not authenticate user") unless auth_request.authenticated?
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                auth_request.auth_response["x-vcloud-authorization"]
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              def check_for_success auth_header, configure_task
         
     | 
| 
      
 36 
     | 
    
         
            +
                begin
         
     | 
| 
      
 37 
     | 
    
         
            +
                  puts "\n\n\nSleeping for 10 seconds before the next check for success \n\n\n"
         
     | 
| 
      
 38 
     | 
    
         
            +
                  sleep(10) unless ENV['GEM_ENV'] == "test"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  response = VcloudCheckForConfigureTaskRequest.new(auth_header, configure_task.url).submit
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  configure_task = ConfigureTask.new(response.body)
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  if configure_task.error?
         
     | 
| 
      
 44 
     | 
    
         
            +
                    abort("Failed to configure the edge gateway")
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                end while not configure_task.complete?
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                puts "\n\n\nSuccessfully configured the edge gateway"
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "net/http"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "vcloud_network_configurator/vcloud_settings"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class VcloudAuthRequest
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def initialize vcloud_settings, username, password
         
     | 
| 
      
 7 
     | 
    
         
            +
                @user_name = username
         
     | 
| 
      
 8 
     | 
    
         
            +
                @password = password
         
     | 
| 
      
 9 
     | 
    
         
            +
                @vcloud_settings = vcloud_settings
         
     | 
| 
      
 10 
     | 
    
         
            +
                @response = nil
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def submit
         
     | 
| 
      
 14 
     | 
    
         
            +
                puts "Submitting auth request at #{@vcloud_settings.sessions_url}\n"
         
     | 
| 
      
 15 
     | 
    
         
            +
                url = URI(@vcloud_settings.sessions_url)
         
     | 
| 
      
 16 
     | 
    
         
            +
                request = Net::HTTP::Post.new url.request_uri
         
     | 
| 
      
 17 
     | 
    
         
            +
                request['Accept'] = VcloudSettings.request_headers['Accept']
         
     | 
| 
      
 18 
     | 
    
         
            +
                request.basic_auth @user_name, @password
         
     | 
| 
      
 19 
     | 
    
         
            +
                session = Net::HTTP.new(url.host, url.port)
         
     | 
| 
      
 20 
     | 
    
         
            +
                session.use_ssl = true
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                response = session.start do |http|
         
     | 
| 
      
 23 
     | 
    
         
            +
                  http.request request
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                puts "HTTP #{response.code}"
         
     | 
| 
      
 27 
     | 
    
         
            +
                puts response
         
     | 
| 
      
 28 
     | 
    
         
            +
                @response = response
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              def authenticated?
         
     | 
| 
      
 32 
     | 
    
         
            +
                auth_response.code == "200"
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              def auth_response
         
     | 
| 
      
 36 
     | 
    
         
            +
                @response
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "net/http"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class VcloudCheckForConfigureTaskRequest
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def initialize auth_header, task_url
         
     | 
| 
      
 6 
     | 
    
         
            +
                @auth_header = auth_header
         
     | 
| 
      
 7 
     | 
    
         
            +
                @task_url = task_url
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def submit
         
     | 
| 
      
 11 
     | 
    
         
            +
                url = URI(@task_url)
         
     | 
| 
      
 12 
     | 
    
         
            +
                request = Net::HTTP::Get.new url.request_uri
         
     | 
| 
      
 13 
     | 
    
         
            +
                request['Accept'] = 'application/*+xml;version=5.1'
         
     | 
| 
      
 14 
     | 
    
         
            +
                request['x-vcloud-authorization'] = @auth_header
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                puts "Submitting request at #{@task_url}"
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                session = Net::HTTP.new(url.host, url.port)
         
     | 
| 
      
 19 
     | 
    
         
            +
                session.use_ssl = true
         
     | 
| 
      
 20 
     | 
    
         
            +
                response = session.start do |http|
         
     | 
| 
      
 21 
     | 
    
         
            +
                  http.request request
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
                puts response
         
     | 
| 
      
 24 
     | 
    
         
            +
                return response
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "net/http"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class VcloudConfigureRequest
         
     | 
| 
      
 5 
     | 
    
         
            +
              def initialize vcloud_settings, auth_header, environment, component, rules_directory
         
     | 
| 
      
 6 
     | 
    
         
            +
                @auth_header = auth_header
         
     | 
| 
      
 7 
     | 
    
         
            +
                @config_url =  vcloud_settings.edge_gateway_config_url
         
     | 
| 
      
 8 
     | 
    
         
            +
                @environment = environment
         
     | 
| 
      
 9 
     | 
    
         
            +
                @component = component
         
     | 
| 
      
 10 
     | 
    
         
            +
                @response = nil
         
     | 
| 
      
 11 
     | 
    
         
            +
                @interfaces = YAML::load_file("#{rules_directory}/#{@environment}/interfaces.yaml")['interfaces']
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                require "#{rules_directory}/common_#{component}.rb"
         
     | 
| 
      
 14 
     | 
    
         
            +
                require "#{rules_directory}/#{@environment}/#{component}"
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              def components
         
     | 
| 
      
 18 
     | 
    
         
            +
                { "firewall" => "Firewall", "nat" => "NAT", "lb" => "LoadBalancer" }
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              def submit
         
     | 
| 
      
 22 
     | 
    
         
            +
                url = URI(@config_url)
         
     | 
| 
      
 23 
     | 
    
         
            +
                request = Net::HTTP::Post.new url.request_uri
         
     | 
| 
      
 24 
     | 
    
         
            +
                request['Accept'] = VcloudSettings.request_headers['Accept']
         
     | 
| 
      
 25 
     | 
    
         
            +
                request['Content-Type'] = VcloudSettings.request_headers['Content-Type']
         
     | 
| 
      
 26 
     | 
    
         
            +
                request['x-vcloud-authorization'] = @auth_header
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                request.body = Kernel.const_get("Component").const_get(components[@component]).generate_xml(@interfaces).to_xml
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                puts "Reading configuration from #{@config_file}"
         
     | 
| 
      
 31 
     | 
    
         
            +
                puts "Submitting request at #{@config_url}\n"
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                session = Net::HTTP.new(url.host, url.port)
         
     | 
| 
      
 34 
     | 
    
         
            +
                session.use_ssl = true
         
     | 
| 
      
 35 
     | 
    
         
            +
                response = session.start do |http|
         
     | 
| 
      
 36 
     | 
    
         
            +
                  http.request request
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                puts "HTTP #{response.code}"
         
     | 
| 
      
 40 
     | 
    
         
            +
                puts response
         
     | 
| 
      
 41 
     | 
    
         
            +
                @response = response
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              def success?
         
     | 
| 
      
 45 
     | 
    
         
            +
                @response.code == "202"
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
              def response_body
         
     | 
| 
      
 49 
     | 
    
         
            +
                @response.body
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class VcloudSettings
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              def initialize options = {}
         
     | 
| 
      
 4 
     | 
    
         
            +
                @api_url = options[:url]
         
     | 
| 
      
 5 
     | 
    
         
            +
                @edge_gateway_uuid = options[:edge_gateway_uuid]
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              def sessions_url
         
     | 
| 
      
 9 
     | 
    
         
            +
                @api_url + "/sessions"
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def edge_gateway_config_url
         
     | 
| 
      
 13 
     | 
    
         
            +
                @api_url + "/admin/edgeGateway/" + @edge_gateway_uuid + "/action/configureServices"
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              def self.request_headers
         
     | 
| 
      
 17 
     | 
    
         
            +
                {
         
     | 
| 
      
 18 
     | 
    
         
            +
                  'Accept' => 'application/*+xml;version=5.1',
         
     | 
| 
      
 19 
     | 
    
         
            +
                  'Content-Type' => 'application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml'
         
     | 
| 
      
 20 
     | 
    
         
            +
                }
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            VERSION = '0.1.0'
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <?xml version="1.0" encoding="UTF-8"?>
         
     | 
| 
      
 2 
     | 
    
         
            +
            <EdgeGatewayServiceConfiguration xmlns="http://www.vmware.com/vcloud/v1.5"
         
     | 
| 
      
 3 
     | 
    
         
            +
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         
     | 
| 
      
 4 
     | 
    
         
            +
              xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://vendor-api-url.net/v1.5/schema/master.xsd">
         
     | 
| 
      
 5 
     | 
    
         
            +
              <FirewallService>
         
     | 
| 
      
 6 
     | 
    
         
            +
                <IsEnabled>true</IsEnabled>
         
     | 
| 
      
 7 
     | 
    
         
            +
                <DefaultAction>drop</DefaultAction>
         
     | 
| 
      
 8 
     | 
    
         
            +
                <LogDefaultAction>false</LogDefaultAction>
         
     | 
| 
      
 9 
     | 
    
         
            +
                <FirewallRule>
         
     | 
| 
      
 10 
     | 
    
         
            +
                  <Id>1</Id>
         
     | 
| 
      
 11 
     | 
    
         
            +
                  <IsEnabled>true</IsEnabled>
         
     | 
| 
      
 12 
     | 
    
         
            +
                  <MatchOnTranslate>false</MatchOnTranslate>
         
     | 
| 
      
 13 
     | 
    
         
            +
                  <Description>Oubound Traffic</Description>
         
     | 
| 
      
 14 
     | 
    
         
            +
                  <Policy>allow</Policy>
         
     | 
| 
      
 15 
     | 
    
         
            +
                  <Protocols>
         
     | 
| 
      
 16 
     | 
    
         
            +
                    <Tcp>true</Tcp>
         
     | 
| 
      
 17 
     | 
    
         
            +
                    <Udp>true</Udp>
         
     | 
| 
      
 18 
     | 
    
         
            +
                  </Protocols>
         
     | 
| 
      
 19 
     | 
    
         
            +
                  <Port>-1</Port>
         
     | 
| 
      
 20 
     | 
    
         
            +
                  <DestinationPortRange>Any</DestinationPortRange>
         
     | 
| 
      
 21 
     | 
    
         
            +
                  <DestinationIp>external</DestinationIp>
         
     | 
| 
      
 22 
     | 
    
         
            +
                  <SourcePort>-1</SourcePort>
         
     | 
| 
      
 23 
     | 
    
         
            +
                  <SourcePortRange>Any</SourcePortRange>
         
     | 
| 
      
 24 
     | 
    
         
            +
                  <SourceIp>Any</SourceIp>
         
     | 
| 
      
 25 
     | 
    
         
            +
                  <EnableLogging>false</EnableLogging>
         
     | 
| 
      
 26 
     | 
    
         
            +
                </FirewallRule>
         
     | 
| 
      
 27 
     | 
    
         
            +
                <FirewallRule>
         
     | 
| 
      
 28 
     | 
    
         
            +
                  <Id>2</Id>
         
     | 
| 
      
 29 
     | 
    
         
            +
                  <IsEnabled>true</IsEnabled>
         
     | 
| 
      
 30 
     | 
    
         
            +
                  <MatchOnTranslate>false</MatchOnTranslate>
         
     | 
| 
      
 31 
     | 
    
         
            +
                  <Description>ssh access to jumpbox1</Description>
         
     | 
| 
      
 32 
     | 
    
         
            +
                  <Policy>allow</Policy>
         
     | 
| 
      
 33 
     | 
    
         
            +
                  <Protocols>
         
     | 
| 
      
 34 
     | 
    
         
            +
                    <Tcp>true</Tcp>
         
     | 
| 
      
 35 
     | 
    
         
            +
                  </Protocols>
         
     | 
| 
      
 36 
     | 
    
         
            +
                  <Port>22</Port>
         
     | 
| 
      
 37 
     | 
    
         
            +
                  <DestinationPortRange>22</DestinationPortRange>
         
     | 
| 
      
 38 
     | 
    
         
            +
                  <DestinationIp>200.11.99.70</DestinationIp>
         
     | 
| 
      
 39 
     | 
    
         
            +
                  <SourcePort>-1</SourcePort>
         
     | 
| 
      
 40 
     | 
    
         
            +
                  <SourcePortRange>Any</SourcePortRange>
         
     | 
| 
      
 41 
     | 
    
         
            +
                  <SourceIp>Any</SourceIp>
         
     | 
| 
      
 42 
     | 
    
         
            +
                  <EnableLogging>false</EnableLogging>
         
     | 
| 
      
 43 
     | 
    
         
            +
                </FirewallRule>
         
     | 
| 
      
 44 
     | 
    
         
            +
              </FirewallService>
         
     | 
| 
      
 45 
     | 
    
         
            +
            </EdgeGatewayServiceConfiguration>
         
     | 
| 
         @@ -0,0 +1,115 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'nokogiri'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'equivalent-xml'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'component/firewall'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Component
         
     | 
| 
      
 7 
     | 
    
         
            +
              describe "firewall" do
         
     | 
| 
      
 8 
     | 
    
         
            +
                before :each do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @interfaces = {
         
     | 
| 
      
 10 
     | 
    
         
            +
                    "TestData" => "https://vendor-api-url.net/admin/network/1000"
         
     | 
| 
      
 11 
     | 
    
         
            +
                  }
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                it "should be able to generate XML that matches what we created directly through the control panel" do
         
     | 
| 
      
 15 
     | 
    
         
            +
                  Firewall.reset
         
     | 
| 
      
 16 
     | 
    
         
            +
                  firewall do
         
     | 
| 
      
 17 
     | 
    
         
            +
                    rule "Oubound Traffic", :protocols => [:tcp, :udp] do
         
     | 
| 
      
 18 
     | 
    
         
            +
                      source      :ip => "Any",           :port => "Any"
         
     | 
| 
      
 19 
     | 
    
         
            +
                      destination :ip => "external",      :port => "Any"
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    rule "ssh access to jumpbox1", :protocols => [:tcp] do
         
     | 
| 
      
 23 
     | 
    
         
            +
                      source      :ip => "Any",           :port => "Any"
         
     | 
| 
      
 24 
     | 
    
         
            +
                      destination :ip => "200.11.99.70", :port => 22
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  Nokogiri::XML(Firewall.generate_xml(@interfaces).doc.root.to_s).should be_equivalent_to Nokogiri::XML(File.open("spec/component/firewall.xml"))
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                it "should default the protocol to tcp" do
         
     | 
| 
      
 32 
     | 
    
         
            +
                  Firewall.reset
         
     | 
| 
      
 33 
     | 
    
         
            +
                  firewall do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    rule "tcp only" do
         
     | 
| 
      
 35 
     | 
    
         
            +
                      source      :ip => "Any", :port => "Any"
         
     | 
| 
      
 36 
     | 
    
         
            +
                      destination :ip => "Any", :port => "Any"
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  expected = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
         
     | 
| 
      
 41 
     | 
    
         
            +
                    xml.EdgeGatewayServiceConfiguration('xmlns' => "http://www.vmware.com/vcloud/v1.5", 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", 'xsi:schemaLocation' => "http://www.vmware.com/vcloud/v1.5 http://vendor-api-url.net/v1.5/schema/master.xsd") {
         
     | 
| 
      
 42 
     | 
    
         
            +
                      xml.FirewallService {
         
     | 
| 
      
 43 
     | 
    
         
            +
                        xml.IsEnabled "true"
         
     | 
| 
      
 44 
     | 
    
         
            +
                        xml.DefaultAction "drop"
         
     | 
| 
      
 45 
     | 
    
         
            +
                        xml.LogDefaultAction "false"
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                        xml.FirewallRule {
         
     | 
| 
      
 48 
     | 
    
         
            +
                          xml.Id "1"
         
     | 
| 
      
 49 
     | 
    
         
            +
                          xml.IsEnabled "true"
         
     | 
| 
      
 50 
     | 
    
         
            +
                          xml.MatchOnTranslate "false"
         
     | 
| 
      
 51 
     | 
    
         
            +
                          xml.Description "tcp only"
         
     | 
| 
      
 52 
     | 
    
         
            +
                          xml.Policy "allow"
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                          xml.Protocols {
         
     | 
| 
      
 55 
     | 
    
         
            +
                            xml.Tcp "true"
         
     | 
| 
      
 56 
     | 
    
         
            +
                          }
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                          xml.Port "-1"
         
     | 
| 
      
 59 
     | 
    
         
            +
                          xml.DestinationPortRange "Any"
         
     | 
| 
      
 60 
     | 
    
         
            +
                          xml.DestinationIp "Any"
         
     | 
| 
      
 61 
     | 
    
         
            +
                          xml.SourcePort "-1"
         
     | 
| 
      
 62 
     | 
    
         
            +
                          xml.SourcePortRange "Any"
         
     | 
| 
      
 63 
     | 
    
         
            +
                          xml.SourceIp "Any"
         
     | 
| 
      
 64 
     | 
    
         
            +
                          xml.EnableLogging "false"
         
     | 
| 
      
 65 
     | 
    
         
            +
                        }
         
     | 
| 
      
 66 
     | 
    
         
            +
                      }
         
     | 
| 
      
 67 
     | 
    
         
            +
                    }
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  Nokogiri::XML(Firewall.generate_xml(@interfaces).doc.root.to_s).should be_equivalent_to(expected.doc.root.to_s)
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                it "should default the source to Any" do
         
     | 
| 
      
 74 
     | 
    
         
            +
                  Firewall.reset
         
     | 
| 
      
 75 
     | 
    
         
            +
                  firewall do
         
     | 
| 
      
 76 
     | 
    
         
            +
                    rule "source port any" do
         
     | 
| 
      
 77 
     | 
    
         
            +
                      source      :ip => "Any"
         
     | 
| 
      
 78 
     | 
    
         
            +
                      destination :ip => "Any", :port => "Any"
         
     | 
| 
      
 79 
     | 
    
         
            +
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  expected = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
         
     | 
| 
      
 83 
     | 
    
         
            +
                    xml.EdgeGatewayServiceConfiguration('xmlns' => "http://www.vmware.com/vcloud/v1.5", 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", 'xsi:schemaLocation' => "http://www.vmware.com/vcloud/v1.5 http://vendor-api-url.net/v1.5/schema/master.xsd") {
         
     | 
| 
      
 84 
     | 
    
         
            +
                      xml.FirewallService {
         
     | 
| 
      
 85 
     | 
    
         
            +
                        xml.IsEnabled "true"
         
     | 
| 
      
 86 
     | 
    
         
            +
                        xml.DefaultAction "drop"
         
     | 
| 
      
 87 
     | 
    
         
            +
                        xml.LogDefaultAction "false"
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                        xml.FirewallRule {
         
     | 
| 
      
 90 
     | 
    
         
            +
                          xml.Id "1"
         
     | 
| 
      
 91 
     | 
    
         
            +
                          xml.IsEnabled "true"
         
     | 
| 
      
 92 
     | 
    
         
            +
                          xml.MatchOnTranslate "false"
         
     | 
| 
      
 93 
     | 
    
         
            +
                          xml.Description "source port any"
         
     | 
| 
      
 94 
     | 
    
         
            +
                          xml.Policy "allow"
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                          xml.Protocols {
         
     | 
| 
      
 97 
     | 
    
         
            +
                            xml.Tcp "true"
         
     | 
| 
      
 98 
     | 
    
         
            +
                          }
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                          xml.Port "-1"
         
     | 
| 
      
 101 
     | 
    
         
            +
                          xml.DestinationPortRange "Any"
         
     | 
| 
      
 102 
     | 
    
         
            +
                          xml.DestinationIp "Any"
         
     | 
| 
      
 103 
     | 
    
         
            +
                          xml.SourcePort "-1"
         
     | 
| 
      
 104 
     | 
    
         
            +
                          xml.SourcePortRange "Any"
         
     | 
| 
      
 105 
     | 
    
         
            +
                          xml.SourceIp "Any"
         
     | 
| 
      
 106 
     | 
    
         
            +
                          xml.EnableLogging "false"
         
     | 
| 
      
 107 
     | 
    
         
            +
                        }
         
     | 
| 
      
 108 
     | 
    
         
            +
                      }
         
     | 
| 
      
 109 
     | 
    
         
            +
                    }
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                  Nokogiri::XML(Firewall.generate_xml(@interfaces).doc.root.to_s).should be_equivalent_to(expected.doc.root.to_s)
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
      
 114 
     | 
    
         
            +
              end
         
     | 
| 
      
 115 
     | 
    
         
            +
            end
         
     |