vcloud-edge_gateway 0.0.1
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 +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
|