opennebula 5.12.9 → 6.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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ActionManager.rb +1 -1
  3. data/lib/CommandManager.rb +1 -1
  4. data/lib/DriverExecHelper.rb +44 -28
  5. data/lib/OpenNebulaDriver.rb +8 -4
  6. data/lib/VirtualMachineDriver.rb +9 -2
  7. data/lib/cloud/CloudClient.rb +3 -3
  8. data/lib/datacenter.rb +1257 -0
  9. data/lib/datastore.rb +1025 -0
  10. data/lib/distributed_firewall.rb +280 -0
  11. data/lib/file_helper.rb +370 -0
  12. data/lib/host.rb +1517 -0
  13. data/lib/logical_port.rb +50 -0
  14. data/lib/logical_switch.rb +77 -0
  15. data/lib/memoize.rb +74 -0
  16. data/lib/models.rb +32 -0
  17. data/lib/models/role.rb +1126 -0
  18. data/lib/models/service.rb +709 -0
  19. data/lib/network.rb +699 -0
  20. data/lib/nsx_client.rb +144 -0
  21. data/lib/nsx_component.rb +28 -0
  22. data/lib/nsx_constants.rb +149 -0
  23. data/lib/nsx_driver.rb +78 -0
  24. data/lib/nsx_error.rb +77 -0
  25. data/lib/nsx_rule.rb +193 -0
  26. data/lib/nsxt_client.rb +176 -0
  27. data/lib/nsxt_dfw.rb +196 -0
  28. data/lib/nsxt_logical_port.rb +94 -0
  29. data/lib/nsxt_rule.rb +188 -0
  30. data/lib/nsxt_tz.rb +38 -0
  31. data/lib/nsxv_client.rb +176 -0
  32. data/lib/nsxv_dfw.rb +202 -0
  33. data/lib/nsxv_logical_port.rb +107 -0
  34. data/lib/nsxv_rule.rb +172 -0
  35. data/lib/nsxv_tz.rb +41 -0
  36. data/lib/opaque_network.rb +134 -0
  37. data/lib/opennebula.rb +5 -2
  38. data/lib/opennebula/acl.rb +1 -1
  39. data/lib/opennebula/acl_pool.rb +1 -1
  40. data/lib/opennebula/client.rb +10 -2
  41. data/lib/opennebula/cluster.rb +1 -1
  42. data/lib/opennebula/cluster_pool.rb +1 -1
  43. data/lib/opennebula/datastore.rb +1 -1
  44. data/lib/opennebula/datastore_pool.rb +1 -1
  45. data/lib/opennebula/document.rb +8 -29
  46. data/lib/opennebula/document_json.rb +42 -12
  47. data/lib/opennebula/document_pool.rb +1 -1
  48. data/lib/opennebula/document_pool_json.rb +1 -1
  49. data/lib/opennebula/error.rb +4 -1
  50. data/lib/opennebula/flow.rb +23 -0
  51. data/lib/opennebula/flow/grammar.rb +1195 -0
  52. data/lib/opennebula/flow/service_pool.rb +190 -0
  53. data/lib/opennebula/flow/service_template.rb +608 -0
  54. data/lib/opennebula/flow/service_template_ext.rb +84 -0
  55. data/lib/opennebula/flow/service_template_pool.rb +32 -0
  56. data/lib/opennebula/flow/validator.rb +499 -0
  57. data/lib/opennebula/group.rb +1 -1
  58. data/lib/opennebula/group_pool.rb +1 -1
  59. data/lib/opennebula/hook.rb +5 -12
  60. data/lib/opennebula/hook_log.rb +1 -1
  61. data/lib/opennebula/hook_pool.rb +1 -1
  62. data/lib/opennebula/host.rb +1 -1
  63. data/lib/opennebula/host_pool.rb +1 -1
  64. data/lib/opennebula/image.rb +19 -14
  65. data/lib/opennebula/image_pool.rb +1 -1
  66. data/lib/opennebula/ldap_auth.rb +1 -1
  67. data/lib/opennebula/ldap_auth_spec.rb +1 -1
  68. data/lib/opennebula/lockable_ext.rb +163 -0
  69. data/lib/opennebula/marketplace.rb +1 -1
  70. data/lib/opennebula/marketplace_pool.rb +1 -1
  71. data/lib/opennebula/marketplaceapp.rb +9 -119
  72. data/lib/opennebula/marketplaceapp_ext.rb +586 -0
  73. data/lib/opennebula/marketplaceapp_pool.rb +1 -1
  74. data/lib/opennebula/oneflow_client.rb +4 -3
  75. data/lib/opennebula/pool.rb +6 -3
  76. data/lib/opennebula/pool_element.rb +1 -1
  77. data/lib/opennebula/security_group.rb +1 -1
  78. data/lib/opennebula/security_group_pool.rb +1 -1
  79. data/lib/opennebula/server_cipher_auth.rb +1 -1
  80. data/lib/opennebula/server_x509_auth.rb +1 -1
  81. data/lib/opennebula/ssh_auth.rb +1 -1
  82. data/lib/opennebula/system.rb +1 -1
  83. data/lib/opennebula/template.rb +4 -13
  84. data/lib/opennebula/template_ext.rb +342 -0
  85. data/lib/opennebula/template_pool.rb +1 -1
  86. data/lib/opennebula/user.rb +26 -2
  87. data/lib/opennebula/user_pool.rb +1 -1
  88. data/lib/opennebula/utils.rb +1 -1
  89. data/lib/opennebula/vdc.rb +1 -1
  90. data/lib/opennebula/vdc_pool.rb +1 -1
  91. data/lib/opennebula/virtual_machine.rb +26 -206
  92. data/lib/opennebula/virtual_machine_ext.rb +469 -0
  93. data/lib/opennebula/virtual_machine_pool.rb +1 -1
  94. data/lib/opennebula/virtual_network.rb +4 -10
  95. data/lib/opennebula/virtual_network_pool.rb +1 -1
  96. data/lib/opennebula/virtual_router.rb +4 -12
  97. data/lib/opennebula/virtual_router_pool.rb +1 -1
  98. data/lib/opennebula/vm_group.rb +4 -11
  99. data/lib/opennebula/vm_group_pool.rb +1 -1
  100. data/lib/opennebula/vntemplate.rb +4 -13
  101. data/lib/opennebula/vntemplate_pool.rb +1 -1
  102. data/lib/opennebula/wait_ext.rb +257 -0
  103. data/lib/opennebula/x509_auth.rb +1 -1
  104. data/lib/opennebula/xml_element.rb +1 -1
  105. data/lib/opennebula/xml_pool.rb +1 -1
  106. data/lib/opennebula/xml_utils.rb +1 -1
  107. data/lib/opennebula/zone.rb +1 -1
  108. data/lib/opennebula/zone_pool.rb +1 -1
  109. data/lib/rest_client.rb +201 -0
  110. data/lib/scripts_common.rb +183 -0
  111. data/lib/transport_zone.rb +43 -0
  112. data/lib/vcenter_driver.rb +13 -12
  113. data/lib/vcenter_importer.rb +616 -0
  114. data/lib/vi_client.rb +281 -0
  115. data/lib/vi_helper.rb +313 -0
  116. data/lib/virtual_machine.rb +3477 -0
  117. data/lib/virtual_wire.rb +158 -0
  118. data/lib/vm_device.rb +80 -0
  119. data/lib/vm_disk.rb +202 -0
  120. data/lib/vm_folder.rb +69 -0
  121. data/lib/vm_helper.rb +30 -0
  122. data/lib/vm_monitor.rb +303 -0
  123. data/lib/vm_nic.rb +70 -0
  124. data/lib/vm_template.rb +1963 -0
  125. data/lib/vmm_importer.rb +121 -0
  126. metadata +140 -27
@@ -0,0 +1,190 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2021, OpenNebula Project, OpenNebula Systems #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+ module OpenNebula
18
+
19
+ # ServicePool class
20
+ class OpenNebulaServicePool < DocumentPoolJSON
21
+
22
+ DOCUMENT_TYPE = 100
23
+
24
+ def initialize(client, user_id = -2)
25
+ super(client, user_id)
26
+ end
27
+
28
+ def factory(element_xml)
29
+ service = OpenNebula::Service.new(element_xml, @client)
30
+ service.load_body
31
+ service
32
+ end
33
+
34
+ end
35
+
36
+ # ServicePool class
37
+ class ServicePool < Pool
38
+
39
+ # rubocop:disable Style/ClassVars
40
+ @@mutex = Mutex.new
41
+ @@mutex_hash = {}
42
+ # rubocop:enable Style/ClassVars
43
+
44
+ # Class constructor
45
+ #
46
+ # @param [OpenNebula::Client] client the xml-rpc client
47
+ # @param [Integer] user_id the filter flag, see
48
+ # http://docs.opennebula.io/stable/integration/system_interfaces/api.html
49
+ #
50
+ # @return [DocumentPool] the new object
51
+ def initialize(cloud_auth, client)
52
+ # TODO, what if cloud_auth is nil?
53
+ @cloud_auth = cloud_auth
54
+ @client = client
55
+ @one_pool = nil
56
+
57
+ if @client
58
+ info = Nokogiri::XML(@client.call('user.info', -1))
59
+ @user_id = Integer(info.xpath('/USER/ID').text)
60
+ end
61
+
62
+ super('DOCUMENT_POOL', 'DOCUMENT', @client)
63
+ end
64
+
65
+ def client
66
+ # If there's a client defined use it
67
+ return @client unless @client.nil?
68
+
69
+ # If not, get one via cloud_auth
70
+ @cloud_auth.client
71
+ end
72
+
73
+ def info
74
+ osp = OpenNebulaServicePool.new(client)
75
+ rc = osp.info
76
+
77
+ @one_pool = osp
78
+
79
+ rc
80
+ end
81
+
82
+ def info_all
83
+ osp = OpenNebulaServicePool.new(client)
84
+ rc = osp.info_all
85
+
86
+ @one_pool = osp
87
+
88
+ rc
89
+ end
90
+
91
+ # rubocop:disable Lint/ToJSON
92
+ def to_json
93
+ # rubocop:enable Lint/ToJSON
94
+ @one_pool.to_json
95
+ end
96
+
97
+ def each(&block)
98
+ return if @one_pool.nil?
99
+
100
+ @one_pool.each(&block)
101
+ end
102
+
103
+ # Iterates over pool pages
104
+ # size:: nil => default page size
105
+ # > 0 => page size
106
+ # state state of objects
107
+ def each_page(size)
108
+ loop_page(size, Service::DOCUMENT_TYPE, false) do |element, page|
109
+ page.each("//#{element}") do |obj|
110
+ service = Service.new_with_id(obj['ID'], @client)
111
+ service.info
112
+
113
+ yield(service)
114
+ end
115
+
116
+ size
117
+ end
118
+ end
119
+
120
+ # Retrieves a Service element from OpenNebula. The Service::info()
121
+ # method is called
122
+ #
123
+ # @param [Integer] service_id Numerical Id of the service to retrieve
124
+ # @yieldparam [Service] this block will have the service's mutex locked.
125
+ # The mutex will be unlocked after the block execution.
126
+ #
127
+ # @return [Service, OpenNebula::Error] The Service in case of success
128
+ def get(service_id, external_client = nil, &block)
129
+ service_id = service_id.to_i if service_id
130
+ aux_client = nil
131
+
132
+ if external_client.nil?
133
+ aux_client = client
134
+ else
135
+ aux_client = external_client
136
+ end
137
+
138
+ service = Service.new_with_id(service_id, aux_client)
139
+
140
+ if block_given?
141
+ obj_mutex = nil
142
+ entry = nil
143
+
144
+ @@mutex.synchronize do
145
+ # entry is an array of [Mutex, waiting]
146
+ # waiting is the number of threads waiting on this mutex
147
+ entry = @@mutex_hash[service_id]
148
+
149
+ if entry.nil?
150
+ entry = [Mutex.new, 0]
151
+ @@mutex_hash[service_id] = entry
152
+ end
153
+
154
+ obj_mutex = entry[0]
155
+ entry[1] = entry[1] + 1
156
+
157
+ if @@mutex_hash.size > 10000
158
+ @@mutex_hash.delete_if do |_s_id, entry_loop|
159
+ entry_loop[1] == 0
160
+ end
161
+ end
162
+ end
163
+
164
+ rc = obj_mutex.synchronize do
165
+ rc = service.info
166
+
167
+ if OpenNebula.is_error?(rc)
168
+ return rc
169
+ end
170
+
171
+ block.call(service)
172
+ end
173
+
174
+ @@mutex.synchronize do
175
+ entry[1] = entry[1] - 1
176
+ end
177
+
178
+ if OpenNebula.is_error?(rc)
179
+ return rc
180
+ end
181
+ else
182
+ service.info
183
+ end
184
+
185
+ service
186
+ end
187
+
188
+ end
189
+
190
+ end
@@ -0,0 +1,608 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2002-2021, OpenNebula Project, OpenNebula Systems #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+ require 'parse-cron'
18
+
19
+ module OpenNebula
20
+
21
+ # Service Template
22
+ class ServiceTemplate < DocumentJSON
23
+
24
+ ROLE_SCHEMA = {
25
+ :type => :object,
26
+ :properties => {
27
+ 'name' => {
28
+ :type => :string,
29
+ :required => true,
30
+ :regex => /^\w+$/
31
+ },
32
+ 'cardinality' => {
33
+ :type => :integer,
34
+ :default => 1,
35
+ :minimum => 0
36
+ },
37
+ 'vm_template' => {
38
+ :type => :integer,
39
+ :required => true
40
+ },
41
+ 'vm_template_contents' => {
42
+ :type => :string,
43
+ :required => false
44
+ },
45
+ 'parents' => {
46
+ :type => :array,
47
+ :items => {
48
+ :type => :string
49
+ }
50
+ },
51
+ 'shutdown_action' => {
52
+ :type => :string,
53
+ :enum => %w[
54
+ terminate
55
+ terminate-hard
56
+ shutdown
57
+ shutdown-hard
58
+ ],
59
+ :required => false
60
+ },
61
+ 'min_vms' => {
62
+ :type => :integer,
63
+ :required => false,
64
+ :minimum => 0
65
+ },
66
+ 'max_vms' => {
67
+ :type => :integer,
68
+ :required => false,
69
+ :minimum => 0
70
+ },
71
+ 'cooldown' => {
72
+ :type => :integer,
73
+ :required => false,
74
+ :minimum => 0
75
+ },
76
+ 'elasticity_policies' => {
77
+ :type => :array,
78
+ :items => {
79
+ :type => :object,
80
+ :properties => {
81
+ 'type' => {
82
+ :type => :string,
83
+ :enum => %w[
84
+ CHANGE
85
+ CARDINALITY
86
+ PERCENTAGE_CHANGE
87
+ ],
88
+ :required => true
89
+ },
90
+ 'adjust' => {
91
+ :type => :integer,
92
+ :required => true
93
+ },
94
+ 'min_adjust_step' => {
95
+ :type => :integer,
96
+ :required => false,
97
+ :minimum => 1
98
+ },
99
+ 'period_number' => {
100
+ :type => :integer,
101
+ :required => false,
102
+ :minimum => 0
103
+ },
104
+ 'period' => {
105
+ :type => :integer,
106
+ :required => false,
107
+ :minimum => 0
108
+ },
109
+ 'expression' => {
110
+ :type => :string,
111
+ :required => true
112
+ },
113
+ 'cooldown' => {
114
+ :type => :integer,
115
+ :required => false,
116
+ :minimum => 0
117
+ }
118
+ # 'statistic' => {
119
+ # # SampleCount | Average | Sum | Minimum | Maximum
120
+ # :type => :string
121
+ # }
122
+ }
123
+ }
124
+ },
125
+ 'scheduled_policies' => {
126
+ :type => :array,
127
+ :items => {
128
+ :type => :object,
129
+ :properties => {
130
+ 'type' => {
131
+ :type => :string,
132
+ :enum => %w[
133
+ CHANGE
134
+ CARDINALITY
135
+ PERCENTAGE_CHANGE
136
+ ],
137
+ :required => true
138
+ },
139
+ 'adjust' => {
140
+ :type => :integer,
141
+ :required => true
142
+ },
143
+ 'min_adjust_step' => {
144
+ :type => :integer,
145
+ :required => false,
146
+ :minimum => 1
147
+ },
148
+ 'start_time' => {
149
+ :type => :string,
150
+ :required => false
151
+ },
152
+ 'recurrence' => {
153
+ :type => :string,
154
+ :required => false
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ SCHEMA = {
163
+ :type => :object,
164
+ :properties => {
165
+ 'name' => {
166
+ :type => :string,
167
+ :required => true
168
+ },
169
+ 'deployment' => {
170
+ :type => :string,
171
+ :enum => %w[none straight],
172
+ :default => 'none'
173
+ },
174
+ 'description' => {
175
+ :type => :string,
176
+ :default => ''
177
+ },
178
+ 'shutdown_action' => {
179
+ :type => :string,
180
+ :enum => %w[
181
+ terminate
182
+ terminate-hard
183
+ shutdown
184
+ shutdown-hard
185
+ ],
186
+ :required => false
187
+ },
188
+ 'roles' => {
189
+ :type => :array,
190
+ :items => ROLE_SCHEMA,
191
+ :required => true
192
+ },
193
+ 'custom_attrs' => {
194
+ :type => :object,
195
+ :properties => {},
196
+ :required => false
197
+ },
198
+ 'custom_attrs_values' => {
199
+ :type => :object,
200
+ :properties => {},
201
+ :required => false
202
+ },
203
+ 'ready_status_gate' => {
204
+ :type => :boolean,
205
+ :required => false
206
+ },
207
+ 'automatic_deletion' => {
208
+ :type => :boolean,
209
+ :required => false
210
+ },
211
+ 'networks' => {
212
+ :type => :object,
213
+ :properties => {},
214
+ :required => false
215
+ },
216
+ 'networks_values' => {
217
+ :type => :array,
218
+ :items => {
219
+ :type => :object,
220
+ :properties => {}
221
+ },
222
+ :required => false
223
+ }
224
+ }
225
+ }
226
+
227
+ # List of attributes that can't be changed in update operation
228
+ #
229
+ # registration_time: this is internal info managed by OneFlow server
230
+ IMMUTABLE_ATTRS = %w[
231
+ registration_time
232
+ ]
233
+
234
+ def self.init_default_vn_name_template(vn_name_template)
235
+ # rubocop:disable Style/ClassVars
236
+ @@vn_name_template = vn_name_template
237
+ # rubocop:enable Style/ClassVars
238
+ end
239
+
240
+ DOCUMENT_TYPE = 101
241
+
242
+ def allocate(template_json)
243
+ template = JSON.parse(template_json)
244
+
245
+ ServiceTemplate.validate(template)
246
+
247
+ template['registration_time'] = Integer(Time.now)
248
+
249
+ super(template.to_json, template['name'])
250
+ end
251
+
252
+ # Delete service template
253
+ #
254
+ # @param type [String] Delete type
255
+ # - none: just the service template
256
+ # - all: delete VM templates, images and service template
257
+ # - templates: delete VM templates and service template
258
+ def delete(type = nil)
259
+ case type
260
+ when 'all'
261
+ recursive = true
262
+ when 'templates'
263
+ recursive = false
264
+ end
265
+
266
+ if type && type != 'none'
267
+ rc = vm_template_ids
268
+
269
+ return rc if OpenNebula.is_error?(rc)
270
+
271
+ rc = rc.each do |t_id|
272
+ t = OpenNebula::Template.new_with_id(t_id, @client)
273
+ rc = t.info
274
+
275
+ break rc if OpenNebula.is_error?(rc)
276
+
277
+ rc = t.delete(recursive)
278
+
279
+ break rc if OpenNebula.is_error?(rc)
280
+ end
281
+ end
282
+
283
+ return rc if OpenNebula.is_error?(rc)
284
+
285
+ super()
286
+ end
287
+
288
+ # Retrieves the template
289
+ #
290
+ # @return [String] json template
291
+ def template
292
+ @body.to_json
293
+ end
294
+
295
+ # Replaces the template contents
296
+ #
297
+ # @param template_json [String] New template contents
298
+ # @param append [true, false] True to append new attributes instead of
299
+ # replace the whole template
300
+ #
301
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
302
+ # otherwise
303
+ def update(template_json, append = false)
304
+ rc = info
305
+
306
+ return rc if OpenNebula.is_error?(rc)
307
+
308
+ template = JSON.parse(template_json)
309
+
310
+ IMMUTABLE_ATTRS.each do |attr|
311
+ next if template[attr] == @body[attr]
312
+
313
+ return [false, "service_template/#{attr}"]
314
+ end
315
+
316
+ template = @body.merge(template) if append
317
+
318
+ ServiceTemplate.validate(template)
319
+
320
+ super(template.to_json)
321
+ end
322
+
323
+ # Clone service template and the VM templates asssociated to it
324
+ #
325
+ # @param name [String] New template name
326
+ # @param mode [Symbol] Cloning mode (:all, :templates)
327
+ #
328
+ # @return [Integer] New document ID
329
+ def clone_recursively(name, mode)
330
+ recursive = mode == 'all'
331
+
332
+ # clone the document to get new ID
333
+ new_id = clone(name)
334
+
335
+ return new_id if OpenNebula.is_error?(new_id)
336
+
337
+ doc = OpenNebula::ServiceTemplate.new_with_id(new_id, @client)
338
+ rc = doc.info
339
+
340
+ return rc if OpenNebula.is_error?(rc)
341
+
342
+ body = JSON.parse(doc["TEMPLATE/#{TEMPLATE_TAG}"])
343
+ cloned_templates = {}
344
+
345
+ # iterate over roles to clone templates
346
+ rc = body['roles'].each do |role|
347
+ t_id = role['vm_template']
348
+
349
+ # if the template has already been cloned, just update the value
350
+ if cloned_templates.keys.include?(t_id)
351
+ role['vm_template'] = cloned_templates[t_id]
352
+ next
353
+ end
354
+
355
+ template = OpenNebula::Template.new_with_id(t_id, @client)
356
+ rc = template.info
357
+
358
+ break rc if OpenNebula.is_error?(rc)
359
+
360
+ # The maximum size is 128, so crop the template name if it
361
+ # exceeds the limit
362
+ new_name = "#{template.name}-#{name}"
363
+
364
+ if new_name.size > 128
365
+ new_name = "#{template.name[0..(126 - name.size)]}-#{name}"
366
+ end
367
+
368
+ rc = template.clone(new_name, recursive)
369
+
370
+ break rc if OpenNebula.is_error?(rc)
371
+
372
+ # add new ID to the hash
373
+ cloned_templates[t_id] = rc
374
+
375
+ role['vm_template'] = rc
376
+ end
377
+
378
+ # if any error, rollback and delete the left templates
379
+ if OpenNebula.is_error?(rc)
380
+ cloned_templates.each do |_, value|
381
+ template = OpenNebula::Template.new_with_id(value, @client)
382
+
383
+ rc = template.info
384
+
385
+ break rc if OpenNebula.is_error?(rc)
386
+
387
+ rc = template.delete(recursive)
388
+
389
+ break rc if OpenNebula.is_error?(rc)
390
+ end
391
+
392
+ return rc
393
+ end
394
+
395
+ # add registration time, as the template is new
396
+ body['registration_time'] = Integer(Time.now)
397
+
398
+ # update the template with the new body
399
+ doc.update(body.to_json)
400
+
401
+ # return the new document ID
402
+ new_id
403
+ end
404
+
405
+ # Clones a service template
406
+ #
407
+ # @param name [Stirng] New name
408
+ #
409
+ # @return [Integer] New template ID
410
+ def clone(name)
411
+ new_id = super
412
+
413
+ doc = OpenNebula::ServiceTemplate.new_with_id(new_id, @client)
414
+ rc = doc.info
415
+
416
+ return rc if OpenNebula.is_error?(rc)
417
+
418
+ body = JSON.parse(doc["TEMPLATE/#{TEMPLATE_TAG}"])
419
+
420
+ # add registration time, as the template is new
421
+ body['registration_time'] = Integer(Time.now)
422
+
423
+ # update the template with the new body
424
+ DocumentJSON.instance_method(:update).bind(doc).call(body.to_json)
425
+
426
+ # return the new document ID
427
+ new_id
428
+ end
429
+
430
+ # Replaces the raw template contents
431
+ #
432
+ # @param template [String] New template contents, in the form KEY = VAL
433
+ # @param append [true, false] True to append new attributes instead of
434
+ # replace the whole template
435
+ #
436
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
437
+ # otherwise
438
+ def update_raw(template_raw, append = false)
439
+ super(template_raw, append)
440
+ end
441
+
442
+ def self.validate(template)
443
+ validator = Validator::Validator.new(
444
+ :default_values => true,
445
+ :delete_extra_properties => false,
446
+ :allow_extra_properties => true
447
+ )
448
+
449
+ validator.validate!(template, SCHEMA)
450
+
451
+ validate_values(template)
452
+ end
453
+
454
+ def instantiate(merge_template)
455
+ rc = nil
456
+
457
+ if merge_template.nil?
458
+ instantiate_template = JSON.parse(@body.to_json)
459
+ else
460
+ instantiate_template = JSON.parse(@body.to_json)
461
+ .merge(merge_template)
462
+ end
463
+
464
+ begin
465
+ ServiceTemplate.validate(instantiate_template)
466
+
467
+ xml = OpenNebula::Service.build_xml
468
+ service = OpenNebula::Service.new(xml, @client)
469
+
470
+ rc = service.allocate(instantiate_template.to_json)
471
+ rescue Validator::ParseException, JSON::ParserError => e
472
+ return e
473
+ end
474
+
475
+ return rc if OpenNebula.is_error?(rc)
476
+
477
+ service.info
478
+ service
479
+ end
480
+
481
+ def self.validate_values(template)
482
+ parser = ElasticityGrammarParser.new
483
+
484
+ roles = template['roles']
485
+
486
+ roles.each_with_index do |role, role_index|
487
+ roles[role_index+1..-1].each do |other_role|
488
+ if role['name'] == other_role['name']
489
+ raise Validator::ParseException,
490
+ "Role name '#{role['name']}' is repeated"
491
+ end
492
+ end
493
+
494
+ if !role['min_vms'].nil? &&
495
+ role['min_vms'].to_i > role['cardinality'].to_i
496
+
497
+ raise Validator::ParseException,
498
+ "Role '#{role['name']}' 'cardinality' must be " \
499
+ "greater than or equal to 'min_vms'"
500
+ end
501
+
502
+ if !role['max_vms'].nil? &&
503
+ role['max_vms'].to_i < role['cardinality'].to_i
504
+
505
+ raise Validator::ParseException,
506
+ "Role '#{role['name']}' 'cardinality' must be " \
507
+ "lower than or equal to 'max_vms'"
508
+ end
509
+
510
+ if ((role['elasticity_policies'] &&
511
+ !role['elasticity_policies'].empty?) ||
512
+ (role['scheduled_policies'] &&
513
+ !role['scheduled_policies'].empty?)) &&
514
+ (role['min_vms'].nil? || role['max_vms'].nil?)
515
+ raise Validator::ParseException,
516
+ "Role '#{role['name']}' with " \
517
+ " 'elasticity_policies' or " \
518
+ "'scheduled_policies'must define both 'min_vms'" \
519
+ " and 'max_vms'"
520
+ end
521
+
522
+ if role['elasticity_policies']
523
+ role['elasticity_policies'].each_with_index do |policy,
524
+ index|
525
+ exp = policy['expression']
526
+
527
+ if exp.empty?
528
+ raise Validator::ParseException,
529
+ "Role '#{role['name']}', elasticity policy " \
530
+ "##{index} 'expression' cannot be empty"
531
+ end
532
+
533
+ treetop = parser.parse(exp)
534
+ next unless treetop.nil?
535
+
536
+ raise Validator::ParseException,
537
+ "Role '#{role['name']}', elasticity policy " \
538
+ "##{index} 'expression' parse error: " \
539
+ "#{parser.failure_reason}"
540
+ end
541
+ end
542
+
543
+ next unless role['scheduled_policies']
544
+
545
+ role['scheduled_policies'].each_with_index do |policy, index|
546
+ start_time = policy['start_time']
547
+ recurrence = policy['recurrence']
548
+
549
+ if !start_time.nil?
550
+ if !policy['recurrence'].nil?
551
+ raise Validator::ParseException,
552
+ "Role '#{role['name']}', scheduled policy "\
553
+ "##{index} must define "\
554
+ "'start_time' or 'recurrence', but not both"
555
+ end
556
+
557
+ begin
558
+ next if start_time.match(/^\d+$/)
559
+
560
+ Time.parse(start_time)
561
+ rescue ArgumentError
562
+ raise Validator::ParseException,
563
+ "Role '#{role['name']}', scheduled policy " \
564
+ "##{index} 'start_time' is not a valid " \
565
+ 'Time. Try with YYYY-MM-DD hh:mm:ss or ' \
566
+ '0YYY-MM-DDThh:mm:ssZ'
567
+ end
568
+ elsif !recurrence.nil?
569
+ begin
570
+ cron_parser = CronParser.new(recurrence)
571
+ cron_parser.next
572
+ rescue StandardError
573
+ raise Validator::ParseException,
574
+ "Role '#{role['name']}', scheduled policy " \
575
+ "##{index} 'recurrence' is not a valid " \
576
+ 'cron expression'
577
+ end
578
+ else
579
+ raise Validator::ParseException,
580
+ "Role '#{role['name']}', scheduled policy #" \
581
+ "#{index} needs to define either " \
582
+ "'start_time' or 'recurrence'"
583
+ end
584
+ end
585
+ end
586
+ end
587
+
588
+ # Retreives all associated VM templates IDs
589
+ #
590
+ # @return [Array] VM templates IDs
591
+ def vm_template_ids
592
+ rc = info
593
+
594
+ return rc if OpenNebula.is_error?(rc)
595
+
596
+ ret = []
597
+
598
+ @body['roles'].each do |role|
599
+ t_id = Integer(role['vm_template'])
600
+ ret << t_id unless ret.include?(t_id)
601
+ end
602
+
603
+ ret
604
+ end
605
+
606
+ end
607
+
608
+ end