vcloud-core 0.0.8 → 0.0.9

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/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