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.
Files changed (44) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +4 -0
  3. data/README.md +116 -0
  4. data/Rakefile +25 -0
  5. data/bin/vcloud_configure_edge_gateway +5 -0
  6. data/docs/find_network_url.md +56 -0
  7. data/docs/find_organisation_edgegateway_uuid.md +58 -0
  8. data/jenkins.sh +6 -0
  9. data/lib/component/firewall.rb +82 -0
  10. data/lib/component/load_balancer.rb +181 -0
  11. data/lib/component/nat.rb +73 -0
  12. data/lib/vcloud_network_configurator.rb +64 -0
  13. data/lib/vcloud_network_configurator/configure_task.rb +22 -0
  14. data/lib/vcloud_network_configurator/edge_gateway.rb +51 -0
  15. data/lib/vcloud_network_configurator/vcloud_auth_request.rb +39 -0
  16. data/lib/vcloud_network_configurator/vcloud_check_for_configure_task_request.rb +26 -0
  17. data/lib/vcloud_network_configurator/vcloud_configure_request.rb +51 -0
  18. data/lib/vcloud_network_configurator/vcloud_settings.rb +22 -0
  19. data/lib/vcloud_network_configurator/version.rb +1 -0
  20. data/spec/component/firewall.xml +45 -0
  21. data/spec/component/firewall_spec.rb +115 -0
  22. data/spec/component/lb.xml +567 -0
  23. data/spec/component/load_balancer_spec.rb +67 -0
  24. data/spec/component/nat.xml +146 -0
  25. data/spec/component/nat_spec.rb +28 -0
  26. data/spec/integration/authorization_failed_spec.rb +26 -0
  27. data/spec/integration/happy_path_firewall_spec.rb +74 -0
  28. data/spec/integration/happy_path_loadbalancer_spec.rb +173 -0
  29. data/spec/integration/happy_path_nat_spec.rb +78 -0
  30. data/spec/integration/test_data/happy_path_auth_response.xml +30 -0
  31. data/spec/integration/test_data/rules_dir/common_firewall.rb +6 -0
  32. data/spec/integration/test_data/rules_dir/common_lb.rb +10 -0
  33. data/spec/integration/test_data/rules_dir/common_nat.rb +0 -0
  34. data/spec/integration/test_data/rules_dir/preview/firewall.rb +0 -0
  35. data/spec/integration/test_data/rules_dir/preview/interfaces.yaml +2 -0
  36. data/spec/integration/test_data/rules_dir/preview/lb.rb +0 -0
  37. data/spec/integration/test_data/rules_dir/preview/nat.rb +4 -0
  38. data/spec/spec_helper.rb +9 -0
  39. data/spec/vcloud_network_configurator/configure_task_spec.rb +59 -0
  40. data/spec/vcloud_network_configurator/edge_gateway_spec.rb +41 -0
  41. data/spec/vcloud_network_configurator/vcloud_auth_request_spec.rb +20 -0
  42. data/spec/vcloud_network_configurator/vcloud_settings_spec.rb +19 -0
  43. data/vcloud-network-configurator.gemspec +33 -0
  44. metadata +212 -0
@@ -0,0 +1,2 @@
1
+ .bundle/
2
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gds-provisioning.gemspec
4
+ gemspec
@@ -0,0 +1,116 @@
1
+ # Vcloud Network Configurator
2
+
3
+ This is ruby gem which provides a dsl to configure firewall, nat and
4
+ loadbalancer rules. It is a wrapper around the network components of
5
+ vcloud api.
6
+
7
+ ## Installation
8
+
9
+ gem install vcloud-network-configurator
10
+
11
+ * Note: It is work in progress, and currently you would have to build
12
+ them gem locally using the following commands
13
+
14
+ git clone git@github.com:alphagov/vcloud-network-configurator.git
15
+ gem build vcloud-network-configurator.gemspec
16
+ gem install ./vcloud-network-configurator-0.1.0.gem
17
+
18
+ ## Usage
19
+
20
+ Usage: vcloud_configure_edge_gateway [options] API_URL
21
+ -u, --username=U Vcloud Username
22
+ -p, --password=P Vcloud Password
23
+ -e, --env=E Environment: preview | staging | production
24
+ -U, --organization-edgegateway-uuid=U UID: This is required to configure edgegateway services. For more info refer to
25
+ docs/find_organisation_edgegateway_uuid
26
+ -c, --component=c Environment: lb|firewall|nat
27
+ -o, --organization=o Organization: optional. Will default to environment
28
+ -d, --rule-directory=d Rules Directory: From where to read the NAT/Firewal/LB rules
29
+
30
+ Note: organization maps to the organization name in vcloud. Whereas,
31
+ environment maps to your internal environment reference (e.g.
32
+ preview, qa, staging, production, etc)
33
+
34
+ ### Example
35
+
36
+ vcloud_configure_edge_gateway -u username -p password -e preview -U 1yenz127ynz1872eyz12yz817e -c firewall -o development -d . http://vcloud.vendor.com/api
37
+
38
+ ### Rules Directory
39
+
40
+ A particular rules directory structure could be as follows.
41
+
42
+ .
43
+ ├── Gemfile
44
+ ├── Gemfile.lock
45
+ ├── common_firewall.rb
46
+ ├── common_lb.rb
47
+ ├── common_nat.rb
48
+ ├── env1
49
+ │ ├── firewall.rb
50
+ │ ├── interfaces.yaml
51
+ │ ├── lb.rb
52
+ │ └── nat.rb
53
+ ├── env2
54
+ ├── firewall.rb
55
+ ├── interfaces.yaml
56
+ ├── lb.rb
57
+ └── nat.rb
58
+
59
+ * Here each environment represent a separate organisation with your vcloud
60
+ vendor (eg qa, staging, production). These could have specific rules for nat,
61
+ firewall. Also these can have common firewall rules which could be shared
62
+ across all environments. A common example of such a situation is internal
63
+ network firewall rules are usually shared across environments, whereas
64
+ external network firewall rules would be different for all environment.
65
+
66
+ * Specific network rules => `env1/firewall.rb`, `env1/nat.rb`, `env1/lb.rb`
67
+ * Common network rules => `./common_firewall.rb`, `./common_lb.rb`, `./common_lb.rb`
68
+
69
+ * interfaces.yaml file:
70
+ To find the urls for network, follow the document at
71
+ `docs/find_network_url`
72
+
73
+ interfaces:
74
+ Network-1: "https://localhost:4567/api/admin/network/<vdc-network-uuid>"
75
+ Network-2: "https://localhost:4567/api/admin/network/<vdc-network-uuid>"
76
+
77
+ ### DSL
78
+
79
+ #### Firewall
80
+
81
+ firewall do
82
+ rule "<description>" do
83
+ source :ip => "172.10.0.0/8"
84
+ destination :ip => "172.10.0.5", :port => 4567
85
+ end
86
+ end
87
+
88
+ #### NAT
89
+
90
+ nat do
91
+ snat :interface => "<key-from-interfaces.rb>", :original => { :ip => "internal-ip" }, :translated => { :ip => "external-ip" }, :desc => "description"
92
+ dnat :interface => "<key-from-interfaces.rb>", :original => { :ip => "external-ip", :port => 22 }, :translated => { :ip => "internal-ip", :port => 22 }, :desc => "SSH"
93
+ end
94
+
95
+
96
+ #### Load Balancer
97
+
98
+ load_balancer do
99
+ configure "description-1" do
100
+ pool ["<ip-1>", "<ip-2>"] do
101
+ http
102
+ https
103
+ end
104
+
105
+ virtual_server :name => "description-1", :interface => "<key-from-interfaces.rb>", :ip => "<vse-ip>"
106
+ end
107
+
108
+ configure "description-2" do
109
+ pool ["<ip-1>", "<ip-2>", "<ip-3>"] do
110
+ http :port => 8080, :health_check_path => "</router/healthcheck>"
111
+ https
112
+ end
113
+
114
+ virtual_server :name => "description-2", :interface => "<key-from-interfaces.rb>", :ip => "<vse-ip>"
115
+ end
116
+ end
@@ -0,0 +1,25 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+ require 'rspec/core/rake_task'
4
+ require "gem_publisher"
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |task|
7
+ task.pattern = FileList.new('spec/**/*_spec.rb') do |file|
8
+ file.exclude(/integration/)
9
+ end
10
+ task.rspec_opts = ['--color']
11
+ end
12
+
13
+ RSpec::Core::RakeTask.new(:integration) do |task|
14
+ task.pattern = FileList['spec/integration/*_spec.rb']
15
+ task.rspec_opts = ['--color']
16
+ end
17
+
18
+ task :default => [:spec]
19
+
20
+ desc "Publish gem to RubyGems.org"
21
+ task :publish_gem do |t|
22
+ gem = GemPublisher.publish_if_updated("vcloud-network-configurator.gemspec", :rubygems)
23
+ puts "Published #{gem}" if gem
24
+ end
25
+
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.dirname(__FILE__) + '/../lib'
3
+ require 'vcloud_network_configurator'
4
+
5
+ VcloudNetworkConfigurator.new(ARGV).execute
@@ -0,0 +1,56 @@
1
+ # How to find Network UUID for interfaces.yaml
2
+
3
+ ## Steps
4
+
5
+ * vcloud authorization
6
+
7
+ curl -v -X POST -d '' -H "Accept: application/*+xml;version=5.1"
8
+ -u "{username}@vcloud-org-name:**********"
9
+ https://vendor-api-url.net/sessions
10
+
11
+
12
+ The above returns the following information in response
13
+ `x-cloud-authorization` and
14
+ `<Link rel="down" type="application/vnd.vmware.vcloud.orgList+xml" href="https://vendor-api-url.net/org/"/>`
15
+
16
+
17
+ * List organisations
18
+
19
+ curl -v --insecure
20
+ -H "x-vcloud-authorization: {x-vcloud-auth-code}"
21
+ -H "Accept: application/*+xml;version=5.1"
22
+ "https://vendor-api-url.net/org/"
23
+
24
+
25
+ This gives the list of organizations you have access to, and you can choose the one you need by using the name attribute `<Org type="application/vnd.vmware.vcloud.org+xml" name="ORG-NAME" href="https://vendor-api-url.net/org/{org-code}"/>`
26
+
27
+ * Get details of the organisation
28
+
29
+ curl -v --insecure -H "x-vcloud-authorization: {x-vcloud-auth-code}"
30
+ -H "Accept: application/*+xml;version=5.1"
31
+ "https://vendor-api-url.net/org/{org-code}"
32
+
33
+ * This also gives details about various vdc. We would need the one for management vdc:
34
+
35
+ <Link rel="down" type="application/vnd.vmware.vcloud.vdc+xml"
36
+ name="Management - GDS Development (SL1)"
37
+ href="https://vendor-api-url.net/vdc/{vdc-uuid}"/>
38
+
39
+ * Get vdc details
40
+
41
+ curl -v --insecure -H "x-vcloud-authorization: {x-vcloud-auth-code}"
42
+ -H "Accept: application/*+xml;version=5.1"
43
+ "https://vendor-api-url.net/vdc/{vdc-uuid}
44
+
45
+ * This would provide you with available networks. From which you
46
+ can use the name and href attributes for adding to your
47
+ interfaces.yaml
48
+
49
+ <AvailableNetworks>
50
+ <Network type="application/vnd.vmware.vcloud.network+xml" name="NetworkTest2"
51
+ href="https:///vendor-api-url.net/network/{network-uuid-2}"/>
52
+ <Network type="application/vnd.vmware.vcloud.network+xml" name="NetworkTest"
53
+ href="https:///vendor-api-url.net/network/{network-uuid-1}"/>
54
+ </AvailableNetworks>
55
+
56
+
@@ -0,0 +1,58 @@
1
+ # How to find Organisation Edgegateway UUID
2
+
3
+ ##Steps:
4
+
5
+ * vcloud authorization
6
+
7
+ curl -v -X POST -d '' -H "Accept: application/*+xml;version=5.1"
8
+ -u "{username}@vcloud-org-name:**********"
9
+ https://vendor-api-url.net/sessions
10
+
11
+
12
+ The above returns the following information in response
13
+ `x-cloud-authorization` and
14
+ `<Link rel="down" type="application/vnd.vmware.vcloud.orgList+xml" href="https://vendor-api-url.net/org/"/>`
15
+
16
+
17
+ * List organisations
18
+
19
+ curl -v --insecure
20
+ -H "x-vcloud-authorization: {x-vcloud-auth-code}"
21
+ -H "Accept: application/*+xml;version=5.1"
22
+ "https://vendor-api-url.net/org/"
23
+
24
+
25
+ This gives the list of organizations you have access to, and you can choose the one you need by using the name attribute `<Org type="application/vnd.vmware.vcloud.org+xml" name="ORG-NAME" href="https://vendor-api-url.net/org/{org-code}"/>`
26
+
27
+ * Get details of the organisation
28
+
29
+ curl -v --insecure -H "x-vcloud-authorization: {x-vcloud-auth-code}"
30
+ -H "Accept: application/*+xml;version=5.1"
31
+ "https://vendor-api-url.net/org/{org-code}"
32
+
33
+ * This also gives details about various vdc. We would need the one for management vdc:
34
+
35
+ <Link rel="down" type="application/vnd.vmware.vcloud.vdc+xml"
36
+ name="Management - GDS Development (SL1)"
37
+ href="https://vendor-api-url.net/vdc/{org-code}"/>
38
+
39
+ * Retrieve edgegateway record
40
+
41
+ curl -v --insecure -H "x-vcloud-authorization: {x-vcloud-auth-code}="
42
+ -H "Accept: application/*+xml;version=5.1"
43
+ "https://vendor-api-url.net/admin/vdc/{management-edgegateway-uuid}/edgeGateways"
44
+
45
+ * Response of the above is (from which you would need the id in the href attribute):
46
+
47
+ <EdgeGatewayRecord vdc="https://vendor-api-url.net/vdc/{management-edgegateway-uuid}"
48
+ numberOfOrgNetworks="8" numberOfExtNetworks="1"
49
+ name="GDS Development Gateway" isBusy="false" haStatus="UP" gatewayStatus="READY"
50
+ href="https://vendor-api-url.net/admin/edgeGateway/{id}"
51
+ isSyslogServerSettingInSync="true" taskStatus="success"
52
+ taskOperation="networkConfigureEdgeGatewayServices"
53
+ task="https://vendor-api-url.net/task/***" taskDetails=" "/>
54
+
55
+ *e.g. https://vendor-api-url.net/admin/edgeGateway/{id}*
56
+
57
+
58
+
@@ -0,0 +1,6 @@
1
+ #!/bin/bash -x
2
+ set -e
3
+ bundle install --path "${HOME}/bundles/${JOB_NAME}"
4
+ bundle exec rake spec
5
+ bundle exec rake integration
6
+ bundle exec rake publish_gem --trace
@@ -0,0 +1,82 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+
4
+ module Component
5
+ class Firewall
6
+ attr_reader :rules
7
+
8
+ def initialize
9
+ @rules = []
10
+ @count = 0
11
+ end
12
+
13
+ def rule(description, options = {}, &block)
14
+ defaults = { :enabled => true, :protocols => [:tcp], :id => @count+=1, :description => description}
15
+ @current_rule = defaults.merge(options)
16
+ rules << @current_rule
17
+ yield
18
+ ensure
19
+ @current_rule = nil
20
+ end
21
+
22
+ def source(options)
23
+ @current_rule[:source] = { :port => options[:port] || "Any", :ip => options[:ip] }
24
+ end
25
+
26
+ def destination(options)
27
+ @current_rule[:destination] = { :port => options[:port], :ip => options[:ip] }
28
+ end
29
+
30
+ def self.reset
31
+ @firewall = nil
32
+ end
33
+
34
+ def self.instance
35
+ @firewall ||= Firewall.new
36
+ end
37
+
38
+ def self.generate_xml interfaces
39
+ Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
40
+ 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") {
41
+ xml.FirewallService {
42
+ xml.IsEnabled "true"
43
+ xml.DefaultAction "drop"
44
+ xml.LogDefaultAction "false"
45
+
46
+ Firewall.instance.rules.each do |rule|
47
+ xml.FirewallRule {
48
+ xml.Id rule[:id]
49
+ xml.IsEnabled rule[:enabled]
50
+ xml.MatchOnTranslate "false"
51
+ xml.Description rule[:description]
52
+ xml.Policy "allow"
53
+
54
+ xml.Protocols {
55
+ rule[:protocols].each do |protocol|
56
+ xml.send(protocol.to_s.capitalize, true)
57
+ end
58
+ }
59
+
60
+ if rule[:protocols].first == :icmp
61
+ xml.IcmpSubType "any"
62
+ end
63
+
64
+ xml.Port rule[:destination][:port] == "Any" ? "-1" : rule[:destination][:port]
65
+ xml.DestinationPortRange rule[:destination][:port]
66
+ xml.DestinationIp rule[:destination][:ip]
67
+ xml.SourcePort rule[:source][:port] == "Any" ? "-1" : rule[:source][:port]
68
+ xml.SourcePortRange rule[:source][:port]
69
+ xml.SourceIp rule[:source][:ip]
70
+ xml.EnableLogging "false"
71
+ }
72
+ end
73
+ }
74
+ }
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ def firewall (&block)
81
+ Component::Firewall.instance.instance_eval(&block)
82
+ end
@@ -0,0 +1,181 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+
4
+ module Component
5
+ class LoadBalancer
6
+ attr_reader :pools, :configurations
7
+
8
+ def initialize
9
+ @pools = []
10
+ @configurations = []
11
+ end
12
+
13
+ def configure(name, &block)
14
+ @current_configuration = { :name => name, :virtual_servers => [], :pool => nil }
15
+ @configurations << @current_configuration
16
+ yield
17
+ ensure
18
+ @current_pool = nil
19
+ end
20
+
21
+ def virtual_server(options = {})
22
+ raise "Can't add a virtual server without first having defined a pool" if @current_pool.nil?
23
+ virtual_server = { :name => options[:name], :pool => @current_pool[:name], :ip => options[:ip], :interface => options[:interface] }
24
+ @current_configuration[:virtual_servers] << virtual_server
25
+ end
26
+
27
+ def pool(nodes, &block)
28
+ @current_pool = { :name => "#{@current_configuration[:name]} pool", :ports => [], :nodes => nodes }
29
+ @current_configuration[:pool] = @current_pool
30
+ @pools << @current_pool
31
+ yield
32
+ end
33
+
34
+ def http(options = {})
35
+ defaults = { :enabled => true, :health_check_path => "/", :port => 80, :health_check_mode => "HTTP" }
36
+ options = defaults.merge(options)
37
+ @current_pool[:ports] << { :port => options[:port], :health_check_port => options[:health_check_port],
38
+ :health_check_path => options[:health_check_path], :enabled => options[:enabled],
39
+ :type => :http, :health_check_mode=>options[:health_check_mode] }
40
+ end
41
+
42
+ def https(options = {})
43
+ defaults = { :enabled => true, :health_check_path => "/", :port => 443, :health_check_mode => "SSL" }
44
+ options = defaults.merge(options)
45
+ @current_pool[:ports] << { :port => options[:port], :health_check_port => options[:health_check_port],
46
+ :health_check_path => options[:health_check_path], :enabled => options[:enabled],
47
+ :type => :https, :health_check_mode => options[:health_check_mode] }
48
+ end
49
+
50
+ def load_balances(port, options = {})
51
+ defaults = { :enabled => true, :health_check_path => "/" }
52
+ options = defaults.merge(options)
53
+ @current_pool[:ports] << { :port => port, :health_check_port => options[:health_check_port], :health_check_path => options[:health_check_path],
54
+ :enabled => options[:enabled], :type => options[:type] }
55
+ end
56
+
57
+ def self.instance
58
+ @lb ||= LoadBalancer.new
59
+ end
60
+
61
+ def self.generate_xml interfaces
62
+ Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
63
+ 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") {
64
+ xml.LoadBalancerService {
65
+ xml.IsEnabled 'false'
66
+ LoadBalancer.instance.pools.each do |pool|
67
+ xml.Pool {
68
+ xml.Name pool[:name]
69
+
70
+ pool[:ports].each do |port|
71
+ xml.ServicePort {
72
+ xml.IsEnabled port[:enabled]
73
+ xml.Protocol port[:port] == 443 ? "HTTPS" : "HTTP"
74
+ xml.Algorithm 'ROUND_ROBIN'
75
+ xml.Port port[:port]
76
+
77
+ if port[:health_check_port]
78
+ xml.HealthCheckPort port[:health_check_port]
79
+ else
80
+ xml.HealthCheckPort
81
+ end
82
+
83
+ xml.HealthCheck {
84
+ xml.Mode port[:health_check_mode]
85
+ xml.Uri port[:health_check_path]
86
+ xml.HealthThreshold "2"
87
+ xml.UnhealthThreshold "3"
88
+ xml.Interval "5"
89
+ xml.Timeout "15"
90
+ }
91
+ }
92
+ end
93
+
94
+ xml.ServicePort {
95
+ xml.IsEnabled 'false'
96
+ xml.Protocol "TCP"
97
+ xml.Algorithm 'ROUND_ROBIN'
98
+ xml.Port
99
+ xml.HealthCheckPort
100
+ xml.HealthCheck {
101
+ xml.Mode "TCP"
102
+ xml.HealthThreshold "2"
103
+ xml.UnhealthThreshold "3"
104
+ xml.Interval "5"
105
+ xml.Timeout "15"
106
+ }
107
+ }
108
+
109
+ pool[:nodes].each do |node|
110
+ xml.Member {
111
+ xml.IpAddress node
112
+ xml.Weight "1"
113
+
114
+ ["HTTP", "HTTPS"].each do |protocol|
115
+ xml.ServicePort {
116
+ xml.Protocol protocol
117
+ xml.Port pool[:ports].find { |port| port[:type] == protocol.downcase.to_sym }[:port]
118
+ xml.HealthCheckPort
119
+ }
120
+ end
121
+
122
+ xml.ServicePort {
123
+ xml.Protocol "TCP"
124
+ xml.Port
125
+ xml.HealthCheckPort
126
+ }
127
+
128
+ }
129
+ end
130
+ xml.Operational "false"
131
+ }
132
+ end
133
+
134
+ LoadBalancer.instance.configurations.each do |configuration|
135
+ configuration[:virtual_servers].each do |virtual_server|
136
+ xml.VirtualServer {
137
+ xml.IsEnabled "true"
138
+ xml.Name virtual_server[:name]
139
+ xml.Interface('type' => "application/vnd.vmware.vcloud.orgVdcNetwork+xml", :name => virtual_server[:interface], :href => interfaces[virtual_server[:interface]])
140
+ xml.IpAddress virtual_server[:ip]
141
+
142
+ configuration[:pool][:ports].each do |port|
143
+ xml.ServiceProfile {
144
+ xml.IsEnabled port[:enabled]
145
+ xml.Protocol port[:type].to_s.upcase
146
+ xml.Port port[:port]
147
+ xml.Persistence {
148
+ if port[:type] == :https
149
+ xml.Method
150
+ else
151
+ xml.Method
152
+ end
153
+ }
154
+ }
155
+ end
156
+
157
+ xml.ServiceProfile {
158
+ xml.IsEnabled "false"
159
+ xml.Protocol "TCP"
160
+ xml.Port
161
+ xml.Persistence {
162
+ xml.Method
163
+ }
164
+ }
165
+ xml.Logging "false"
166
+ xml.Pool configuration[:pool][:name]
167
+
168
+ }
169
+ end
170
+ end
171
+ }
172
+ }
173
+ end
174
+ end
175
+
176
+ end
177
+ end
178
+
179
+ def load_balancer (&block)
180
+ Component::LoadBalancer.instance.instance_eval(&block)
181
+ end