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.
- checksums.yaml +4 -4
- data/lib/ActionManager.rb +1 -1
- data/lib/CommandManager.rb +1 -1
- data/lib/DriverExecHelper.rb +44 -28
- data/lib/OpenNebulaDriver.rb +8 -4
- data/lib/VirtualMachineDriver.rb +9 -2
- data/lib/cloud/CloudClient.rb +3 -3
- data/lib/datacenter.rb +1257 -0
- data/lib/datastore.rb +1025 -0
- data/lib/distributed_firewall.rb +280 -0
- data/lib/file_helper.rb +370 -0
- data/lib/host.rb +1517 -0
- data/lib/logical_port.rb +50 -0
- data/lib/logical_switch.rb +77 -0
- data/lib/memoize.rb +74 -0
- data/lib/models.rb +32 -0
- data/lib/models/role.rb +1126 -0
- data/lib/models/service.rb +709 -0
- data/lib/network.rb +699 -0
- data/lib/nsx_client.rb +144 -0
- data/lib/nsx_component.rb +28 -0
- data/lib/nsx_constants.rb +149 -0
- data/lib/nsx_driver.rb +78 -0
- data/lib/nsx_error.rb +77 -0
- data/lib/nsx_rule.rb +193 -0
- data/lib/nsxt_client.rb +176 -0
- data/lib/nsxt_dfw.rb +196 -0
- data/lib/nsxt_logical_port.rb +94 -0
- data/lib/nsxt_rule.rb +188 -0
- data/lib/nsxt_tz.rb +38 -0
- data/lib/nsxv_client.rb +176 -0
- data/lib/nsxv_dfw.rb +202 -0
- data/lib/nsxv_logical_port.rb +107 -0
- data/lib/nsxv_rule.rb +172 -0
- data/lib/nsxv_tz.rb +41 -0
- data/lib/opaque_network.rb +134 -0
- data/lib/opennebula.rb +5 -2
- data/lib/opennebula/acl.rb +1 -1
- data/lib/opennebula/acl_pool.rb +1 -1
- data/lib/opennebula/client.rb +10 -2
- data/lib/opennebula/cluster.rb +1 -1
- data/lib/opennebula/cluster_pool.rb +1 -1
- data/lib/opennebula/datastore.rb +1 -1
- data/lib/opennebula/datastore_pool.rb +1 -1
- data/lib/opennebula/document.rb +8 -29
- data/lib/opennebula/document_json.rb +42 -12
- data/lib/opennebula/document_pool.rb +1 -1
- data/lib/opennebula/document_pool_json.rb +1 -1
- data/lib/opennebula/error.rb +4 -1
- data/lib/opennebula/flow.rb +23 -0
- data/lib/opennebula/flow/grammar.rb +1195 -0
- data/lib/opennebula/flow/service_pool.rb +190 -0
- data/lib/opennebula/flow/service_template.rb +608 -0
- data/lib/opennebula/flow/service_template_ext.rb +84 -0
- data/lib/opennebula/flow/service_template_pool.rb +32 -0
- data/lib/opennebula/flow/validator.rb +499 -0
- data/lib/opennebula/group.rb +1 -1
- data/lib/opennebula/group_pool.rb +1 -1
- data/lib/opennebula/hook.rb +5 -12
- data/lib/opennebula/hook_log.rb +1 -1
- data/lib/opennebula/hook_pool.rb +1 -1
- data/lib/opennebula/host.rb +1 -1
- data/lib/opennebula/host_pool.rb +1 -1
- data/lib/opennebula/image.rb +19 -14
- data/lib/opennebula/image_pool.rb +1 -1
- data/lib/opennebula/ldap_auth.rb +1 -1
- data/lib/opennebula/ldap_auth_spec.rb +1 -1
- data/lib/opennebula/lockable_ext.rb +163 -0
- data/lib/opennebula/marketplace.rb +1 -1
- data/lib/opennebula/marketplace_pool.rb +1 -1
- data/lib/opennebula/marketplaceapp.rb +9 -119
- data/lib/opennebula/marketplaceapp_ext.rb +586 -0
- data/lib/opennebula/marketplaceapp_pool.rb +1 -1
- data/lib/opennebula/oneflow_client.rb +4 -3
- data/lib/opennebula/pool.rb +6 -3
- data/lib/opennebula/pool_element.rb +1 -1
- data/lib/opennebula/security_group.rb +1 -1
- data/lib/opennebula/security_group_pool.rb +1 -1
- data/lib/opennebula/server_cipher_auth.rb +1 -1
- data/lib/opennebula/server_x509_auth.rb +1 -1
- data/lib/opennebula/ssh_auth.rb +1 -1
- data/lib/opennebula/system.rb +1 -1
- data/lib/opennebula/template.rb +4 -13
- data/lib/opennebula/template_ext.rb +342 -0
- data/lib/opennebula/template_pool.rb +1 -1
- data/lib/opennebula/user.rb +26 -2
- data/lib/opennebula/user_pool.rb +1 -1
- data/lib/opennebula/utils.rb +1 -1
- data/lib/opennebula/vdc.rb +1 -1
- data/lib/opennebula/vdc_pool.rb +1 -1
- data/lib/opennebula/virtual_machine.rb +26 -206
- data/lib/opennebula/virtual_machine_ext.rb +469 -0
- data/lib/opennebula/virtual_machine_pool.rb +1 -1
- data/lib/opennebula/virtual_network.rb +4 -10
- data/lib/opennebula/virtual_network_pool.rb +1 -1
- data/lib/opennebula/virtual_router.rb +4 -12
- data/lib/opennebula/virtual_router_pool.rb +1 -1
- data/lib/opennebula/vm_group.rb +4 -11
- data/lib/opennebula/vm_group_pool.rb +1 -1
- data/lib/opennebula/vntemplate.rb +4 -13
- data/lib/opennebula/vntemplate_pool.rb +1 -1
- data/lib/opennebula/wait_ext.rb +257 -0
- data/lib/opennebula/x509_auth.rb +1 -1
- data/lib/opennebula/xml_element.rb +1 -1
- data/lib/opennebula/xml_pool.rb +1 -1
- data/lib/opennebula/xml_utils.rb +1 -1
- data/lib/opennebula/zone.rb +1 -1
- data/lib/opennebula/zone_pool.rb +1 -1
- data/lib/rest_client.rb +201 -0
- data/lib/scripts_common.rb +183 -0
- data/lib/transport_zone.rb +43 -0
- data/lib/vcenter_driver.rb +13 -12
- data/lib/vcenter_importer.rb +616 -0
- data/lib/vi_client.rb +281 -0
- data/lib/vi_helper.rb +313 -0
- data/lib/virtual_machine.rb +3477 -0
- data/lib/virtual_wire.rb +158 -0
- data/lib/vm_device.rb +80 -0
- data/lib/vm_disk.rb +202 -0
- data/lib/vm_folder.rb +69 -0
- data/lib/vm_helper.rb +30 -0
- data/lib/vm_monitor.rb +303 -0
- data/lib/vm_nic.rb +70 -0
- data/lib/vm_template.rb +1963 -0
- data/lib/vmm_importer.rb +121 -0
- 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
|