chef-provisioning-opennebula 0.4.4 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +273 -4
- data/lib/chef/provider/one_flow_service.rb +346 -0
- data/lib/chef/provider/one_flow_template.rb +175 -0
- data/lib/chef/provider/one_image.rb +6 -6
- data/lib/chef/provider/one_template.rb +4 -6
- data/lib/chef/provider/one_user.rb +11 -14
- data/lib/chef/provider/one_vnet.rb +6 -9
- data/lib/chef/provider/one_vnet_lease.rb +3 -3
- data/lib/chef/provisioning/driver_init/opennebula.rb +1 -1
- data/lib/chef/provisioning/driver_init/server_version.rb +28 -0
- data/lib/chef/provisioning/opennebula_driver.rb +1 -1
- data/lib/chef/provisioning/opennebula_driver/credentials.rb +2 -2
- data/lib/chef/provisioning/opennebula_driver/driver.rb +132 -34
- data/lib/chef/provisioning/opennebula_driver/flow_lib.rb +491 -0
- data/lib/chef/provisioning/opennebula_driver/one_lib.rb +39 -49
- data/lib/chef/provisioning/opennebula_driver/resources.rb +2 -2
- data/lib/chef/provisioning/opennebula_driver/version.rb +2 -2
- data/lib/chef/resource/one_flow_service.rb +61 -0
- data/lib/chef/resource/one_flow_template.rb +53 -0
- data/lib/chef/resource/one_image.rb +2 -2
- data/lib/chef/resource/one_template.rb +1 -1
- data/lib/chef/resource/one_user.rb +1 -1
- data/lib/chef/resource/one_vnet.rb +2 -2
- data/lib/chef/resource/one_vnet_lease.rb +1 -1
- data/spec/config_sample.rb +12 -3
- data/spec/integration/test_all_integration_spec.rb +6 -272
- data/spec/integration/test_one_driver.rb +177 -0
- data/spec/integration/test_one_flow.rb +546 -0
- data/spec/recipes/OneDriver/{instantiate_one_template_spec.rb → allocate_change_profile.rb} +5 -7
- data/spec/recipes/OneDriver/{converge_back_two_vm_spec.rb → attach_one_image.rb} +4 -5
- data/spec/recipes/OneDriver/create_one_image.rb +20 -0
- data/spec/recipes/OneDriver/{create_one_template_int_spec.rb → create_one_template_ints.rb} +21 -4
- data/spec/recipes/OneDriver/create_one_template_mix.rb +51 -0
- data/spec/recipes/OneDriver/{create_one_image_spec.rb → create_one_template_strings.rb} +18 -7
- data/spec/recipes/OneDriver/{converge_back_one_vm_spec.rb → create_one_vnet.rb} +5 -5
- data/spec/recipes/OneDriver/delete/{OpenNebula-tpl-1-vm.rb → OpenNebula-test-img.rb} +2 -4
- data/spec/recipes/OneDriver/delete/{OpenNebula-back-1-vm.rb → OpenNebula-test-snap-img.rb} +2 -4
- data/spec/recipes/OneDriver/delete/OpenNebula-test-tpl-ints.rb +2 -4
- data/spec/recipes/OneDriver/delete/{OpenNebula-test-tpl.rb → OpenNebula-test-tpl-mix.rb} +2 -4
- data/spec/recipes/OneDriver/delete/OpenNebula-test-tpl-strings.rb +17 -0
- data/spec/recipes/OneDriver/delete/{OpenNebula-back-2-vm.rb → OpenNebula-test-vm-vnet.rb} +2 -4
- data/spec/recipes/OneDriver/delete/{OpenNebula-bootstrap-vm.rb → OpenNebula-test-vm.rb} +2 -4
- data/spec/recipes/OneDriver/delete/OpenNebula-test-vnet.rb +17 -0
- data/spec/recipes/OneDriver/{attach_back_one_vm_spec.rb → instantiate_one_template.rb} +7 -6
- data/spec/recipes/OneDriver/{converge_bootstrap_vm_spec.rb → instantiate_one_template_vnet.rb} +10 -8
- data/spec/recipes/OneDriver/snapshot_one_image.rb +19 -0
- data/spec/recipes/OneFlowService/action/boot.rb +19 -0
- data/spec/recipes/OneFlowService/action/delete.rb +18 -0
- data/spec/recipes/OneFlowService/action/delete_recreate.rb +18 -0
- data/spec/recipes/OneFlowService/action/hold.rb +19 -0
- data/spec/recipes/OneFlowService/action/poweroff.rb +18 -0
- data/spec/recipes/OneFlowService/action/poweroff_hard.rb +18 -0
- data/spec/recipes/OneFlowService/action/reboot.rb +18 -0
- data/spec/recipes/OneFlowService/action/reboot_hard.rb +18 -0
- data/spec/recipes/OneFlowService/action/release.rb +19 -0
- data/spec/recipes/OneFlowService/action/resume.rb +18 -0
- data/spec/recipes/OneFlowService/action/scale.rb +19 -0
- data/spec/recipes/OneFlowService/action/shutdown.rb +18 -0
- data/spec/recipes/OneFlowService/action/shutdown_hard.rb +18 -0
- data/spec/recipes/OneFlowService/action/shutdown_service.rb +17 -0
- data/spec/recipes/OneFlowService/action/snapshot_create.rb +18 -0
- data/spec/recipes/OneFlowService/action/stop.rb +18 -0
- data/spec/recipes/OneFlowService/action/suspend.rb +18 -0
- data/spec/recipes/OneFlowService/action/undeploy.rb +18 -0
- data/spec/recipes/OneFlowService/action/undeploy_hard.rb +18 -0
- data/spec/recipes/OneFlowService/chmod_simple_by_name.rb +19 -0
- data/spec/recipes/OneFlowService/chmod_simple_by_name_2.rb +18 -0
- data/spec/recipes/OneFlowService/chmod_tpl_opts.rb +31 -0
- data/spec/recipes/OneFlowService/delete/test_instance_template_options.rb +17 -0
- data/spec/recipes/OneFlowService/delete/test_role_action.rb +17 -0
- data/spec/recipes/OneFlowService/delete/test_simple_instance.rb +17 -0
- data/spec/recipes/OneFlowService/delete/test_simple_instance_by_id.rb +17 -0
- data/spec/recipes/{OneDriver/create_bootstrap_vm_spec.rb → OneFlowService/instance_role_action.rb} +19 -11
- data/spec/recipes/OneFlowService/instance_simple_by_id.rb +20 -0
- data/spec/recipes/OneFlowService/instance_simple_by_name.rb +18 -0
- data/spec/recipes/OneFlowService/instance_tpl_opts.rb +30 -0
- data/spec/recipes/OneFlowTemplate/chmod_simple_from_hash.rb +17 -0
- data/spec/recipes/OneFlowTemplate/chmod_update_simple_from_file.rb +19 -0
- data/spec/recipes/OneFlowTemplate/create_branch_from_one_id.rb +43 -0
- data/spec/recipes/OneFlowTemplate/create_branch_from_one_name.rb +20 -0
- data/spec/recipes/OneFlowTemplate/create_role_action_instance.rb +99 -0
- data/spec/recipes/OneFlowTemplate/create_simple_from_file.rb +18 -0
- data/spec/recipes/{OneDriver/attach_back_two_vm_spec.rb → OneFlowTemplate/create_simple_from_hash.rb} +8 -6
- data/spec/recipes/OneFlowTemplate/create_simple_from_web.rb +17 -0
- data/spec/recipes/{OneDriver/attach_one_image_spec.rb → OneFlowTemplate/create_simple_instance_tpl.rb} +8 -6
- data/spec/recipes/OneFlowTemplate/create_tpl_opts_from_file.rb +30 -0
- data/spec/recipes/OneFlowTemplate/create_tpl_opts_from_hash.rb +35 -0
- data/spec/recipes/OneFlowTemplate/delete/branch_from_one_id.rb +17 -0
- data/spec/recipes/OneFlowTemplate/delete/branch_from_one_name.rb +17 -0
- data/spec/recipes/OneFlowTemplate/delete/role_action_instance.rb +17 -0
- data/spec/recipes/OneFlowTemplate/delete/simple_from_file.rb +17 -0
- data/spec/recipes/OneFlowTemplate/delete/simple_from_hash.rb +17 -0
- data/spec/recipes/OneFlowTemplate/delete/simple_from_web.rb +17 -0
- data/spec/recipes/OneFlowTemplate/delete/simple_instance_tpl.rb +17 -0
- data/spec/recipes/OneFlowTemplate/delete/tpl_opts_from_file.rb +17 -0
- data/spec/recipes/OneFlowTemplate/delete/tpl_opts_from_hash.rb +17 -0
- data/spec/recipes/OneFlowTemplate/update_simple_from_hash.rb +57 -0
- data/spec/recipes/{driver_options_spec.rb → common.rb} +9 -3
- data/spec/spec_helper.rb +22 -17
- data/spec/support/opennebula_support.rb +75 -45
- metadata +114 -27
- data/spec/recipes/OneDriver/create_back_one_vm_spec.rb +0 -20
- data/spec/recipes/OneDriver/create_back_two_vm_spec.rb +0 -20
- data/spec/recipes/OneDriver/create_one_template_spec.rb +0 -21
- data/spec/recipes/OneDriver/delete/OpenNebula-bootstrap-img.rb +0 -19
- data/spec/recipes/OneDriver/delete/OpenNebula-snap-1-img.rb +0 -19
- data/spec/recipes/OneDriver/delete/OpenNebula-snap-2-img.rb +0 -19
- data/spec/recipes/OneDriver/snapshot_one_image_spec.rb +0 -21
- data/spec/recipes/OneDriver/snapshot_two_image_spec.rb +0 -21
@@ -0,0 +1,491 @@
|
|
1
|
+
# Copyright 2016, BlackBerry Limited
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'rest-client'
|
16
|
+
require 'json'
|
17
|
+
require 'set'
|
18
|
+
|
19
|
+
#
|
20
|
+
# Implementation.
|
21
|
+
#
|
22
|
+
class Chef
|
23
|
+
#
|
24
|
+
# Module extension.
|
25
|
+
#
|
26
|
+
module Provisioning
|
27
|
+
#
|
28
|
+
# Module extension.
|
29
|
+
#
|
30
|
+
module OpenNebulaDriver
|
31
|
+
#
|
32
|
+
# ONE error.
|
33
|
+
#
|
34
|
+
class OpenNebulaException < Exception
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Implementation.
|
39
|
+
#
|
40
|
+
class FlowLib
|
41
|
+
attr_accessor :flow_url, :username, :password
|
42
|
+
|
43
|
+
# STATE NUMBERS TO SYMBOLS
|
44
|
+
|
45
|
+
# SERVICE:
|
46
|
+
SERVICE_PENDING = 0
|
47
|
+
SERVICE_DEPLOYING = 1
|
48
|
+
SERVICE_RUNNING = 2
|
49
|
+
SERVICE_UNDEPLOYING = 3
|
50
|
+
SERVICE_DONE = 5
|
51
|
+
SERVICE_FAILED_DEPLOYING = 7
|
52
|
+
SERVICE_SCALING = 8
|
53
|
+
SERVICE_FAILED_SCALING = 9
|
54
|
+
SERVICE_COOLDOWN = 10
|
55
|
+
|
56
|
+
# ROLE:
|
57
|
+
ROLE_NOT_EXIST = nil
|
58
|
+
ROLE_NO_VMS = -1
|
59
|
+
ROLE_PENDING = 1
|
60
|
+
ROLE_RUNNING = 3
|
61
|
+
ROLE_STOPPED = 4
|
62
|
+
ROLE_SUSPENDED = 5
|
63
|
+
ROLE_POWEROFF = 8
|
64
|
+
ROLE_UNDEPLOYED = 9
|
65
|
+
|
66
|
+
def initialize(url, one_auth)
|
67
|
+
@flow_url = url
|
68
|
+
@username, _, @password = one_auth.rpartition(':')
|
69
|
+
end
|
70
|
+
|
71
|
+
###########
|
72
|
+
# HELPERS #
|
73
|
+
###########
|
74
|
+
|
75
|
+
# Performs some basic verifications on a template
|
76
|
+
# Also adds in default values
|
77
|
+
def normalize_template(name, driver, template, allow_no_roles = false, allow_no_vm_template = false)
|
78
|
+
template = {
|
79
|
+
:deployment => 'straight',
|
80
|
+
:name => name,
|
81
|
+
:ready_status_gate => false,
|
82
|
+
:description => '',
|
83
|
+
:roles => [],
|
84
|
+
:custom_attrs => {}
|
85
|
+
}.merge(template)
|
86
|
+
|
87
|
+
fail "You must specify at least 1 role for template '#{name}'" if template[:roles].empty? && !allow_no_roles
|
88
|
+
id_cache = {}
|
89
|
+
template[:roles].map! do |role|
|
90
|
+
fail "Some roles in template '#{name}' are missing a name." if role[:name].nil?
|
91
|
+
fail "Role '#{role[:name]}' in template '#{name}' is missing a vm_template." if role[:vm_template].nil? && !allow_no_vm_template
|
92
|
+
new_role = {
|
93
|
+
:cardinality => role[:min_vms] || 1,
|
94
|
+
:elasticity_policies => [],
|
95
|
+
:scheduled_policies => []
|
96
|
+
}.merge(role)
|
97
|
+
if role[:vm_template].is_a?(String)
|
98
|
+
if id_cache[role[:vm_template]].nil?
|
99
|
+
template_from_one = driver.one.get_resource(:template, :name => role[:vm_template])
|
100
|
+
fail "Could not find a template with the name '#{role[:vm_template]}'" if template_from_one.nil?
|
101
|
+
id = template_from_one.to_hash['VMTEMPLATE']['ID'].to_i
|
102
|
+
id_cache[role[:vm_template]] = id
|
103
|
+
new_role[:vm_template] = id
|
104
|
+
else
|
105
|
+
new_role[:vm_template] = id_cache[role[:vm_template]]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
new_role
|
109
|
+
end
|
110
|
+
template
|
111
|
+
end
|
112
|
+
|
113
|
+
# Helper for merge_template
|
114
|
+
def special_merge_hash(base_hash, new_hash, delete_roles = true)
|
115
|
+
keys_to_delete = []
|
116
|
+
merged = base_hash.merge(new_hash) do |key, oldval, newval|
|
117
|
+
# This is probably a redundant fail ...
|
118
|
+
fail 'Class of values in the templates must remain the same. If you want to delete an entry, set it to nil.' unless
|
119
|
+
oldval.is_a?(newval.class) || newval.is_a?(NilClass) || key == :vm_template
|
120
|
+
case newval
|
121
|
+
when NilClass
|
122
|
+
keys_to_delete.push(key)
|
123
|
+
nil
|
124
|
+
when Array
|
125
|
+
if key == :roles
|
126
|
+
new_array = []
|
127
|
+
old_as_hash = Hash[oldval.collect { |role| [role[:name], role] }]
|
128
|
+
|
129
|
+
newval.each do |role|
|
130
|
+
if role.key?(:delete_role) && delete_roles
|
131
|
+
old_as_hash.delete(role[:name])
|
132
|
+
next
|
133
|
+
end
|
134
|
+
fail 'All roles must have a name.' if role[:name].nil?
|
135
|
+
if old_as_hash.key?(role[:name])
|
136
|
+
new_array.push(special_merge_hash(old_as_hash[role[:name]], role))
|
137
|
+
old_as_hash.delete(role[:name])
|
138
|
+
else
|
139
|
+
new_array.push(role)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
new_array + old_as_hash.values
|
144
|
+
else
|
145
|
+
newval
|
146
|
+
end
|
147
|
+
when Hash
|
148
|
+
special_merge_hash(oldval, newval)
|
149
|
+
else
|
150
|
+
newval
|
151
|
+
end
|
152
|
+
end
|
153
|
+
keys_to_delete.each { |key| merged.delete(key) }
|
154
|
+
merged
|
155
|
+
end
|
156
|
+
|
157
|
+
# Performs a overwrite-merge of two OneFlow templates, any key with nil value will be deleted
|
158
|
+
def merge_template(base_tpl, new_tpl, overwrite_name = false, delete_roles = true)
|
159
|
+
fail 'Service template name changing is not supported.' if new_tpl.key?(:name) && !overwrite_name && base_tpl[:name] != new_tpl[:name]
|
160
|
+
special_merge_hash(base_tpl, new_tpl, delete_roles)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Issues warnings for a failsafe override
|
164
|
+
def override_failsafe_warn
|
165
|
+
Chef::Log.warn('You have chose to use an action that is untested / partially implemented.')
|
166
|
+
Chef::Log.warn('Specifically, the driver will send the appropriate POST request to the Flow API')
|
167
|
+
Chef::Log.warn('But the driver will not verify that the action ran successfully, or ran at all.')
|
168
|
+
Chef::Log.warn('Moreover, the driver will not wait for the action complete, as in, the action will')
|
169
|
+
Chef::Log.warn('run asynchronously, meaning dependent actions after this one may fail.')
|
170
|
+
Chef::Log.warn('Use at your own risk. Please report any issues.')
|
171
|
+
end
|
172
|
+
|
173
|
+
# Validate the attributes period and number
|
174
|
+
def validate_role_action(period, number)
|
175
|
+
fail "Make sure 'period' >= 0" if !period.empty? && period.to_i < 0
|
176
|
+
fail "Make sure 'number' >= 0" if !number.empty? && number.to_i < 0
|
177
|
+
end
|
178
|
+
|
179
|
+
# REST call to flow api
|
180
|
+
def request(method, url, payload = '{}')
|
181
|
+
case payload
|
182
|
+
when Hash
|
183
|
+
RestClient::Request.execute(
|
184
|
+
method: method,
|
185
|
+
url: @flow_url + url,
|
186
|
+
user: @username,
|
187
|
+
password: @password,
|
188
|
+
payload: payload.to_json
|
189
|
+
)
|
190
|
+
when String
|
191
|
+
JSON.parse(payload)
|
192
|
+
RestClient::Request.execute(
|
193
|
+
method: method,
|
194
|
+
url: @flow_url + url,
|
195
|
+
user: @username,
|
196
|
+
password: @password,
|
197
|
+
payload: payload
|
198
|
+
)
|
199
|
+
else
|
200
|
+
fail 'Payload must be hash or json string.'
|
201
|
+
end
|
202
|
+
rescue JSON::ParserError
|
203
|
+
fail 'Malformed json string.'
|
204
|
+
rescue RestClient::ResourceNotFound, RestClient::BadRequest, RestClient::InternalServerError => e
|
205
|
+
raise OpenNebulaException, "#{e}\nThere's a problem. Here's a hint:\n#{e.response}"
|
206
|
+
end
|
207
|
+
|
208
|
+
# Converts all arrays to sets
|
209
|
+
def recursive_array_to_set(object)
|
210
|
+
case object
|
211
|
+
when Array
|
212
|
+
return object.map { |e| recursive_array_to_set(e) }.to_set
|
213
|
+
when Hash
|
214
|
+
object.each do |key, value|
|
215
|
+
object[key] = recursive_array_to_set(value)
|
216
|
+
end
|
217
|
+
return object
|
218
|
+
else
|
219
|
+
return object
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Checks if two hashes are equal, ignore array order
|
224
|
+
def hash_eq?(hash1, hash2)
|
225
|
+
recursive_array_to_set(Marshal.load(Marshal.dump(hash1))) == recursive_array_to_set(Marshal.load(Marshal.dump(hash2)))
|
226
|
+
end
|
227
|
+
|
228
|
+
# Returns all of the IDs of a service or template that matches a name
|
229
|
+
def get_ids(type, name)
|
230
|
+
response = request(:get, type == :template ? '/service_template' : '/service')
|
231
|
+
ids = []
|
232
|
+
data = JSON.parse(response, :symbolize_names => true)
|
233
|
+
return [] if data[:DOCUMENT_POOL][:DOCUMENT].nil?
|
234
|
+
data[:DOCUMENT_POOL][:DOCUMENT].each { |e| ids.push(e[:ID].to_i) if e[:NAME] == name }
|
235
|
+
ids
|
236
|
+
end
|
237
|
+
|
238
|
+
# Gets a single ID of a service or template, fails if there's not exactly 1, or returns nil if there 0 and nil_if_none
|
239
|
+
def get_unique_id(type, name, nil_if_none = false)
|
240
|
+
matches = get_ids(type, name)
|
241
|
+
if matches.empty?
|
242
|
+
return nil if nil_if_none
|
243
|
+
fail "There are no OneFlow #{type}s with the name '#{name}'"
|
244
|
+
elsif matches.length > 1
|
245
|
+
fail "There are multiple OneFlow #{type}s with the name '#{name}'"
|
246
|
+
else
|
247
|
+
matches[0]
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# Check if a service or template exists
|
252
|
+
def exists?(type, name)
|
253
|
+
!get_ids(type, name).empty?
|
254
|
+
end
|
255
|
+
|
256
|
+
# Gets permission of service or template
|
257
|
+
def get_permissions(type, id)
|
258
|
+
id = id.to_s
|
259
|
+
response = request(:get, type == :template ? '/service_template' : '/service')
|
260
|
+
data = JSON.parse(response, :symbolize_names => true)[:DOCUMENT_POOL][:DOCUMENT]
|
261
|
+
data.each do |tpl|
|
262
|
+
next unless tpl[:ID] == id
|
263
|
+
perms = tpl[:PERMISSIONS]
|
264
|
+
mode = ''
|
265
|
+
[:OWNER_U, :OWNER_M, :OWNER_A, :GROUP_U, :GROUP_M, :GROUP_A, :OTHER_U, :OTHER_M, :OTHER_A].each { |m| mode += perms[m] }
|
266
|
+
return mode.to_i(2).to_s(8)
|
267
|
+
end
|
268
|
+
fail "#{type} with id=#{id} does not exist."
|
269
|
+
end
|
270
|
+
|
271
|
+
# Wrapper for get_ids
|
272
|
+
def get_template_ids(name)
|
273
|
+
get_ids(:template, name)
|
274
|
+
end
|
275
|
+
|
276
|
+
# Wrapper for get_unique_id
|
277
|
+
def get_unique_template_id(name, nil_if_none = false)
|
278
|
+
get_unique_id(:template, name, nil_if_none)
|
279
|
+
end
|
280
|
+
|
281
|
+
# Wrapper for exists?
|
282
|
+
def template_exists?(name)
|
283
|
+
exists?(:template, name)
|
284
|
+
end
|
285
|
+
|
286
|
+
# Gets a template given a template ID
|
287
|
+
def get_template(id)
|
288
|
+
response = request(:get, "/service_template/#{id}")
|
289
|
+
JSON.parse(response, :symbolize_names => true)[:DOCUMENT][:TEMPLATE][:BODY]
|
290
|
+
end
|
291
|
+
|
292
|
+
# Wrapper for get_permissions
|
293
|
+
def get_template_permissions(id)
|
294
|
+
get_permissions(:template, id)
|
295
|
+
end
|
296
|
+
|
297
|
+
# Wrapper for get_ids
|
298
|
+
def get_service_ids(name)
|
299
|
+
get_ids(:service, name)
|
300
|
+
end
|
301
|
+
|
302
|
+
# Wrapper for get_unique_id
|
303
|
+
def get_unique_service_id(name, nil_if_none = false)
|
304
|
+
get_unique_id(:service, name, nil_if_none)
|
305
|
+
end
|
306
|
+
|
307
|
+
# Wrapper for exists?
|
308
|
+
def service_exists?(name)
|
309
|
+
exists?(:service, name)
|
310
|
+
end
|
311
|
+
|
312
|
+
# Wrapper for get_permissions
|
313
|
+
def get_service_permissions(id)
|
314
|
+
get_permissions(:service, id)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Returns the template of a service with runtime content removed
|
318
|
+
def get_reduced_service_template(id)
|
319
|
+
response = request(:get, "/service/#{id}")
|
320
|
+
template_from_one = JSON.parse(response, :symbolize_names => true)[:DOCUMENT][:TEMPLATE][:BODY]
|
321
|
+
service_name = template_from_one[:name]
|
322
|
+
[:log, :name, :state, :custom_attrs_values].each { |key| template_from_one.delete(key) }
|
323
|
+
template_from_one[:roles].each do |role|
|
324
|
+
role[:nodes].each do |node|
|
325
|
+
unless node[:running]
|
326
|
+
Chef::Log.warn("A node in role '#{node[:vm_info][:VM][:USER_TEMPLATE][:ROLE_NAME]}' of service '#{service_name}' is not normal!")
|
327
|
+
end
|
328
|
+
end
|
329
|
+
[:cardinality, :nodes, :state, :disposed_nodes, :cooldown_end, :last_vmname, :user_inputs_values, :vm_template_contents].each { |key| role.delete(key) }
|
330
|
+
end
|
331
|
+
template_from_one
|
332
|
+
end
|
333
|
+
|
334
|
+
# Gets the state of a service
|
335
|
+
# 0 => PENDING, 1 => DEPLOYING, 2 => RUNNING, 3 => UNDEPLOYING, 5 => DONE,
|
336
|
+
# 7 => FAILED_DEPLOYING, 8 => SCALING, 9 => FAILED_SCALING, 10 => COOLDOWN
|
337
|
+
def get_service_state(id)
|
338
|
+
response = request(:get, "/service/#{id}")
|
339
|
+
JSON.parse(response, :symbolize_names => true)[:DOCUMENT][:TEMPLATE][:BODY][:state].to_i
|
340
|
+
end
|
341
|
+
|
342
|
+
# Returns a role of a service
|
343
|
+
def get_role(service_id, role_name)
|
344
|
+
response = request(:get, "/service/#{service_id}")
|
345
|
+
JSON.parse(response, :symbolize_names => true)[:DOCUMENT][:TEMPLATE][:BODY][:roles].each { |role| return role if role[:name] == role_name }
|
346
|
+
fail "#{role_name} doesn't seem to exist!"
|
347
|
+
end
|
348
|
+
|
349
|
+
# Returns the state of a role
|
350
|
+
# It seems that regardless of the state of the VMs, the state of a role will be RUNNING
|
351
|
+
# So I will be doing a workaround where I will return that it's SUSPENDED if all of the VMs are SUSPENDED
|
352
|
+
# nil => role doesn't exist, -1 => there are no VMs, 1 => PENDING,
|
353
|
+
# 3 => RUNNING, 4 => STOPPED, 5 => SUSPENDED, 8 => POWEROFF, 9 => UNDEPLOYED
|
354
|
+
def get_role_state(id, role_name)
|
355
|
+
role = get_role(id, role_name)
|
356
|
+
return -1 if role[:cardinality].to_i == 0
|
357
|
+
state_counter = { 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 8 => 0, 9 => 0 }
|
358
|
+
role[:nodes].each do |node|
|
359
|
+
state = node[:vm_info][:VM][:STATE].to_i
|
360
|
+
fail "UNSUPPORTED STATE #{state}" if state_counter[state].nil?
|
361
|
+
state_counter[state] += 1
|
362
|
+
return state if state_counter[state] == role[:cardinality].to_i
|
363
|
+
end
|
364
|
+
state_counter # Return the hash of counters if states are staggered
|
365
|
+
end
|
366
|
+
|
367
|
+
# Gets the cardinality of a role
|
368
|
+
def get_role_cardinality(id, role_name)
|
369
|
+
get_role(id, role_name)[:cardinality].to_i
|
370
|
+
end
|
371
|
+
|
372
|
+
# Creates a post request for an action
|
373
|
+
def perform_action(url, action, params)
|
374
|
+
request(:post, url, "{\"action\":{\"perform\":\"#{action}\",\"params\":#{params.to_json}}}")
|
375
|
+
end
|
376
|
+
|
377
|
+
####################
|
378
|
+
# TEMPLATE ACTIONS #
|
379
|
+
####################
|
380
|
+
|
381
|
+
# Creates a template in ONE
|
382
|
+
def create_template(payload)
|
383
|
+
request(:post, '/service_template', payload)
|
384
|
+
true
|
385
|
+
end
|
386
|
+
|
387
|
+
# Updates a template in ONE
|
388
|
+
def update_template(template_name, payload)
|
389
|
+
request(:put, "/service_template/#{get_unique_template_id(template_name)}", payload)
|
390
|
+
end
|
391
|
+
|
392
|
+
# Deletes a template in ONE
|
393
|
+
def delete_template(template_id)
|
394
|
+
request(:delete, "/service_template/#{template_id}")
|
395
|
+
end
|
396
|
+
|
397
|
+
# Spawns a service from a template
|
398
|
+
def instantiate_template(tid, template, service_name)
|
399
|
+
url = "/service_template/#{tid}/action"
|
400
|
+
perform_action(url, 'instantiate', :merge_template => template)
|
401
|
+
|
402
|
+
service_id = get_unique_service_id(service_name)
|
403
|
+
state = nil
|
404
|
+
while state != SERVICE_RUNNING
|
405
|
+
Chef::Log.info("Waiting for RUNNING for '#{service_name}'")
|
406
|
+
sleep(15)
|
407
|
+
state = get_service_state(service_id)
|
408
|
+
fail "Service failed to deploy ...\nThere's probably something wrong with your template." if state == SERVICE_FAILED_DEPLOYING
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
# Modifies the permissions of a template
|
413
|
+
def chmod_template(template_id, octet)
|
414
|
+
url = "/service_template/#{template_id}/action"
|
415
|
+
perform_action(url, 'chmod', :octet => octet)
|
416
|
+
end
|
417
|
+
|
418
|
+
###################
|
419
|
+
# SERVICE ACTIONS #
|
420
|
+
###################
|
421
|
+
|
422
|
+
# Deletes a service in ONE
|
423
|
+
def delete_service(service_id)
|
424
|
+
request(:delete, "/service/#{service_id}")
|
425
|
+
end
|
426
|
+
|
427
|
+
# Performs shutdown on an entire service
|
428
|
+
def shutdown_service(service_name, sid)
|
429
|
+
url = "/service/#{sid}/action"
|
430
|
+
perform_action(url, 'shutdown', {})
|
431
|
+
|
432
|
+
state = nil
|
433
|
+
while state != SERVICE_DONE
|
434
|
+
Chef::Log.info("Waiting for SHUTDOWN COMPLETE for '#{service_name}'")
|
435
|
+
sleep(15)
|
436
|
+
state = get_service_state(sid)
|
437
|
+
fail 'Service failed to shutdown ...' unless Set[SERVICE_RUNNING, SERVICE_UNDEPLOYING, SERVICE_DONE].include?(state)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
# Performs the recover action on a service
|
442
|
+
def recover_service(service_id, service_name)
|
443
|
+
url = "/service/#{service_id}/action"
|
444
|
+
perform_action(url, 'recover', {})
|
445
|
+
|
446
|
+
state = nil
|
447
|
+
while state != SERVICE_RUNNING
|
448
|
+
Chef::Log.info("Waiting for RUNNING for '#{service_name}'")
|
449
|
+
sleep(15)
|
450
|
+
state = get_service_state(service_id)
|
451
|
+
fail 'Service failed to recover ...' if state == SERVICE_FAILED_DEPLOYING
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
# Modifies the permissions of a service
|
456
|
+
def chmod_service(sid, octet)
|
457
|
+
url = "/service/#{sid}/action"
|
458
|
+
perform_action(url, 'chmod', :octet => octet)
|
459
|
+
end
|
460
|
+
|
461
|
+
# Performs an action on a role
|
462
|
+
def role_action(sid, role_name, action, period, number, desired_state = nil)
|
463
|
+
validate_role_action(period, number)
|
464
|
+
url = "/service/#{sid}/role/#{role_name}/action"
|
465
|
+
perform_action(url, action, :period => period, :number => number)
|
466
|
+
|
467
|
+
state = nil
|
468
|
+
while state != desired_state
|
469
|
+
Chef::Log.info("Waiting for #{action} to complete")
|
470
|
+
sleep(15)
|
471
|
+
state = get_role_state(sid, role_name)
|
472
|
+
fail "#{action} failed. Got unsupported state #{state}" unless Set[ROLE_NO_VMS, ROLE_PENDING, ROLE_RUNNING, ROLE_STOPPED, ROLE_SUSPENDED, ROLE_POWEROFF, ROLE_UNDEPLOYED].include?(state)
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
# Scales a role to a new cardinality
|
477
|
+
def role_scale(service_id, service_name, role_name, card, force)
|
478
|
+
request(:put, "/service/#{service_id}/role/#{role_name}", :cardinality => card, :force => force)
|
479
|
+
|
480
|
+
state = nil
|
481
|
+
while state != SERVICE_RUNNING
|
482
|
+
Chef::Log.info("Waiting for RUNNING for '#{service_name}'")
|
483
|
+
sleep(15)
|
484
|
+
state = get_service_state(service_id)
|
485
|
+
fail 'Service failed to scale ...' if state == SERVICE_FAILED_SCALING
|
486
|
+
end
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|