vcloud-edge_gateway 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +16 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.md +160 -0
- data/Rakefile +23 -0
- data/bin/vcloud-edge +12 -0
- data/jenkins.sh +11 -0
- data/lib/vcloud/config_loader.rb +27 -0
- data/lib/vcloud/config_validator.rb +207 -0
- data/lib/vcloud/edge_gateway/configuration_differ.rb +17 -0
- data/lib/vcloud/edge_gateway/configuration_generator/firewall_service.rb +63 -0
- data/lib/vcloud/edge_gateway/configuration_generator/id_ranges.rb +10 -0
- data/lib/vcloud/edge_gateway/configuration_generator/load_balancer_service.rb +243 -0
- data/lib/vcloud/edge_gateway/configuration_generator/nat_service.rb +54 -0
- data/lib/vcloud/edge_gateway/edge_gateway_configuration.rb +41 -0
- data/lib/vcloud/edge_gateway/version.rb +6 -0
- data/lib/vcloud/edge_gateway.rb +32 -0
- data/lib/vcloud/edge_gateway_services.rb +26 -0
- data/lib/vcloud/schema/edge_gateway.rb +15 -0
- data/lib/vcloud/schema/firewall_service.rb +39 -0
- data/lib/vcloud/schema/load_balancer_service.rb +129 -0
- data/lib/vcloud/schema/nat_service.rb +35 -0
- data/scripts/generate_fog_conf_file.sh +6 -0
- data/spec/erb_helper.rb +11 -0
- data/spec/integration/edge_gateway/data/firewall_config.yaml.erb +17 -0
- data/spec/integration/edge_gateway/data/firewall_config_updated_rule.yaml.erb +17 -0
- data/spec/integration/edge_gateway/data/firewall_rule_order_test.yaml.erb +24 -0
- data/spec/integration/edge_gateway/data/hairpin_nat_config.yaml.erb +13 -0
- data/spec/integration/edge_gateway/data/incorrect_firewall_config.yaml +14 -0
- data/spec/integration/edge_gateway/data/nat_and_firewall_config.yaml.erb +32 -0
- data/spec/integration/edge_gateway/data/nat_config.yaml.erb +17 -0
- data/spec/integration/edge_gateway/edge_gateway_services_spec.rb +132 -0
- data/spec/integration/edge_gateway/firewall_service_spec.rb +201 -0
- data/spec/integration/edge_gateway/nat_service_spec.rb +208 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/vcloud/config_loader_spec.rb +112 -0
- data/spec/vcloud/config_validator_spec.rb +570 -0
- data/spec/vcloud/data/basic_preamble_test.erb +8 -0
- data/spec/vcloud/data/basic_preamble_test.erb.OUT +8 -0
- data/spec/vcloud/data/working.json +21 -0
- data/spec/vcloud/data/working.yaml +22 -0
- data/spec/vcloud/data/working_with_defaults.yaml +25 -0
- data/spec/vcloud/edge_gateway/configuration_differ_spec.rb +131 -0
- data/spec/vcloud/edge_gateway/configuration_generator/data/load_balancer_http-input.yaml +41 -0
- data/spec/vcloud/edge_gateway/configuration_generator/data/load_balancer_http-output.yaml +93 -0
- data/spec/vcloud/edge_gateway/configuration_generator/data/load_balancer_https-input.yaml +39 -0
- data/spec/vcloud/edge_gateway/configuration_generator/data/load_balancer_https-output.yaml +92 -0
- data/spec/vcloud/edge_gateway/configuration_generator/data/load_balancer_mixed_complex-input.yaml +65 -0
- data/spec/vcloud/edge_gateway/configuration_generator/data/load_balancer_mixed_complex-output.yaml +94 -0
- data/spec/vcloud/edge_gateway/configuration_generator/firewall_service_spec.rb +378 -0
- data/spec/vcloud/edge_gateway/configuration_generator/load_balancer_service_spec.rb +233 -0
- data/spec/vcloud/edge_gateway/configuration_generator/nat_service_spec.rb +360 -0
- data/spec/vcloud/edge_gateway/edge_gateway_configuration_spec.rb +182 -0
- data/spec/vcloud/edge_gateway/firewall_schema_validation_spec.rb +45 -0
- data/spec/vcloud/edge_gateway/load_balancer_schema_validation_spec.rb +153 -0
- data/spec/vcloud/edge_gateway/nat_schema_validation_spec.rb +93 -0
- data/vcloud-edge_gateway.gemspec +32 -0
- metadata +252 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 HM Government (Government Digital Service)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# vCloud Edge Gateway
|
2
|
+
|
3
|
+
vCloud Edge Gateway is a tool that supports automated provisiong of a VMware vCloud Edge Gateway. It depends on [vCloud Core](https://github.com/alphagov/vcloud-core) and uses Fog under the hood.
|
4
|
+
|
5
|
+
|
6
|
+
#Configure edge gateway services
|
7
|
+
|
8
|
+
You can configure following services on an existing edgegateway using fog.
|
9
|
+
- FirewallService
|
10
|
+
- NatService
|
11
|
+
- LoadBalancerService
|
12
|
+
|
13
|
+
###How to configure:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require 'fog'
|
17
|
+
vcloud = Fog::Compute::VcloudDirector.new
|
18
|
+
vcloud.post_configure_edge_gateway_services edge_gateway_id, configuration
|
19
|
+
vcloud.process_task(task.body)
|
20
|
+
```
|
21
|
+
|
22
|
+
The Configuration contain definitions of any of the services listed.Details of service configurations may vary,
|
23
|
+
but the mechanism is the same for updating any Edge Gateway service.<br/>You can include one or more services when you configure an Edge Gateway.
|
24
|
+
|
25
|
+
###Examples:
|
26
|
+
|
27
|
+
Service examples, to be used in place of the `configuration` object above.
|
28
|
+
|
29
|
+
Firewall:
|
30
|
+
```ruby
|
31
|
+
configuration = {
|
32
|
+
:FirewallService => {
|
33
|
+
:IsEnabled => true,
|
34
|
+
:DefaultAction => 'allow',
|
35
|
+
:LogDefaultAction => false,
|
36
|
+
:FirewallRule => [
|
37
|
+
{
|
38
|
+
:Policy => 'allow',
|
39
|
+
:Description => 'description',
|
40
|
+
:Protocols => {:Tcp => true},
|
41
|
+
:Port => 22,
|
42
|
+
:DestinationPortRange => 22,
|
43
|
+
:DestinationIp => 'Internal',
|
44
|
+
:SourcePort => 22,
|
45
|
+
:SourceIp => 'External',
|
46
|
+
:SourcePortRange => '22'
|
47
|
+
}
|
48
|
+
]
|
49
|
+
}
|
50
|
+
}
|
51
|
+
```
|
52
|
+
|
53
|
+
Load balancer:
|
54
|
+
```ruby
|
55
|
+
configuration = {
|
56
|
+
:LoadBalancerService => {
|
57
|
+
:IsEnabled => "true",
|
58
|
+
:Pool => [
|
59
|
+
{
|
60
|
+
:Name => 'web-app',
|
61
|
+
:ServicePort => [
|
62
|
+
{
|
63
|
+
:IsEnabled => "true",
|
64
|
+
:Protocol => "HTTP",
|
65
|
+
:Algorithm => "ROUND_ROBIN",
|
66
|
+
:Port => 80,
|
67
|
+
:HealthCheckPort => 80,
|
68
|
+
:HealthCheck => {
|
69
|
+
:Mode => "HTTP", :HealthThreshold => 1, :UnhealthThreshold => 6, :Interval => 20, :Timeout => 25
|
70
|
+
}
|
71
|
+
},
|
72
|
+
{
|
73
|
+
:IsEnabled => true,
|
74
|
+
:Protocol => "HTTPS",
|
75
|
+
:Algorithm => "ROUND_ROBIN",
|
76
|
+
:Port => 443,
|
77
|
+
:HealthCheckPort => 443,
|
78
|
+
:HealthCheck => {
|
79
|
+
:Mode => "SSL", :HealthThreshold => 1, :UnhealthThreshold => 6, :Interval => 20, :Timeout => 25
|
80
|
+
}
|
81
|
+
}
|
82
|
+
],
|
83
|
+
:Member => [
|
84
|
+
{
|
85
|
+
:IpAddress => "192.0.2.0",
|
86
|
+
:Weight => 1,
|
87
|
+
:ServicePort => [
|
88
|
+
{:Protocol => "HTTP", :Port => 80, :HealthCheckPort => 80}
|
89
|
+
]
|
90
|
+
}
|
91
|
+
]
|
92
|
+
}
|
93
|
+
],
|
94
|
+
:VirtualServer => [
|
95
|
+
{
|
96
|
+
:IsEnabled => "true",
|
97
|
+
:Name => "app1",
|
98
|
+
:Description => "app1",
|
99
|
+
:Interface => {:name => "Default", :href => "https://vmware.api.net/api/admin/network/2ad93597-7b54-43dd-9eb1-631dd337e5a7"},
|
100
|
+
:IpAddress => '192.0.2.0',
|
101
|
+
:ServiceProfile => [
|
102
|
+
{:IsEnabled => "true", :Protocol => "HTTP", :Port => 80, :Persistence => {:Method => ""}},
|
103
|
+
{:IsEnabled => "true", :Protocol => "HTTPS", :Port => 443, :Persistence => {:Method => ""}}
|
104
|
+
],
|
105
|
+
:Logging => false,
|
106
|
+
:Pool => 'web-app'
|
107
|
+
}
|
108
|
+
]
|
109
|
+
}
|
110
|
+
}
|
111
|
+
```
|
112
|
+
|
113
|
+
Nat:
|
114
|
+
```ruby
|
115
|
+
configuration = {
|
116
|
+
:NatService => {
|
117
|
+
:IsEnabled => true,
|
118
|
+
:nat_type => 'ipTranslation',
|
119
|
+
:Policy => 'allowTrafficIn',
|
120
|
+
:NatRule => [
|
121
|
+
{
|
122
|
+
:Description => 'a snat rule',
|
123
|
+
:RuleType => 'SNAT',
|
124
|
+
:IsEnabled => true,
|
125
|
+
:Id => '65538',
|
126
|
+
:GatewayNatRule => {
|
127
|
+
:Interface => {
|
128
|
+
:name => 'nft00001',
|
129
|
+
:href => 'https://vmware.api.net/api/admin/network/44265cc3-6d63-4ea9-ac72-4905b5aa6111'
|
130
|
+
},
|
131
|
+
:OriginalIp => "192.0.2.0",
|
132
|
+
:TranslatedIp => "203.0.113.10"
|
133
|
+
}
|
134
|
+
},
|
135
|
+
{
|
136
|
+
:Description => 'a dnat rule',
|
137
|
+
:RuleType => 'DNAT',
|
138
|
+
:IsEnabled => true,
|
139
|
+
:Id => '65539',
|
140
|
+
:GatewayNatRule =>
|
141
|
+
{
|
142
|
+
:Interface => {
|
143
|
+
:name => 'nft00001',
|
144
|
+
:href => 'https://vmware.api.net/api/admin/network/44265cc3-6d63-4ea9-ac72-4905b5aa6111'
|
145
|
+
},
|
146
|
+
:Protocol => 'tcp',
|
147
|
+
:OriginalIp => "203.0.113.10",
|
148
|
+
:OriginalPort => 22,
|
149
|
+
:TranslatedIp => "192.0.2.0",
|
150
|
+
:TranslatedPort => 22
|
151
|
+
},
|
152
|
+
}
|
153
|
+
]
|
154
|
+
}
|
155
|
+
}
|
156
|
+
```
|
157
|
+
|
158
|
+
###Debug
|
159
|
+
|
160
|
+
Set environment variable DEBUG=true to see fog debug info.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
5
|
+
# Set a bogus Fog credential, otherwise it's possible for the unit
|
6
|
+
# tests to accidentially run (and succeed against!) an actual
|
7
|
+
# environment, if Fog connection is not stubbed correctly.
|
8
|
+
ENV['FOG_CREDENTIAL'] = 'random_nonsense_owiejfoweijf'
|
9
|
+
ENV['COVERAGE'] = 'true'
|
10
|
+
task.pattern = FileList['spec/vcloud/**/*_spec.rb']
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => [:spec]
|
14
|
+
|
15
|
+
RSpec::Core::RakeTask.new('integration') do |t|
|
16
|
+
t.pattern = FileList['spec/integration/**/*_spec.rb']
|
17
|
+
end
|
18
|
+
|
19
|
+
require "gem_publisher"
|
20
|
+
task :publish_gem do |t|
|
21
|
+
gem = GemPublisher.publish_if_updated("vcloud-edge_gateway.gemspec", :rubygems)
|
22
|
+
puts "Published #{gem}" if gem
|
23
|
+
end
|
data/bin/vcloud-edge
ADDED
data/jenkins.sh
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/bin/bash -x
|
2
|
+
set -e
|
3
|
+
bundle install --path "${HOME}/bundles/${JOB_NAME}"
|
4
|
+
bundle exec rake
|
5
|
+
|
6
|
+
./scripts/generate_fog_conf_file.sh
|
7
|
+
export FOG_RC=fog_integration_test.config
|
8
|
+
bundle exec rake integration
|
9
|
+
rm fog_integration_test.config
|
10
|
+
|
11
|
+
bundle exec rake publish_gem
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Vcloud
|
5
|
+
class ConfigLoader
|
6
|
+
|
7
|
+
def load_config(config_file, schema = nil)
|
8
|
+
input_config = YAML::load(File.open(config_file))
|
9
|
+
|
10
|
+
# There is no way in YAML or Ruby to symbolize keys in a hash
|
11
|
+
json_string = JSON.generate(input_config)
|
12
|
+
config = JSON.parse(json_string, :symbolize_names => true)
|
13
|
+
|
14
|
+
if schema
|
15
|
+
validation = ConfigValidator.validate(:base, config, schema)
|
16
|
+
unless validation.valid?
|
17
|
+
validation.errors.each do |error|
|
18
|
+
Vcloud::EdgeGateway.logger.fatal(error)
|
19
|
+
end
|
20
|
+
raise("Supplied configuration does not match supplied schema")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
config
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
module Vcloud
|
4
|
+
class ConfigValidator
|
5
|
+
|
6
|
+
attr_reader :key, :data, :schema, :type, :errors
|
7
|
+
|
8
|
+
VALID_ALPHABETICAL_VALUES_FOR_IP_RANGE = %w(Any external internal)
|
9
|
+
|
10
|
+
def initialize(key, data, schema)
|
11
|
+
raise "Nil schema" unless schema
|
12
|
+
raise "Invalid schema" unless schema.key?(:type)
|
13
|
+
@type = schema[:type].to_s.downcase
|
14
|
+
@errors = []
|
15
|
+
@data = data
|
16
|
+
@schema = schema
|
17
|
+
@key = key
|
18
|
+
validate
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
@errors.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.validate(key, data, schema)
|
26
|
+
new(key, data, schema)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate
|
32
|
+
self.send("validate_#{type}".to_sym)
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_string
|
36
|
+
unless @data.is_a? String
|
37
|
+
errors << "#{key}: #{@data} is not a string"
|
38
|
+
return
|
39
|
+
end
|
40
|
+
return unless check_emptyness_ok
|
41
|
+
return unless check_matcher_matches
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_string_or_number
|
45
|
+
unless data.is_a?(String) || data.is_a?(Numeric)
|
46
|
+
@errors << "#{key}: #{@data} is not a string_or_number"
|
47
|
+
return
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_ip_address
|
52
|
+
unless data.is_a?(String)
|
53
|
+
@errors << "#{key}: #{@data} is not a valid ip_address"
|
54
|
+
return
|
55
|
+
end
|
56
|
+
@errors << "#{key}: #{@data} is not a valid ip_address" unless valid_ip_address?(data)
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_ip_address_range
|
60
|
+
unless data.is_a?(String)
|
61
|
+
@errors << "#{key}: #{@data} is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."
|
62
|
+
return
|
63
|
+
end
|
64
|
+
valid = valid_cidr_or_ip_address? || valid_alphabetical_ip_range? || valid_ip_range?
|
65
|
+
@errors << "#{key}: #{@data} is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'." unless valid
|
66
|
+
end
|
67
|
+
|
68
|
+
def valid_cidr_or_ip_address?
|
69
|
+
begin
|
70
|
+
ip = IPAddr.new(data)
|
71
|
+
ip.ipv4?
|
72
|
+
rescue ArgumentError
|
73
|
+
false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def valid_alphabetical_ip_range?
|
78
|
+
VALID_ALPHABETICAL_VALUES_FOR_IP_RANGE.include?(data)
|
79
|
+
end
|
80
|
+
|
81
|
+
def valid_ip_address? ip_address
|
82
|
+
begin
|
83
|
+
#valid formats recognized by IPAddr are : “address”, “address/prefixlen” and “address/mask”.
|
84
|
+
# Attribute like member_ip in case of load-balancer is an "address"
|
85
|
+
# and we should not accept “address/prefixlen” and “address/mask” for such fields.
|
86
|
+
ip = IPAddr.new(ip_address)
|
87
|
+
ip.ipv4? && !ip_address.include?('/')
|
88
|
+
rescue ArgumentError
|
89
|
+
false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def valid_ip_range?
|
94
|
+
range_parts = data.split('-')
|
95
|
+
return false if range_parts.size != 2
|
96
|
+
start_address = range_parts.first
|
97
|
+
end_address = range_parts.last
|
98
|
+
valid_ip_address?(start_address) && valid_ip_address?(end_address) &&
|
99
|
+
valid_start_and_end_address_combination?(end_address, start_address)
|
100
|
+
end
|
101
|
+
|
102
|
+
def valid_start_and_end_address_combination?(end_address, start_address)
|
103
|
+
IPAddr.new(start_address) < IPAddr.new(end_address)
|
104
|
+
end
|
105
|
+
|
106
|
+
def validate_hash
|
107
|
+
unless data.is_a? Hash
|
108
|
+
@errors << "#{key}: is not a hash"
|
109
|
+
return
|
110
|
+
end
|
111
|
+
return unless check_emptyness_ok
|
112
|
+
check_for_unknown_parameters
|
113
|
+
if schema.key?(:internals)
|
114
|
+
internals = schema[:internals]
|
115
|
+
internals.each do |param_key,param_schema|
|
116
|
+
check_hash_parameter(param_key, param_schema)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def validate_array
|
122
|
+
unless data.is_a? Array
|
123
|
+
@errors << "#{key} is not an array"
|
124
|
+
return
|
125
|
+
end
|
126
|
+
return unless check_emptyness_ok
|
127
|
+
if schema.key?(:each_element_is)
|
128
|
+
element_schema = schema[:each_element_is]
|
129
|
+
data.each do |element|
|
130
|
+
sub_validator = ConfigValidator.validate(key, element, element_schema)
|
131
|
+
unless sub_validator.valid?
|
132
|
+
@errors = errors + sub_validator.errors
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def validate_enum
|
139
|
+
unless (acceptable_values = schema[:acceptable_values]) && acceptable_values.is_a?(Array)
|
140
|
+
raise "Must set :acceptable_values for type 'enum'"
|
141
|
+
end
|
142
|
+
unless acceptable_values.include?(data)
|
143
|
+
acceptable_values_string = acceptable_values.collect {|v| "'#{v}'" }.join(', ')
|
144
|
+
@errors << "#{key}: #{@data} is not a valid value. Acceptable values are #{acceptable_values_string}."
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def validate_boolean
|
149
|
+
unless [true, false].include?(data)
|
150
|
+
@errors << "#{key}: #{data} is not a valid boolean value."
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def check_emptyness_ok
|
155
|
+
unless schema.key?(:allowed_empty) && schema[:allowed_empty]
|
156
|
+
if data.empty?
|
157
|
+
@errors << "#{key}: cannot be empty #{type}"
|
158
|
+
return false
|
159
|
+
end
|
160
|
+
end
|
161
|
+
true
|
162
|
+
end
|
163
|
+
|
164
|
+
def check_matcher_matches
|
165
|
+
return unless regex = schema[:matcher]
|
166
|
+
raise "#{key}: #{regex} is not a Regexp" unless regex.is_a? Regexp
|
167
|
+
unless data =~ regex
|
168
|
+
@errors << "#{key}: #{data} does not match"
|
169
|
+
return false
|
170
|
+
end
|
171
|
+
true
|
172
|
+
end
|
173
|
+
|
174
|
+
def check_hash_parameter(sub_key, sub_schema)
|
175
|
+
if sub_schema.key?(:required) && sub_schema[:required] == false
|
176
|
+
# short circuit out if we do not have the key, but it's not required.
|
177
|
+
return true unless data.key?(sub_key)
|
178
|
+
end
|
179
|
+
unless data.key?(sub_key)
|
180
|
+
@errors << "#{key}: missing '#{sub_key}' parameter"
|
181
|
+
return false
|
182
|
+
end
|
183
|
+
sub_validator = ConfigValidator.validate(
|
184
|
+
sub_key,
|
185
|
+
data[sub_key],
|
186
|
+
sub_schema
|
187
|
+
)
|
188
|
+
unless sub_validator.valid?
|
189
|
+
@errors = errors + sub_validator.errors
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def check_for_unknown_parameters
|
194
|
+
unless internals = schema[:internals]
|
195
|
+
# if there are no parameters specified, then assume all are ok.
|
196
|
+
return true
|
197
|
+
end
|
198
|
+
if schema[:permit_unknown_parameters]
|
199
|
+
return true
|
200
|
+
end
|
201
|
+
data.keys.each do |k|
|
202
|
+
@errors << "#{key}: parameter '#{k}' is invalid" unless internals[k]
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Vcloud
|
2
|
+
module EdgeGateway
|
3
|
+
class ConfigurationDiffer
|
4
|
+
|
5
|
+
def initialize local, remote
|
6
|
+
@local = local
|
7
|
+
@remote = remote
|
8
|
+
end
|
9
|
+
|
10
|
+
def diff
|
11
|
+
( @local == @remote ) ? [] : HashDiff.diff(@local, @remote)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Vcloud
|
2
|
+
module EdgeGateway
|
3
|
+
module ConfigurationGenerator
|
4
|
+
class FirewallService
|
5
|
+
|
6
|
+
def generate_fog_config(input_config)
|
7
|
+
if input_config
|
8
|
+
firewall_service = {}
|
9
|
+
firewall_service[:IsEnabled] = input_config.key?(:enabled) ? input_config[:enabled].to_s : 'true'
|
10
|
+
firewall_service[:DefaultAction] = input_config.key?(:policy) ? input_config[:policy] : "drop"
|
11
|
+
firewall_service[:LogDefaultAction] = input_config.key?(:log_default_action) ? input_config[:log_default_action].to_s : 'false'
|
12
|
+
firewall_service[:FirewallRule] = populate_firewall_rules(input_config[:firewall_rules]) if input_config.key?(:firewall_rules)
|
13
|
+
firewall_service
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def populate_firewall_rules rules
|
19
|
+
i = ID_RANGES::FIREWALL_SERVICE[:min]
|
20
|
+
rules.collect do |rule|
|
21
|
+
new_rule = {}
|
22
|
+
new_rule[:Id] = rule.key?(:id) ? rule[:id] : i.to_s
|
23
|
+
new_rule[:IsEnabled] = rule.key?(:enabled) ? rule[:enabled].to_s : 'true'
|
24
|
+
new_rule[:MatchOnTranslate] = rule.key?(:match_on_translate) ? rule[:match_on_translate].to_s : 'false'
|
25
|
+
new_rule[:Description] = rule.key?(:description) ? rule[:description] : ""
|
26
|
+
new_rule[:Policy] = rule.key?(:policy) ? rule[:policy] : "allow"
|
27
|
+
new_rule[:Protocols] = rule.key?(:protocols) ? handle_protocols(rule[:protocols]) : {Tcp: 'true'}
|
28
|
+
new_rule[:DestinationPortRange] = rule.key?(:destination_port_range) ? rule[:destination_port_range] : 'Any'
|
29
|
+
new_rule[:Port] = handle_vmware_port_deprecation_behaviour(rule[:destination_port_range])
|
30
|
+
new_rule[:DestinationIp] = rule[:destination_ip]
|
31
|
+
new_rule[:SourcePortRange] = rule.key?(:source_port_range) ? rule[:source_port_range] : 'Any'
|
32
|
+
new_rule[:SourcePort] = handle_vmware_port_deprecation_behaviour(rule[:source_port_range])
|
33
|
+
new_rule[:SourceIp] = rule[:source_ip]
|
34
|
+
new_rule[:EnableLogging] = rule.key?(:enable_logging) ? rule[:enable_logging].to_s : 'false'
|
35
|
+
i += 1
|
36
|
+
new_rule
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_vmware_port_deprecation_behaviour(port_spec)
|
41
|
+
(port_spec.to_s =~ /^\d+$/) ? port_spec.to_s : '-1'
|
42
|
+
end
|
43
|
+
|
44
|
+
def handle_protocols(protocols)
|
45
|
+
case protocols.downcase
|
46
|
+
when "tcp+udp"
|
47
|
+
{Tcp: 'true', Udp: 'true'}
|
48
|
+
when "udp"
|
49
|
+
{Udp: 'true'}
|
50
|
+
when "tcp"
|
51
|
+
{Tcp: 'true'}
|
52
|
+
when "icmp"
|
53
|
+
{Icmp: 'true'}
|
54
|
+
when "any"
|
55
|
+
{Tcp: 'true', Udp: 'true', Icmp: 'true'}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|