vcloud-core 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.0.9 (2014-03-10)
2
+
3
+ Features:
4
+
5
+ - adds a configuration loader and a configuration validator
6
+
1
7
  ## 0.0.8 (2014-03-04)
2
8
 
3
9
  Bugfix:
data/lib/vcloud/core.rb CHANGED
@@ -3,6 +3,8 @@ require 'vcloud/fog'
3
3
 
4
4
  require 'vcloud/core/version'
5
5
 
6
+ require 'vcloud/core/config_loader'
7
+ require 'vcloud/core/config_validator'
6
8
  require 'vcloud/core/entity'
7
9
  require 'vcloud/core/metadata_helper'
8
10
  require 'vcloud/core/compute_metadata'
@@ -0,0 +1,26 @@
1
+ module Vcloud
2
+ module Core
3
+ class ConfigLoader
4
+
5
+ def load_config(config_file, schema = nil)
6
+ input_config = YAML::load(File.open(config_file))
7
+
8
+ # There is no way in YAML or Ruby to symbolize keys in a hash
9
+ json_string = JSON.generate(input_config)
10
+ config = JSON.parse(json_string, :symbolize_names => true)
11
+
12
+ if schema
13
+ validation = Core::ConfigValidator.validate(:base, config, schema)
14
+ unless validation.valid?
15
+ validation.errors.each do |error|
16
+ Vcloud::Core.logger.fatal(error)
17
+ end
18
+ raise("Supplied configuration does not match supplied schema")
19
+ end
20
+ end
21
+ config
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,208 @@
1
+ require 'ipaddr'
2
+
3
+ module Vcloud
4
+ module Core
5
+ class ConfigValidator
6
+
7
+ attr_reader :key, :data, :schema, :type, :errors
8
+
9
+ VALID_ALPHABETICAL_VALUES_FOR_IP_RANGE = %w(Any external internal)
10
+
11
+ def initialize(key, data, schema)
12
+ raise "Nil schema" unless schema
13
+ raise "Invalid schema" unless schema.key?(:type)
14
+ @type = schema[:type].to_s.downcase
15
+ @errors = []
16
+ @data = data
17
+ @schema = schema
18
+ @key = key
19
+ validate
20
+ end
21
+
22
+ def valid?
23
+ @errors.empty?
24
+ end
25
+
26
+ def self.validate(key, data, schema)
27
+ new(key, data, schema)
28
+ end
29
+
30
+ private
31
+
32
+ def validate
33
+ self.send("validate_#{type}".to_sym)
34
+ end
35
+
36
+ def validate_string
37
+ unless @data.is_a? String
38
+ errors << "#{key}: #{@data} is not a string"
39
+ return
40
+ end
41
+ return unless check_emptyness_ok
42
+ return unless check_matcher_matches
43
+ end
44
+
45
+ def validate_string_or_number
46
+ unless data.is_a?(String) || data.is_a?(Numeric)
47
+ @errors << "#{key}: #{@data} is not a string_or_number"
48
+ return
49
+ end
50
+ end
51
+
52
+ def validate_ip_address
53
+ unless data.is_a?(String)
54
+ @errors << "#{key}: #{@data} is not a valid ip_address"
55
+ return
56
+ end
57
+ @errors << "#{key}: #{@data} is not a valid ip_address" unless valid_ip_address?(data)
58
+ end
59
+
60
+ def validate_ip_address_range
61
+ unless data.is_a?(String)
62
+ @errors << "#{key}: #{@data} is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."
63
+ return
64
+ end
65
+ valid = valid_cidr_or_ip_address? || valid_alphabetical_ip_range? || valid_ip_range?
66
+ @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
67
+ end
68
+
69
+ def valid_cidr_or_ip_address?
70
+ begin
71
+ ip = IPAddr.new(data)
72
+ ip.ipv4?
73
+ rescue ArgumentError
74
+ false
75
+ end
76
+ end
77
+
78
+ def valid_alphabetical_ip_range?
79
+ VALID_ALPHABETICAL_VALUES_FOR_IP_RANGE.include?(data)
80
+ end
81
+
82
+ def valid_ip_address? ip_address
83
+ begin
84
+ #valid formats recognized by IPAddr are : “address”, “address/prefixlen” and “address/mask”.
85
+ # Attribute like member_ip in case of load-balancer is an "address"
86
+ # and we should not accept “address/prefixlen” and “address/mask” for such fields.
87
+ ip = IPAddr.new(ip_address)
88
+ ip.ipv4? && !ip_address.include?('/')
89
+ rescue ArgumentError
90
+ false
91
+ end
92
+ end
93
+
94
+ def valid_ip_range?
95
+ range_parts = data.split('-')
96
+ return false if range_parts.size != 2
97
+ start_address = range_parts.first
98
+ end_address = range_parts.last
99
+ valid_ip_address?(start_address) && valid_ip_address?(end_address) &&
100
+ valid_start_and_end_address_combination?(end_address, start_address)
101
+ end
102
+
103
+ def valid_start_and_end_address_combination?(end_address, start_address)
104
+ IPAddr.new(start_address) < IPAddr.new(end_address)
105
+ end
106
+
107
+ def validate_hash
108
+ unless data.is_a? Hash
109
+ @errors << "#{key}: is not a hash"
110
+ return
111
+ end
112
+ return unless check_emptyness_ok
113
+ check_for_unknown_parameters
114
+ if schema.key?(:internals)
115
+ internals = schema[:internals]
116
+ internals.each do |param_key,param_schema|
117
+ check_hash_parameter(param_key, param_schema)
118
+ end
119
+ end
120
+ end
121
+
122
+ def validate_array
123
+ unless data.is_a? Array
124
+ @errors << "#{key} is not an array"
125
+ return
126
+ end
127
+ return unless check_emptyness_ok
128
+ if schema.key?(:each_element_is)
129
+ element_schema = schema[:each_element_is]
130
+ data.each do |element|
131
+ sub_validator = ConfigValidator.validate(key, element, element_schema)
132
+ unless sub_validator.valid?
133
+ @errors = errors + sub_validator.errors
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ def validate_enum
140
+ unless (acceptable_values = schema[:acceptable_values]) && acceptable_values.is_a?(Array)
141
+ raise "Must set :acceptable_values for type 'enum'"
142
+ end
143
+ unless acceptable_values.include?(data)
144
+ acceptable_values_string = acceptable_values.collect {|v| "'#{v}'" }.join(', ')
145
+ @errors << "#{key}: #{@data} is not a valid value. Acceptable values are #{acceptable_values_string}."
146
+ end
147
+ end
148
+
149
+ def validate_boolean
150
+ unless [true, false].include?(data)
151
+ @errors << "#{key}: #{data} is not a valid boolean value."
152
+ end
153
+ end
154
+
155
+ def check_emptyness_ok
156
+ unless schema.key?(:allowed_empty) && schema[:allowed_empty]
157
+ if data.empty?
158
+ @errors << "#{key}: cannot be empty #{type}"
159
+ return false
160
+ end
161
+ end
162
+ true
163
+ end
164
+
165
+ def check_matcher_matches
166
+ return unless regex = schema[:matcher]
167
+ raise "#{key}: #{regex} is not a Regexp" unless regex.is_a? Regexp
168
+ unless data =~ regex
169
+ @errors << "#{key}: #{data} does not match"
170
+ return false
171
+ end
172
+ true
173
+ end
174
+
175
+ def check_hash_parameter(sub_key, sub_schema)
176
+ if sub_schema.key?(:required) && sub_schema[:required] == false
177
+ # short circuit out if we do not have the key, but it's not required.
178
+ return true unless data.key?(sub_key)
179
+ end
180
+ unless data.key?(sub_key)
181
+ @errors << "#{key}: missing '#{sub_key}' parameter"
182
+ return false
183
+ end
184
+ sub_validator = ConfigValidator.validate(
185
+ sub_key,
186
+ data[sub_key],
187
+ sub_schema
188
+ )
189
+ unless sub_validator.valid?
190
+ @errors = errors + sub_validator.errors
191
+ end
192
+ end
193
+
194
+ def check_for_unknown_parameters
195
+ unless internals = schema[:internals]
196
+ # if there are no parameters specified, then assume all are ok.
197
+ return true
198
+ end
199
+ if schema[:permit_unknown_parameters]
200
+ return true
201
+ end
202
+ data.keys.each do |k|
203
+ @errors << "#{key}: parameter '#{k}' is invalid" unless internals[k]
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -1,5 +1,5 @@
1
1
  module Vcloud
2
2
  module Core
3
- VERSION = '0.0.8'
3
+ VERSION = '0.0.9'
4
4
  end
5
5
  end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ module Vcloud
4
+ module Core
5
+ describe ConfigLoader do
6
+
7
+ before(:all) do
8
+ @data_dir = File.join(File.dirname(__FILE__), "/data")
9
+ end
10
+
11
+ it "should create a valid hash when input is JSON" do
12
+ input_file = "#{@data_dir}/working.json"
13
+ loader = ConfigLoader.new
14
+ actual_config = loader.load_config(input_file)
15
+ valid_config.should eq(actual_config)
16
+ end
17
+
18
+ it "should create a valid hash when input is YAML" do
19
+ input_file = "#{@data_dir}/working.yaml"
20
+ loader = ConfigLoader.new
21
+ actual_config = loader.load_config(input_file)
22
+ valid_config.should eq(actual_config)
23
+ end
24
+
25
+ it "should create a valid hash when input is YAML with anchor defaults" do
26
+ input_file = "#{@data_dir}/working_with_defaults.yaml"
27
+ loader = ConfigLoader.new
28
+ actual_config = loader.load_config(input_file)
29
+ valid_config['vapps'].should eq(actual_config['vapps'])
30
+ end
31
+
32
+ it "should validate correctly against a schema" do
33
+ input_file = "#{@data_dir}/working_with_defaults.yaml"
34
+ loader = ConfigLoader.new
35
+ schema = vapp_config_schema
36
+ actual_config = loader.load_config(input_file, schema)
37
+ valid_config['vapps'].should eq(actual_config['vapps'])
38
+ end
39
+
40
+ it "should raise an error if checked against an invalid schema" do
41
+ input_file = "#{@data_dir}/working_with_defaults.yaml"
42
+ loader = ConfigLoader.new
43
+ Vcloud::Core.logger.should_receive(:fatal).with("vapps: is not a hash")
44
+ expect { loader.load_config(input_file, invalid_schema) }.
45
+ to raise_error('Supplied configuration does not match supplied schema')
46
+ end
47
+
48
+ def vapp_config_schema
49
+ {
50
+ type: 'hash',
51
+ allowed_empty: false,
52
+ permit_unknown_parameters: true,
53
+ internals: {
54
+ vapps: {
55
+ type: 'array',
56
+ required: false,
57
+ allowed_empty: true,
58
+ },
59
+ }
60
+ }
61
+ end
62
+
63
+ def invalid_schema
64
+ {
65
+ type: Hash,
66
+ permit_unknown_parameters: true,
67
+ internals: {
68
+ vapps: { type: Hash },
69
+ }
70
+ }
71
+ end
72
+
73
+ def valid_config
74
+ {
75
+ :vapps=>[{
76
+ :name=>"vapp-vcloud-tools-tests",
77
+ :vdc_name=>"VDC_NAME",
78
+ :catalog=>"CATALOG_NAME",
79
+ :catalog_item=>"CATALOG_ITEM",
80
+ :vm=>{
81
+ :hardware_config=>{:memory=>"4096", :cpu=>"2"},
82
+ :extra_disks=>[{:size=>"8192"}],
83
+ :network_connections=>[{
84
+ :name=>"Default",
85
+ :ip_address=>"192.168.2.10"
86
+ },
87
+ {
88
+ :name=>"NetworkTest2",
89
+ :ip_address=>"192.168.1.10"
90
+ }],
91
+ :bootstrap=>{
92
+ :script_path=>"spec/data/basic_preamble_test.erb",
93
+ :vars=>{:message=>"hello world"}
94
+ },
95
+ :metadata=>{}
96
+ }
97
+ }]
98
+ }
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,572 @@
1
+ require 'spec_helper'
2
+
3
+ module Vcloud
4
+ module Core
5
+ describe ConfigValidator do
6
+
7
+ context "sanitize type" do
8
+
9
+ it "should be ok with type as bare String" do
10
+ data = "hello world"
11
+ schema = { type: String }
12
+ v = ConfigValidator.validate(:base, data, schema)
13
+ expect(v.valid?).to be_true
14
+ end
15
+
16
+ it "should be ok with type as string 'String'" do
17
+ data = "hello world"
18
+ schema = { type: 'String' }
19
+ v = ConfigValidator.validate(:base, data, schema)
20
+ expect(v.valid?).to be_true
21
+ end
22
+
23
+ it "should be ok with type as string 'string'" do
24
+ data = "hello world"
25
+ schema = { type: 'string' }
26
+ v = ConfigValidator.validate(:base, data, schema)
27
+ expect(v.valid?).to be_true
28
+ end
29
+
30
+ end
31
+
32
+ context "string validations" do
33
+
34
+ it "should validate a basic string" do
35
+ data = "hello world"
36
+ schema = { type: 'string' }
37
+ v = ConfigValidator.validate(:base, data, schema)
38
+ expect(v.valid?).to be_true
39
+ end
40
+
41
+ it "should not validate a number as a basic string" do
42
+ data = 42
43
+ schema = { type: 'string' }
44
+ v = ConfigValidator.validate(:base, data, schema)
45
+ expect(v.valid?).to be_false
46
+ end
47
+
48
+ it "should log error with number as a basic string" do
49
+ data = 42
50
+ schema = { type: 'string' }
51
+ v = ConfigValidator.validate(:base, data, schema)
52
+ expect(v.errors).to eq([ 'base: 42 is not a string'] )
53
+ end
54
+
55
+ it "should return error with empty string (by default)" do
56
+ data = ""
57
+ schema = { type: 'string' }
58
+ v = ConfigValidator.validate(:base, data, schema)
59
+ expect(v.errors).to eq([ 'base: cannot be empty string'] )
60
+ end
61
+
62
+ it "should return error with empty string with allowed_empty: false)" do
63
+ data = ""
64
+ schema = { type: 'string', allowed_empty: false }
65
+ v = ConfigValidator.validate(:base, data, schema)
66
+ expect(v.errors).to eq([ 'base: cannot be empty string'] )
67
+ end
68
+
69
+ it "should validate ok with empty string with allowed_empty: true)" do
70
+ data = ""
71
+ schema = { type: 'string', allowed_empty: true }
72
+ v = ConfigValidator.validate(:base, data, schema)
73
+ expect(v.valid?).to be_true
74
+ end
75
+
76
+ it "should validate ok with a :matcher regex specified" do
77
+ data = "name-1234"
78
+ schema = { type: 'string', matcher: /^name-\d+$/ }
79
+ v = ConfigValidator.validate(:base, data, schema)
80
+ expect(v.valid?).to be_true
81
+ end
82
+
83
+ it "should return errror with a :matcher regex not matching" do
84
+ data = "name-123a"
85
+ schema = { type: 'string', matcher: /^name-\d+$/ }
86
+ v = ConfigValidator.validate(:base, data, schema)
87
+ expect(v.errors).to eq(['base: name-123a does not match'])
88
+ end
89
+
90
+ end
91
+
92
+ context "hash validations" do
93
+
94
+ it "should validate a basic hash" do
95
+ data = { name: "santa", address: "north pole" }
96
+ schema = {
97
+ type: "Hash",
98
+ internals: {
99
+ name: { type: 'string' },
100
+ address: { type: 'string' },
101
+ }
102
+ }
103
+ v = ConfigValidator.validate(:base, data, schema)
104
+ expect(v.valid?).to be_true
105
+ end
106
+
107
+ it "should not validate a bogus hash" do
108
+ data = { name: 42, address: 42 }
109
+ schema = {
110
+ type: "Hash",
111
+ internals: {
112
+ name: { type: "string" },
113
+ address: { type: "string" },
114
+ }
115
+ }
116
+ v = ConfigValidator.validate(:base, data, schema)
117
+ expect(v.valid?).to be_false
118
+ end
119
+
120
+ it "should return correct errors validating a bogus hash" do
121
+ data = { name: 42, address: 42 }
122
+ schema = {
123
+ type: "Hash",
124
+ internals: {
125
+ name: { type: "string" },
126
+ address: { type: "string" },
127
+ }
128
+ }
129
+ v = ConfigValidator.validate(:base, data, schema)
130
+ expect(v.errors).to eq([
131
+ "name: 42 is not a string",
132
+ "address: 42 is not a string",
133
+ ])
134
+ end
135
+
136
+ it "should return error with empty hash (by default)" do
137
+ data = {}
138
+ schema = { type: 'hash' }
139
+ v = ConfigValidator.validate(:base, data, schema)
140
+ expect(v.errors).to eq([ 'base: cannot be empty hash'] )
141
+ end
142
+
143
+ it "should return error with empty hash with allowed_empty: false)" do
144
+ data = {}
145
+ schema = { type: 'hash', allowed_empty: false }
146
+ v = ConfigValidator.validate(:base, data, schema)
147
+ expect(v.errors).to eq([ 'base: cannot be empty hash'] )
148
+ end
149
+
150
+ it "should validate ok with empty hash with allowed_empty: true)" do
151
+ data = {}
152
+ schema = { type: 'hash', allowed_empty: true }
153
+ v = ConfigValidator.validate(:base, data, schema)
154
+ expect(v.valid?).to be_true
155
+ end
156
+
157
+ it "should validate ok with a missing parameter, when marked :required => false" do
158
+ data = {
159
+ name: 'hello'
160
+ }
161
+ schema = {
162
+ type: 'hash',
163
+ internals: {
164
+ name: { type: 'string' },
165
+ optional_param: { type: 'string', required: false },
166
+ }
167
+ }
168
+ v = ConfigValidator.validate(:base, data, schema)
169
+ expect(v.valid?).to be_true
170
+ end
171
+
172
+ it "should return error with a missing :required => true param" do
173
+ data = {
174
+ name: 'hello'
175
+ }
176
+ schema = {
177
+ type: 'hash',
178
+ internals: {
179
+ name: { type: 'string' },
180
+ not_optional_param: { type: 'string', required: true },
181
+ }
182
+ }
183
+ v = ConfigValidator.validate(:base, data, schema)
184
+ expect(v.errors).to eq(["base: missing 'not_optional_param' parameter"])
185
+ end
186
+
187
+ it "should return error if a bogus parameter is specified" do
188
+ data = {
189
+ name: 'hello',
190
+ bogus_parameter: [ 'wibble' ],
191
+ bogus_parameter2: 'hello',
192
+ }
193
+ schema = {
194
+ type: 'hash',
195
+ internals: {
196
+ name: { type: 'string' },
197
+ },
198
+ }
199
+ v = ConfigValidator.validate(:base, data, schema)
200
+ expect(v.errors).to eq([
201
+ "base: parameter 'bogus_parameter' is invalid",
202
+ "base: parameter 'bogus_parameter2' is invalid",
203
+ ])
204
+ end
205
+
206
+ it "should validate ok if a bogus parameter is specified, when :permit_unknown_parameters is true" do
207
+ data = {
208
+ name: 'hello',
209
+ bogus_parameter: [ 'wibble' ],
210
+ bogus_parameter2: 'hello',
211
+ }
212
+ schema = {
213
+ type: 'hash',
214
+ permit_unknown_parameters: true,
215
+ internals: {
216
+ name: { type: 'string' },
217
+ },
218
+ }
219
+ v = ConfigValidator.validate(:base, data, schema)
220
+ expect(v.valid?).to be_true
221
+ end
222
+
223
+ end
224
+
225
+ context "array validations" do
226
+
227
+ it "should validate a basic array" do
228
+ data = [ "santa", "north pole" ]
229
+ schema = {
230
+ type: "Array",
231
+ each_element_is: { type: "string" }
232
+ }
233
+ v = ConfigValidator.validate(:base, data, schema)
234
+ expect(v.valid?).to be_true
235
+ end
236
+
237
+ it "should validate a bogus array" do
238
+ data = [ 42, 43 ]
239
+ schema = {
240
+ type: "Array",
241
+ each_element_is: { type: "string" }
242
+ }
243
+ v = ConfigValidator.validate(:base, data, schema)
244
+ expect(v.valid?).to be_false
245
+ end
246
+
247
+ it "should return correct errors validating a bogus array" do
248
+ data = [ 42, 43 ]
249
+ schema = {
250
+ type: "Array",
251
+ each_element_is: { type: "string" }
252
+ }
253
+ v = ConfigValidator.validate(:base, data, schema)
254
+ expect(v.errors).to eq([
255
+ "base: 42 is not a string",
256
+ "base: 43 is not a string",
257
+ ])
258
+ end
259
+
260
+ it "should return error with empty array (by default)" do
261
+ data = []
262
+ schema = { type: 'array' }
263
+ v = ConfigValidator.validate(:base, data, schema)
264
+ expect(v.errors).to eq([ 'base: cannot be empty array'] )
265
+ end
266
+
267
+ it "should return error with empty array with allowed_empty: false)" do
268
+ data = []
269
+ schema = { type: 'array', allowed_empty: false }
270
+ v = ConfigValidator.validate(:base, data, schema)
271
+ expect(v.errors).to eq([ 'base: cannot be empty array'] )
272
+ end
273
+
274
+ it "should validate ok with empty array with allowed_empty: true)" do
275
+ data = []
276
+ schema = { type: 'array', allowed_empty: true }
277
+ v = ConfigValidator.validate(:base, data, schema)
278
+ expect(v.valid?).to be_true
279
+ end
280
+
281
+ end
282
+
283
+ context "array of hashes validations" do
284
+
285
+ it "should validate an array of hashes" do
286
+ data = [
287
+ { name: "santa", address: "north pole" },
288
+ { name: "mole", address: "1 hole street" },
289
+ ]
290
+ schema = {
291
+ type: "array",
292
+ each_element_is: {
293
+ type: "hash",
294
+ internals: {
295
+ name: { type: 'string' },
296
+ address: { type: 'string' },
297
+ }
298
+ }
299
+ }
300
+ v = ConfigValidator.validate(:base, data, schema)
301
+ expect(v.valid?).to be_true
302
+ end
303
+
304
+ it "should correctly error on an invalid an array of hashes" do
305
+ data = [
306
+ { name: "santa", address: [] },
307
+ { name: 43, address: "1 hole street" },
308
+ ]
309
+ schema = {
310
+ type: "array",
311
+ each_element_is: {
312
+ type: "hash",
313
+ internals: {
314
+ name: { type: 'string' },
315
+ address: { type: 'string' },
316
+ }
317
+ }
318
+ }
319
+ v = ConfigValidator.validate(:base, data, schema)
320
+ expect(v.errors).to eq([
321
+ "address: [] is not a string",
322
+ "name: 43 is not a string",
323
+ ])
324
+ end
325
+
326
+ end
327
+
328
+ context "hash of arrays validations" do
329
+
330
+ it "should validate a hash of arrays" do
331
+ data = {
332
+ boys_names: [ 'bob', 'andrew', 'charlie', 'dave' ],
333
+ girls_names: [ 'alice', 'beth', 'carol', 'davina' ],
334
+ }
335
+ schema = {
336
+ type: "Hash",
337
+ internals: {
338
+ boys_names: {
339
+ type: "Array",
340
+ each_element_is: { type: 'String' }
341
+ },
342
+ girls_names: {
343
+ type: "Array",
344
+ each_element_is: { type: 'String' }
345
+ }
346
+ }
347
+ }
348
+ v = ConfigValidator.validate(:base, data, schema)
349
+ expect(v.valid?).to be_true
350
+ end
351
+
352
+ it "should correctly error on an invalid hash of arrays" do
353
+ data = {
354
+ boys_names: [ 'bob', 'andrew', 'charlie', 'dave' ],
355
+ girls_names: [ 'alice', 'beth', 'carol', 'davina' ],
356
+ }
357
+ schema = {
358
+ type: "Hash",
359
+ internals: {
360
+ boys_names: {
361
+ type: "Array",
362
+ each_element_is: { type: 'String' },
363
+ },
364
+ girls_names: {
365
+ type: "Array",
366
+ each_element_is: { type: 'String' },
367
+ }
368
+ },
369
+ }
370
+ v = ConfigValidator.validate(:base, data, schema)
371
+ expect(v.valid?).to be_true
372
+ end
373
+
374
+ end
375
+
376
+ context "string_or_number validations" do
377
+
378
+ it "should correctly validate an Integer" do
379
+ data = 2
380
+ schema = { type: 'string_or_number' }
381
+ v = ConfigValidator.validate(:base, data, schema)
382
+ expect(v.valid?).to be_true
383
+ end
384
+
385
+ it "should correctly validate a String" do
386
+ data = '2'
387
+ schema = { type: 'string_or_number' }
388
+ v = ConfigValidator.validate(:base, data, schema)
389
+ expect(v.valid?).to be_true
390
+ end
391
+
392
+ it "should correctly error if not a string or numeric" do
393
+ data = []
394
+ schema = { type: 'string_or_number' }
395
+ v = ConfigValidator.validate(:base, data, schema)
396
+ expect(v.errors).to eq(["base: [] is not a string_or_number"])
397
+ end
398
+
399
+ end
400
+
401
+ context "ip_address validations" do
402
+
403
+ it "should correctly validate an IP address" do
404
+ data = '192.168.100.100'
405
+ schema = { type: 'ip_address' }
406
+ v = ConfigValidator.validate(:base, data, schema)
407
+ expect(v.valid?).to be_true
408
+ end
409
+
410
+ it "should correctly error on an invalid IP address" do
411
+ data = '256.168.100.100'
412
+ schema = { type: 'ip_address' }
413
+ v = ConfigValidator.validate(:base, data, schema)
414
+ expect(v.errors).to eq(['base: 256.168.100.100 is not a valid ip_address'])
415
+ end
416
+
417
+ it "should error if ip address have wrong octets" do
418
+ data = '192.168.100.100/33/33/33'
419
+ schema = { type: 'ip_address' }
420
+ v = ConfigValidator.validate(:base, data, schema)
421
+ expect(v.errors).to eq(['base: 192.168.100.100/33/33/33 is not a valid ip_address'])
422
+ end
423
+
424
+ end
425
+
426
+ context "ip_address_range validations" do
427
+ context "validate CIDR" do
428
+ it "should validate OK if CIDR is correct" do
429
+ data = '192.168.100.100/24'
430
+ schema = { type: 'ip_address_range' }
431
+ v = ConfigValidator.validate(:base, data, schema)
432
+ expect(v.valid?).to be_true
433
+ end
434
+
435
+ it "should return error if network bit value is greater than 32" do
436
+ data = '192.168.100.100/33'
437
+ schema = { type: 'ip_address_range' }
438
+ v = ConfigValidator.validate(:base, data, schema)
439
+ expect(v.valid?).to be_false
440
+ expect(v.errors).to eq(["base: 192.168.100.100/33 is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."])
441
+ end
442
+
443
+ it "should return error if network bit value is less than 0" do
444
+ data = '192.168.100.100/33'
445
+ schema = { type: 'ip_address_range' }
446
+ v = ConfigValidator.validate(:base, data, schema)
447
+ expect(v.valid?).to be_false
448
+ expect(v.errors).to eq(["base: 192.168.100.100/33 is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."])
449
+ end
450
+
451
+ it "should return error if network IP address is incorrect" do
452
+ data = '192.168.100./33'
453
+ schema = { type: 'ip_address_range' }
454
+ v = ConfigValidator.validate(:base, data, schema)
455
+ expect(v.valid?).to be_false
456
+ expect(v.errors).to eq(["base: 192.168.100./33 is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."])
457
+ end
458
+ end
459
+
460
+ context "validate alphabetical values for IP range" do
461
+ %w(Any internal external).each do |data|
462
+ it "should validate OK if IP range is '#{data}'" do
463
+ schema = { type: 'ip_address_range' }
464
+ v = ConfigValidator.validate(:base, data, schema)
465
+ expect(v.valid?).to be_true
466
+ expect(v.errors).to be_empty
467
+ end
468
+ end
469
+
470
+ it "should error if IP range is a string but not a valid alphabetical value" do
471
+ data = 'invalid_ip_range_string'
472
+ schema = { type: 'ip_address_range' }
473
+ v = ConfigValidator.validate(:base, data, schema)
474
+ expect(v.valid?).to be_false
475
+ expect(v.errors).to eq(["base: invalid_ip_range_string is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."])
476
+ end
477
+ end
478
+
479
+ context "validate ranges specified using start and end addresses" do
480
+ it "should validate ok if the combination of start IP and end IP is correct" do
481
+ data = '192.168.100.100-192.168.100.110'
482
+ schema = { type: 'ip_address_range' }
483
+ v = ConfigValidator.validate(:base, data, schema)
484
+ expect(v.valid?).to be_true
485
+ expect(v.errors).to be_empty
486
+ end
487
+
488
+ it "should error if start IP address is incorrect" do
489
+ data = '192.168.100-192.168.100.110'
490
+ schema = { type: 'ip_address_range' }
491
+ v = ConfigValidator.validate(:base, data, schema)
492
+ expect(v.valid?).to be_false
493
+ expect(v.errors).to eq(["base: 192.168.100-192.168.100.110 is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."])
494
+ end
495
+
496
+ it "should error if end IP address is incorrect" do
497
+ data = '192.168.100.110-192.168.100'
498
+ schema = { type: 'ip_address_range' }
499
+ v = ConfigValidator.validate(:base, data, schema)
500
+ expect(v.valid?).to be_false
501
+ expect(v.errors).to eq(["base: 192.168.100.110-192.168.100 is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."])
502
+ end
503
+
504
+ it "should error if the combination of start IP and end IP is incorrect" do
505
+ data = '200.168.100.99-192.168.100'
506
+ schema = { type: 'ip_address_range' }
507
+ v = ConfigValidator.validate(:base, data, schema)
508
+ expect(v.valid?).to be_false
509
+ expect(v.errors).to eq(["base: 200.168.100.99-192.168.100 is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."])
510
+ end
511
+
512
+ it "should error if the start and end IPS are not separated by -" do
513
+ data = '190.168.100.99:192.168.100'
514
+ schema = { type: 'ip_address_range' }
515
+ v = ConfigValidator.validate(:base, data, schema)
516
+ expect(v.valid?).to be_false
517
+ expect(v.errors).to eq(["base: 190.168.100.99:192.168.100 is not a valid IP address range. Valid values can be IP address, CIDR, IP range, 'Any','internal' and 'external'."])
518
+ end
519
+ end
520
+
521
+ it "should accept single ip address as range" do
522
+ data = '190.168.100.99'
523
+ schema = { type: 'ip_address_range' }
524
+ v = ConfigValidator.validate(:base, data, schema)
525
+ expect(v.valid?).to be_true
526
+ expect(v.errors).to eq([])
527
+ end
528
+ end
529
+
530
+ context "enum validations" do
531
+ it "should error if enum value is not present in list" do
532
+ data = 'blah'
533
+ schema = { type: 'enum', required: false, acceptable_values: ['allow', 'decline', 'none']}
534
+ v = ConfigValidator.validate(:base, data, schema)
535
+ expect(v.errors).to eq(["base: blah is not a valid value. Acceptable values are 'allow', 'decline', 'none'."])
536
+ end
537
+
538
+ it "should raise error if enum schema does not contain acceptable_values" do
539
+ data = 'blah'
540
+ schema = { type: 'enum', required: false}
541
+ expect{ ConfigValidator.validate(:base, data, schema) }.to raise_error("Must set :acceptable_values for type 'enum'")
542
+ end
543
+
544
+ it "should validate ok if enum is acceptable" do
545
+ data = 'allow'
546
+ schema = { type: 'enum', required: false, acceptable_values: ['allow', 'decline', 'none']}
547
+ v = ConfigValidator.validate(:base, data, schema)
548
+ expect(v.valid?).to be_true
549
+ end
550
+ end
551
+
552
+ context "boolean validations" do
553
+ it "should error if boolean value is not valid" do
554
+ data = 'blah'
555
+ schema = { type: 'boolean' }
556
+ v = ConfigValidator.validate(:base, data, schema)
557
+ expect(v.errors).to eq(["base: blah is not a valid boolean value."])
558
+ end
559
+
560
+ [true, false].each do |boolean_value|
561
+ it "should validate ok if value is #{boolean_value}" do
562
+ schema = { type: 'boolean' }
563
+ v = ConfigValidator.validate(:base, boolean_value, schema)
564
+ expect(v.valid?).to be_true
565
+ end
566
+ end
567
+
568
+ end
569
+
570
+ end
571
+ end
572
+ end
@@ -0,0 +1,21 @@
1
+ {
2
+ "vapps":[{
3
+ "name":"vapp-vcloud-tools-tests",
4
+ "vdc_name":"VDC_NAME",
5
+ "catalog":"CATALOG_NAME",
6
+ "catalog_item":"CATALOG_ITEM",
7
+ "vm":{
8
+ "hardware_config":{"memory":"4096", "cpu":"2"},
9
+ "extra_disks":[{"size":"8192"}],
10
+ "network_connections":[
11
+ {"name":"Default",
12
+ "ip_address":"192.168.2.10"},
13
+ {"name":"NetworkTest2",
14
+ "ip_address":"192.168.1.10"}
15
+ ],
16
+ "bootstrap":{"script_path":"spec/data/basic_preamble_test.erb",
17
+ "vars":{"message":"hello world"}},
18
+ "metadata":{}
19
+ }
20
+ }]
21
+ }
@@ -0,0 +1,22 @@
1
+ ---
2
+ vapps:
3
+ - name: vapp-vcloud-tools-tests
4
+ vdc_name: VDC_NAME
5
+ catalog: CATALOG_NAME
6
+ catalog_item: CATALOG_ITEM
7
+ vm:
8
+ hardware_config:
9
+ memory: '4096'
10
+ cpu: '2'
11
+ extra_disks:
12
+ - size: '8192'
13
+ network_connections:
14
+ - name: Default
15
+ ip_address: 192.168.2.10
16
+ - name: NetworkTest2
17
+ ip_address: 192.168.1.10
18
+ bootstrap:
19
+ script_path: 'spec/data/basic_preamble_test.erb'
20
+ vars:
21
+ message: 'hello world'
22
+ metadata: {}
@@ -0,0 +1,25 @@
1
+ ---
2
+ anchors:
3
+ - &VDC_NAME dcs-dev
4
+
5
+ vapps:
6
+ - name: vapp-vcloud-tools-tests
7
+ vdc_name: *VDC_NAME
8
+ catalog: CATALOG_NAME
9
+ catalog_item: CATALOG_ITEM
10
+ vm:
11
+ hardware_config:
12
+ memory: '4096'
13
+ cpu: '2'
14
+ extra_disks:
15
+ - size: '8192'
16
+ network_connections:
17
+ - name: Default
18
+ ip_address: 192.168.2.10
19
+ - name: NetworkTest2
20
+ ip_address: 192.168.1.10
21
+ bootstrap:
22
+ script_path: 'spec/data/basic_preamble_test.erb'
23
+ vars:
24
+ message: 'hello world'
25
+ metadata: {}
@@ -9,7 +9,7 @@ module Vcloud
9
9
  @vapp_id = 'vapp-4321'
10
10
  @vapp_name = 'test-vapp-1'
11
11
  @vm_name = 'test-vm-1'
12
- @data_dir = File.join(File.dirname(__FILE__), "../data")
12
+ @data_dir = File.join(File.dirname(__FILE__), "/data")
13
13
  @mock_vm_memory_size = 1024
14
14
  @mock_metadata = {
15
15
  :foo => "bar",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vcloud-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-04 00:00:00.000000000 Z
12
+ date: 2014-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog
@@ -126,6 +126,8 @@ files:
126
126
  - jenkins.sh
127
127
  - lib/vcloud/core.rb
128
128
  - lib/vcloud/core/compute_metadata.rb
129
+ - lib/vcloud/core/config_loader.rb
130
+ - lib/vcloud/core/config_validator.rb
129
131
  - lib/vcloud/core/edge_gateway.rb
130
132
  - lib/vcloud/core/edge_gateway_interface.rb
131
133
  - lib/vcloud/core/entity.rb
@@ -146,6 +148,13 @@ files:
146
148
  - spec/integration/edge_gateway/edge_gateway_spec.rb
147
149
  - spec/spec_helper.rb
148
150
  - spec/support/stub_fog_interface.rb
151
+ - spec/vcloud/core/config_loader_spec.rb
152
+ - spec/vcloud/core/config_validator_spec.rb
153
+ - spec/vcloud/core/data/basic_preamble_test.erb
154
+ - spec/vcloud/core/data/basic_preamble_test.erb.OUT
155
+ - spec/vcloud/core/data/working.json
156
+ - spec/vcloud/core/data/working.yaml
157
+ - spec/vcloud/core/data/working_with_defaults.yaml
149
158
  - spec/vcloud/core/edge_gateway_interface_spec.rb
150
159
  - spec/vcloud/core/edge_gateway_spec.rb
151
160
  - spec/vcloud/core/metadata_helper_spec.rb
@@ -155,8 +164,6 @@ files:
155
164
  - spec/vcloud/core/vapp_template_spec.rb
156
165
  - spec/vcloud/core/vdc_spec.rb
157
166
  - spec/vcloud/core/vm_spec.rb
158
- - spec/vcloud/data/basic_preamble_test.erb
159
- - spec/vcloud/data/basic_preamble_test.erb.OUT
160
167
  - spec/vcloud/fog/fog_model_interface_spec.rb
161
168
  - spec/vcloud/fog/service_interface_spec.rb
162
169
  - vcloud-core.gemspec
@@ -181,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
188
  version: '0'
182
189
  segments:
183
190
  - 0
184
- hash: 4076622022301530583
191
+ hash: -3857077396882591731
185
192
  requirements: []
186
193
  rubyforge_project:
187
194
  rubygems_version: 1.8.23
@@ -193,6 +200,13 @@ test_files:
193
200
  - spec/integration/edge_gateway/edge_gateway_spec.rb
194
201
  - spec/spec_helper.rb
195
202
  - spec/support/stub_fog_interface.rb
203
+ - spec/vcloud/core/config_loader_spec.rb
204
+ - spec/vcloud/core/config_validator_spec.rb
205
+ - spec/vcloud/core/data/basic_preamble_test.erb
206
+ - spec/vcloud/core/data/basic_preamble_test.erb.OUT
207
+ - spec/vcloud/core/data/working.json
208
+ - spec/vcloud/core/data/working.yaml
209
+ - spec/vcloud/core/data/working_with_defaults.yaml
196
210
  - spec/vcloud/core/edge_gateway_interface_spec.rb
197
211
  - spec/vcloud/core/edge_gateway_spec.rb
198
212
  - spec/vcloud/core/metadata_helper_spec.rb
@@ -202,7 +216,5 @@ test_files:
202
216
  - spec/vcloud/core/vapp_template_spec.rb
203
217
  - spec/vcloud/core/vdc_spec.rb
204
218
  - spec/vcloud/core/vm_spec.rb
205
- - spec/vcloud/data/basic_preamble_test.erb
206
- - spec/vcloud/data/basic_preamble_test.erb.OUT
207
219
  - spec/vcloud/fog/fog_model_interface_spec.rb
208
220
  - spec/vcloud/fog/service_interface_spec.rb