chef-provisioning-oneview 1.0.1 → 1.1.0
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/README.md +43 -3
- data/lib/chef/provisioning/create_machine.rb +52 -0
- data/lib/chef/provisioning/customize_machine.rb +78 -0
- data/lib/chef/provisioning/icsp/api_v104.rb +27 -0
- data/lib/chef/provisioning/icsp/icsp_api.rb +282 -0
- data/lib/chef/provisioning/oneview/oneview_api.rb +56 -357
- data/lib/chef/provisioning/oneview/san_storage.rb +91 -0
- data/lib/chef/provisioning/oneview/v1.2/api.rb +3 -0
- data/lib/chef/provisioning/oneview_driver.rb +42 -5
- data/lib/chef/provisioning/rest.rb +51 -0
- data/lib/chef/provisioning/{oneview/version.rb → version.rb} +1 -1
- data/spec/shared_context.rb +77 -0
- data/spec/spec_helper.rb +8 -6
- data/spec/{unit/support → support}/fake_action_handler.rb +0 -0
- data/spec/support/fake_icsp.rb +73 -21
- data/spec/support/fake_machine_spec.rb +18 -0
- data/spec/support/fake_oneview.rb +148 -21
- data/spec/support/fixtures/icsp/v102/error_404.json +13 -13
- data/spec/support/fixtures/icsp/v102/login.json +4 -4
- data/spec/support/fixtures/icsp/v102/os-deployment-build-plans.json +99 -99
- data/spec/support/fixtures/icsp/v102/{os-deployment-servers_managed.json → os-deployment-servers.json} +178 -178
- data/spec/support/fixtures/icsp/v102/os-deployment-servers_1670001.json +83 -0
- data/spec/support/fixtures/icsp/v102/os-deployment-servers_fakesn.json +9 -0
- data/spec/support/fixtures/icsp/v102/{server_by_sn.json → server_by_sn_VCGE9KB041.json} +44 -44
- data/spec/support/fixtures/icsp/v102/server_by_sn_empty.json +16 -0
- data/spec/support/fixtures/icsp/v102/version.json +3 -3
- data/spec/support/fixtures/oneview/v120/error_404.json +13 -13
- data/spec/support/fixtures/oneview/v120/login.json +4 -4
- data/spec/support/fixtures/oneview/v120/server-hardware.json +1475 -1475
- data/spec/support/fixtures/oneview/v120/server-hardware_Template-WebServer.json +468 -0
- data/spec/support/fixtures/oneview/v120/server-hardware_specific.json +151 -0
- data/spec/support/fixtures/oneview/v120/server-profiles.json +368 -746
- data/spec/support/fixtures/oneview/v120/server-profiles_invalid_filter.json +14 -0
- data/spec/support/fixtures/oneview/v120/{server-profiles_specific.json → server-profiles_name_Template-WebServer.json} +132 -132
- data/spec/support/fixtures/oneview/v120/server-profiles_name_Template-WebServerWithSAN.json +200 -0
- data/spec/support/fixtures/oneview/v120/server-profiles_name_chef-web01.json +133 -0
- data/spec/support/fixtures/oneview/v120/server-profiles_name_chef-web03.json +133 -0
- data/spec/support/fixtures/oneview/v120/server-profiles_name_empty.json +15 -0
- data/spec/support/fixtures/oneview/v120/server-profiles_sn_VCGE9KB041.json +133 -0
- data/spec/support/fixtures/oneview/v120/server-profiles_sn_VCGE9KB042.json +206 -0
- data/spec/support/fixtures/oneview/v120/server-profiles_sn_empty.json +15 -0
- data/spec/support/fixtures/oneview/v120/storage-volumes_1B5D3CA2-6C5B-41C2-8B97-1821F1883F22.json +26 -0
- data/spec/support/fixtures/oneview/v120/tasks_fake_active.json +5 -0
- data/spec/support/fixtures/oneview/v120/tasks_fake_complete.json +5 -0
- data/spec/support/fixtures/oneview/v120/version.json +3 -3
- data/spec/support/fixtures/oneview/v200/server-profile-templates_WebServerTemplate.json +109 -0
- data/spec/support/fixtures/oneview/v200/server-profile-templates_WebServerTemplateWithSAN.json +144 -0
- data/spec/support/fixtures/oneview/v200/server-profile-templates_invalid.json +16 -0
- data/spec/support/fixtures/oneview/v200/server-profile-templates_new-profile_WebServerTemplate.json +125 -0
- data/spec/support/fixtures/oneview/v200/server-profile-templates_new-profile_WebServerTemplateWithSAN.json +178 -0
- data/spec/support/fixtures/oneview/v200/version.json +4 -0
- data/spec/unit/create_machine_spec.rb +78 -0
- data/spec/unit/destroy_spec.rb +26 -0
- data/spec/unit/icsp_nic_teams_spec.rb +38 -0
- data/spec/unit/icsp_search_spec.rb +25 -0
- data/spec/unit/oneview_driver_spec.rb +37 -64
- data/spec/unit/oneview_login_spec.rb +23 -0
- data/spec/unit/oneview_power_spec.rb +51 -0
- data/spec/unit/oneview_san_spec.rb +86 -0
- data/spec/unit/oneview_search_spec.rb +63 -0
- data/spec/unit/rest_api_spec.rb +115 -0
- metadata +90 -9
- data/lib/chef/provisioning/oneview/v1.20/api.rb +0 -3
@@ -1,61 +1,11 @@
|
|
1
|
-
|
2
|
-
require_relative 'v2.0/api'
|
1
|
+
Dir[File.dirname(__FILE__) + '/**/*.rb'].each {|file| require file } # Include all helper files in this directory & subdirectories
|
3
2
|
|
4
3
|
module OneViewAPI
|
5
4
|
private
|
6
5
|
|
7
|
-
include
|
6
|
+
include OneViewAPIv1_2
|
8
7
|
include OneViewAPIv2_0
|
9
|
-
|
10
|
-
# API calls for OneView and ICSP
|
11
|
-
def rest_api(host, type, path, options = {})
|
12
|
-
disable_ssl = false
|
13
|
-
case host
|
14
|
-
when 'icsp', :icsp
|
15
|
-
uri = URI.parse(URI.escape(@icsp_base_url + path))
|
16
|
-
options['X-API-Version'] ||= @icsp_api_version unless [:put, 'put'].include?(type.downcase)
|
17
|
-
options['auth'] ||= @icsp_key
|
18
|
-
disable_ssl = true if @icsp_disable_ssl
|
19
|
-
when 'oneview', :oneview
|
20
|
-
uri = URI.parse(URI.escape(@oneview_base_url + path))
|
21
|
-
options['X-API-Version'] ||= @oneview_api_version
|
22
|
-
options['auth'] ||= @oneview_key
|
23
|
-
disable_ssl = true if @oneview_disable_ssl
|
24
|
-
else
|
25
|
-
fail "Invalid rest host: #{host}"
|
26
|
-
end
|
27
|
-
|
28
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
29
|
-
http.use_ssl = true if uri.scheme == 'https'
|
30
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if disable_ssl
|
31
|
-
|
32
|
-
case type.downcase
|
33
|
-
when 'get', :get
|
34
|
-
request = Net::HTTP::Get.new(uri.request_uri)
|
35
|
-
when 'post', :post
|
36
|
-
request = Net::HTTP::Post.new(uri.request_uri)
|
37
|
-
when 'put', :put
|
38
|
-
request = Net::HTTP::Put.new(uri.request_uri)
|
39
|
-
when 'delete', :delete
|
40
|
-
request = Net::HTTP::Delete.new(uri.request_uri)
|
41
|
-
else
|
42
|
-
fail "Invalid rest call: #{type}"
|
43
|
-
end
|
44
|
-
options['Content-Type'] ||= 'application/json'
|
45
|
-
options.delete('Content-Type') if [:none, 'none', nil].include?(options['Content-Type'])
|
46
|
-
options.delete('X-API-Version') if [:none, 'none', nil].include?(options['X-API-Version'])
|
47
|
-
options.delete('auth') if [:none, 'none', nil].include?(options['auth'])
|
48
|
-
options.each do |key, val|
|
49
|
-
if key.downcase == 'body'
|
50
|
-
request.body = val.to_json rescue val
|
51
|
-
else
|
52
|
-
request[key] = val
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
response = http.request(request)
|
57
|
-
JSON.parse(response.body) rescue response
|
58
|
-
end
|
8
|
+
include OneViewSanStorage
|
59
9
|
|
60
10
|
def get_oneview_api_version
|
61
11
|
begin
|
@@ -72,42 +22,6 @@ module OneViewAPI
|
|
72
22
|
version
|
73
23
|
end
|
74
24
|
|
75
|
-
def get_icsp_api_version
|
76
|
-
begin
|
77
|
-
version = rest_api(:icsp, :get, '/rest/version', { 'Content-Type' => :none, 'X-API-Version' => :none, 'auth' => :none })['currentVersion']
|
78
|
-
fail "Couldn't get API version" unless version
|
79
|
-
if version.class != Fixnum
|
80
|
-
version = version.to_i
|
81
|
-
fail 'API version type mismatch' if !version > 0
|
82
|
-
end
|
83
|
-
rescue
|
84
|
-
puts 'Failed to get ICSP API version. Setting to default (102)'
|
85
|
-
version = 102
|
86
|
-
end
|
87
|
-
version
|
88
|
-
end
|
89
|
-
|
90
|
-
# Login functions
|
91
|
-
def auth_tokens
|
92
|
-
@icsp_key ||= login_to_icsp
|
93
|
-
@oneview_key ||= login_to_oneview
|
94
|
-
{ 'icsp_key' => @icsp_key, 'oneview_key' => @oneview_key }
|
95
|
-
end
|
96
|
-
|
97
|
-
def login_to_icsp
|
98
|
-
path = '/rest/login-sessions'
|
99
|
-
options = {
|
100
|
-
'body' => {
|
101
|
-
'userName' => @icsp_username,
|
102
|
-
'password' => @icsp_password,
|
103
|
-
'authLoginDomain' => 'LOCAL'
|
104
|
-
}
|
105
|
-
}
|
106
|
-
response = rest_api(:icsp, :post, path, options)
|
107
|
-
return response['sessionID'] if response['sessionID']
|
108
|
-
fail("\nERROR! Couldn't log into OneView server at #{@oneview_base_url}. Response:\n#{response}")
|
109
|
-
end
|
110
|
-
|
111
25
|
def login_to_oneview
|
112
26
|
path = '/rest/login-sessions'
|
113
27
|
options = {
|
@@ -122,33 +36,69 @@ module OneViewAPI
|
|
122
36
|
fail("\nERROR! Couldn't log into OneView server at #{@oneview_base_url}. Response:\n#{response}")
|
123
37
|
end
|
124
38
|
|
125
|
-
|
126
39
|
def get_oneview_profile_by_sn(serialNumber)
|
40
|
+
fail 'Must specify a serialNumber!' if serialNumber.nil? || serialNumber.empty?
|
127
41
|
matching_profiles = rest_api(:oneview, :get, "/rest/server-profiles?filter=serialNumber matches '#{serialNumber}'&sort=name:asc")
|
42
|
+
fail "Failed to get oneview profile by serialNumber: #{serialNumber}. Response: #{matching_profiles}" unless matching_profiles['count']
|
128
43
|
return matching_profiles['members'].first if matching_profiles['count'] > 0
|
129
44
|
nil
|
130
45
|
end
|
131
46
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
47
|
+
# Search for OneView Template by name
|
48
|
+
def get_oneview_template(template_name)
|
49
|
+
if @current_oneview_api_version >= 200
|
50
|
+
# Look for Server Profile Template (OneView 2.0 or higher)
|
51
|
+
options = { 'X-API-Version' => 200 }
|
52
|
+
templates = rest_api(:oneview, :get, "/rest/server-profile-templates?filter=\"name matches '#{template_name}'\"&sort=name:asc", options)['members']
|
53
|
+
return rest_api(:oneview, :get, "#{templates.first['uri']}/new-profile", options) if templates && templates.count == 1
|
54
|
+
fail "'#{template_name}' matches multiple templates! Please use a unique template name." if templates && templates.count > 1
|
137
55
|
end
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
56
|
+
|
57
|
+
# Look for Server Profile as second option
|
58
|
+
templates = rest_api(:oneview, :get, "/rest/server-profiles?filter=\"name matches '#{template_name}'\"&sort=name:asc")['members']
|
59
|
+
if templates && templates.count == 1
|
60
|
+
# Remove unwanted fields
|
61
|
+
%w(uri serialNumber uuid taskUri).each {|key| templates.first[key] = nil}
|
62
|
+
templates.first['connections'].each do |c|
|
63
|
+
%w(wwnn wwpn mac deploymentStatus interconnectUri wwpnType macType).each {|key| c[key] = nil}
|
147
64
|
end
|
65
|
+
return templates.first
|
148
66
|
end
|
149
|
-
|
67
|
+
fail "'#{template_name}' matches multiple profiles! Please use a unique template name." if templates && templates.count > 1
|
68
|
+
|
69
|
+
fail "Template '#{template_name}' not found! Please match the template name with one that exists on OneView."
|
150
70
|
end
|
151
71
|
|
72
|
+
def available_hardware_for_template(template)
|
73
|
+
server_hardware_type_uri = template['serverHardwareTypeUri']
|
74
|
+
enclosure_group_uri = template['enclosureGroupUri']
|
75
|
+
fail 'Template must specify a valid hardware type uri!' if server_hardware_type_uri.nil? || server_hardware_type_uri.empty?
|
76
|
+
fail 'Template must specify a valid hardware type uri!' if enclosure_group_uri.nil? || enclosure_group_uri.empty?
|
77
|
+
params = "sort=name:asc&filter=serverHardwareTypeUri='#{server_hardware_type_uri}'&filter=serverGroupUri='#{enclosure_group_uri}'"
|
78
|
+
blades = rest_api(:oneview, :get, "/rest/server-hardware?#{params}")
|
79
|
+
fail 'Error! No available blades that are compatible with the server template!' unless blades['count'] > 0
|
80
|
+
blades['members'].each do |member|
|
81
|
+
return member if member['state'] == 'NoProfileApplied'
|
82
|
+
end
|
83
|
+
fail 'No more blades are available for provisioning!' # Every bay is full and no more machines can be allocated
|
84
|
+
end
|
85
|
+
|
86
|
+
def oneview_wait_for(task_uri, wait_iterations = 60, sleep_seconds = 10) # Default time is 10 min
|
87
|
+
fail 'Must specify a task_uri!' if task_uri.nil? || task_uri.empty?
|
88
|
+
wait_iterations.times do
|
89
|
+
task = rest_api(:oneview, :get, task_uri)
|
90
|
+
case task['taskState'].downcase
|
91
|
+
when 'completed'
|
92
|
+
return true
|
93
|
+
when 'error', 'killed', 'terminated'
|
94
|
+
return task
|
95
|
+
else
|
96
|
+
print '.'
|
97
|
+
sleep sleep_seconds
|
98
|
+
end
|
99
|
+
end
|
100
|
+
false
|
101
|
+
end
|
152
102
|
|
153
103
|
def power_on(action_handler, machine_spec, hardware_uri = nil)
|
154
104
|
set_power_state(action_handler, machine_spec, 'on', hardware_uri)
|
@@ -169,6 +119,7 @@ module OneViewAPI
|
|
169
119
|
|
170
120
|
if hardware_uri.nil?
|
171
121
|
profile = get_oneview_profile_by_sn(machine_spec.reference['serial_number'])
|
122
|
+
fail "Could not power #{state} #{machine_spec.name}: Profile with serial number '#{machine_spec.reference['serial_number']}' not found!" unless profile
|
172
123
|
hardware_uri = profile['serverHardwareUri']
|
173
124
|
end
|
174
125
|
|
@@ -190,258 +141,6 @@ module OneViewAPI
|
|
190
141
|
hardware_uri
|
191
142
|
end
|
192
143
|
|
193
|
-
# Chef oneview provisioning
|
194
|
-
def create_machine(action_handler, machine_spec, machine_options)
|
195
|
-
host_name = machine_options[:driver_options][:host_name]
|
196
|
-
server_template = machine_options[:driver_options][:server_template]
|
197
|
-
|
198
|
-
auth_tokens # Login (to both ICSP and OneView)
|
199
|
-
|
200
|
-
# Check if profile exists first
|
201
|
-
matching_profiles = rest_api(:oneview, :get, "/rest/server-profiles?filter=name matches '#{host_name}'&sort=name:asc")
|
202
|
-
|
203
|
-
if matching_profiles['count'] > 0
|
204
|
-
profile = matching_profiles['members'].first
|
205
|
-
power_on(action_handler, machine_spec, profile['serverHardwareUri']) # Make sure server is started
|
206
|
-
return profile
|
207
|
-
end
|
208
|
-
|
209
|
-
|
210
|
-
# Get HPOVProfile by name (to see if it already exists)
|
211
|
-
# For 120 verion of Oneview , we are going to retrive a predefined unassociated server profile
|
212
|
-
templates = rest_api(:oneview, :get, "/rest/server-profiles?filter=name matches '#{server_template}'&sort=name:asc")
|
213
|
-
unless templates['members'] && templates['members'].count > 0
|
214
|
-
fail "Template '#{server_template}' not found! Please match the template name with one that exists on OneView."
|
215
|
-
end
|
216
|
-
|
217
|
-
template_uri = templates['members'].first['uri']
|
218
|
-
server_hardware_type_uri = templates['members'].first['serverHardwareTypeUri']
|
219
|
-
enclosure_group_uri = templates['members'].first['enclosureGroupUri']
|
220
|
-
|
221
|
-
# Get availabe (and compatible) HP OV server blades. Take first one.
|
222
|
-
blades = rest_api(:oneview, :get, "/rest/server-hardware?sort=name:asc&filter=serverHardwareTypeUri='#{server_hardware_type_uri}'&filter=serverGroupUri='#{enclosure_group_uri}'")
|
223
|
-
fail 'Error! No available blades that are compatible with the server profile!' unless blades['count'] > 0
|
224
|
-
chosen_blade = nil
|
225
|
-
blades['members'].each do |member|
|
226
|
-
if member['state'] != 'ProfileApplied' && member['state'] != 'ApplyingProfile'
|
227
|
-
chosen_blade = member
|
228
|
-
break
|
229
|
-
end
|
230
|
-
end
|
231
|
-
if chosen_blade.nil? # TODO
|
232
|
-
# Every bay is full and no more machines can be allocated
|
233
|
-
fail 'No more blades are available for provisioning!'
|
234
|
-
end
|
235
|
-
|
236
|
-
power_off(action_handler, machine_spec, chosen_blade['uri'])
|
237
|
-
# New-HPOVProfileFromTemplate
|
238
|
-
# Create new profile instance from template
|
239
|
-
action_handler.perform_action "Initialize creation of server template for #{machine_spec.name}" do
|
240
|
-
action_handler.report_progress "INFO: Initializing creation of server template for #{machine_spec.name}"
|
241
|
-
|
242
|
-
new_template_profile = rest_api(:oneview, :get, "#{template_uri}")
|
243
|
-
|
244
|
-
# Take response, add name & hardware uri, and post back to /rest/server-profiles
|
245
|
-
new_template_profile['name'] = host_name
|
246
|
-
new_template_profile['uri'] = nil
|
247
|
-
new_template_profile['serialNumber'] = nil
|
248
|
-
new_template_profile['uuid'] = nil
|
249
|
-
new_template_profile['connections'].each do |c|
|
250
|
-
c['wwnn'] = nil
|
251
|
-
c['wwpn'] = nil
|
252
|
-
c['mac'] = nil
|
253
|
-
end
|
254
|
-
|
255
|
-
new_template_profile['serverHardwareUri'] = chosen_blade['uri']
|
256
|
-
task = rest_api(:oneview, :post, '/rest/server-profiles', { 'body' => new_template_profile })
|
257
|
-
task_uri = task['uri']
|
258
|
-
# Poll task resource to see when profile has finished being applied
|
259
|
-
60.times do # Wait for up to 5 min
|
260
|
-
matching_profiles = rest_api(:oneview, :get, "/rest/server-profiles?filter=name matches '#{host_name}'&sort=name:asc")
|
261
|
-
break if matching_profiles['count'] > 0
|
262
|
-
print '.'
|
263
|
-
sleep 5
|
264
|
-
end
|
265
|
-
unless matching_profiles['count'] > 0
|
266
|
-
task = rest_api(:oneview, :get, task_uri)
|
267
|
-
fail "Server template coudln't be applied! #{task['taskStatus']}. #{task['taskErrors'].first['message']}"
|
268
|
-
end
|
269
|
-
end
|
270
|
-
matching_profiles['members'].first
|
271
|
-
end
|
272
|
-
|
273
|
-
|
274
|
-
# Use ICSP to install OS
|
275
|
-
def customize_machine(action_handler, machine_spec, machine_options, profile)
|
276
|
-
auth_tokens # Login (to both ICSP and OneView)
|
277
|
-
|
278
|
-
# Wait for server profile to finish building
|
279
|
-
unless profile['state'] == 'Normal'
|
280
|
-
action_handler.perform_action "Wait for #{machine_spec.name} server to start and profile to be applied" do
|
281
|
-
action_handler.report_progress "INFO: Waiting for #{machine_spec.name} server to start and profile to be applied"
|
282
|
-
task_uri = profile['taskUri']
|
283
|
-
build_server_template_task = rest_api(:oneview, :get, task_uri)
|
284
|
-
# Poll task resource to see when profile has finished being applied
|
285
|
-
240.times do # Wait for up to 40 min
|
286
|
-
build_server_template_task = rest_api(:oneview, :get, task_uri)
|
287
|
-
break if build_server_template_task['taskState'].downcase == 'completed'
|
288
|
-
if build_server_template_task['taskState'].downcase == 'error'
|
289
|
-
server_template = machine_options[:driver_options][:server_template]
|
290
|
-
fail "Error creating server profile from template #{server_template}: #{build_server_template_task['taskErrors'].first['message']}"
|
291
|
-
end
|
292
|
-
print '.'
|
293
|
-
sleep 10
|
294
|
-
end
|
295
|
-
fail 'Timed out waiting for server to start and profile to be applied' unless build_server_template_task['taskState'].downcase == 'completed'
|
296
|
-
end
|
297
|
-
profile = get_oneview_profile_by_sn(machine_spec.reference['serial_number']) # Refresh profile
|
298
|
-
fail "Server profile state '#{profile['state']}' not 'Normal'" unless profile['state'] == 'Normal'
|
299
|
-
end
|
300
|
-
|
301
|
-
# Make sure server is started
|
302
|
-
power_on(action_handler, machine_spec, profile['serverHardwareUri'])
|
303
|
-
|
304
|
-
# Get ICSP servers to poll and wait until server PXE complete (to make sure ICSP is available).
|
305
|
-
my_server = nil
|
306
|
-
action_handler.perform_action "Wait for #{machine_spec.name} to boot" do
|
307
|
-
action_handler.report_progress "INFO: Waiting for #{machine_spec.name} to PXE boot. This may take a while..."
|
308
|
-
360.times do # Wait for up to 1 hr
|
309
|
-
os_deployment_servers = rest_api(:icsp, :get, '/rest/os-deployment-servers')
|
310
|
-
|
311
|
-
# TODO: Maybe check for opswLifecycle = 'UNPROVISIONED' instead of serialNumber existance
|
312
|
-
os_deployment_servers['members'].each do |server|
|
313
|
-
if server['serialNumber'] == profile['serialNumber']
|
314
|
-
my_server = server
|
315
|
-
break
|
316
|
-
end
|
317
|
-
end
|
318
|
-
break if !my_server.nil?
|
319
|
-
print '.'
|
320
|
-
sleep 10
|
321
|
-
end
|
322
|
-
fail "Timeout waiting for server #{machine_spec.name} to register with ICSP" if my_server.nil?
|
323
|
-
end
|
324
|
-
|
325
|
-
# Consume any custom attributes that were specified
|
326
|
-
if machine_options[:driver_options][:custom_attributes]
|
327
|
-
curr_server = rest_api(:icsp, :get, my_server['uri'])
|
328
|
-
machine_options[:driver_options][:custom_attributes].each do |key, val|
|
329
|
-
curr_server['customAttributes'].push({
|
330
|
-
'values' => [{ 'scope' => 'server', 'value' => val.to_s }],
|
331
|
-
'key' => key.to_s
|
332
|
-
})
|
333
|
-
end
|
334
|
-
options = { 'body' => curr_server }
|
335
|
-
rest_api(:icsp, :put, my_server['uri'], options)
|
336
|
-
end
|
337
|
-
|
338
|
-
# Run OS install on a server
|
339
|
-
unless my_server['opswLifecycle'] == 'MANAGED' # Skip if already in MANAGED state
|
340
|
-
os_build = machine_options[:driver_options][:os_build]
|
341
|
-
action_handler.perform_action "Install OS: #{os_build} on #{machine_spec.name}" do
|
342
|
-
action_handler.report_progress "INFO: Installing OS: #{os_build} on #{machine_spec.name}"
|
343
|
-
# Get os-deployment-build-plans
|
344
|
-
build_plan_uri = nil
|
345
|
-
os_deployment_build_plans = rest_api(:icsp, :get, '/rest/os-deployment-build-plans')
|
346
|
-
os_deployment_build_plans['members'].each do |bp|
|
347
|
-
if bp['name'] == os_build
|
348
|
-
build_plan_uri = bp['uri']
|
349
|
-
break
|
350
|
-
end
|
351
|
-
end
|
352
|
-
fail "OS build plan #{os_build} not found!" if build_plan_uri.nil?
|
353
|
-
|
354
|
-
# Do the OS deployment
|
355
|
-
options = { 'body' => {
|
356
|
-
'osbpUris' => [build_plan_uri],
|
357
|
-
'serverData' => [{ 'serverUri' => my_server['uri'] }]
|
358
|
-
} }
|
359
|
-
os_deployment_task = rest_api(:icsp, :post, '/rest/os-deployment-jobs/?force=true', options)
|
360
|
-
os_deployment_task_uri = os_deployment_task['uri']
|
361
|
-
720.times do # Wait for up to 2 hr
|
362
|
-
os_deployment_task = rest_api(:icsp, :get, os_deployment_task_uri, options) # TODO: Need options?
|
363
|
-
break if os_deployment_task['running'] == 'false'
|
364
|
-
print '.'
|
365
|
-
sleep 10
|
366
|
-
end
|
367
|
-
unless os_deployment_task['state'] == 'STATUS_SUCCESS'
|
368
|
-
fail "Error running OS build plan #{os_build}: #{os_deployment_task['jobResult'].first['jobMessage']}\n#{os_deployment_task['jobResult'].first['jobResultErrorDetails']}"
|
369
|
-
end
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
|
-
# Perform network personalization
|
374
|
-
action_handler.perform_action "Perform network personalization on #{machine_spec.name}" do
|
375
|
-
action_handler.report_progress "INFO: Performing network personalization on #{machine_spec.name}"
|
376
|
-
nics = []
|
377
|
-
if machine_options[:driver_options][:connections]
|
378
|
-
machine_options[:driver_options][:connections].each do |id, data|
|
379
|
-
c = data
|
380
|
-
c[:macAddress] = profile['connections'].select {|x| x['id'] == id}.first['mac']
|
381
|
-
c[:mask] ||= machine_options[:driver_options][:mask]
|
382
|
-
c[:dhcp] ||= machine_options[:driver_options][:dhcp] || false
|
383
|
-
c[:gateway] ||= machine_options[:driver_options][:gateway]
|
384
|
-
c[:dns] ||= machine_options[:driver_options][:dns]
|
385
|
-
c[:ip4Address] ||= machine_options[:driver_options][:ip_address]
|
386
|
-
nics.push c
|
387
|
-
end
|
388
|
-
end
|
389
|
-
options = { 'body' => [{
|
390
|
-
'serverUri' => my_server['uri'],
|
391
|
-
'personalityData' => {
|
392
|
-
'hostName' => machine_options[:driver_options][:host_name],
|
393
|
-
'domainType' => machine_options[:driver_options][:domainType],
|
394
|
-
'domainName' => machine_options[:driver_options][:domainName],
|
395
|
-
'nics' => nics
|
396
|
-
}
|
397
|
-
}] }
|
398
|
-
network_personalization_task = rest_api(:icsp, :put, '/rest/os-deployment-apxs/personalizeserver', options)
|
399
|
-
network_personalization_task_uri = network_personalization_task['uri']
|
400
|
-
60.times do # Wait for up to 10 min
|
401
|
-
network_personalization_task = rest_api(:icsp, :get, network_personalization_task_uri, options)
|
402
|
-
break if network_personalization_task['running'] == 'false'
|
403
|
-
print '.'
|
404
|
-
sleep 10
|
405
|
-
end
|
406
|
-
unless network_personalization_task['state'] == 'STATUS_SUCCESS'
|
407
|
-
fail "Error performing network personalization: #{network_personalization_task['jobResult'].first['jobResultLogDetails']}\n#{network_personalization_task['jobResult'].first['jobResultErrorDetails']}"
|
408
|
-
end
|
409
|
-
end
|
410
|
-
# Get all, search for yours. If not there or if it's in uninitialized state, pull again
|
411
|
-
my_server_uri = my_server['uri']
|
412
|
-
30.times do # Wait for up to 5 min
|
413
|
-
my_server = rest_api(:icsp, :get, my_server_uri)
|
414
|
-
break if my_server['opswLifecycle'] == 'MANAGED'
|
415
|
-
print '.'
|
416
|
-
sleep 10
|
417
|
-
end
|
418
|
-
|
419
|
-
fail "Timeout waiting for server #{machine_spec.name} to finish network personalization" if my_server['opswLifecycle'] != 'MANAGED'
|
420
|
-
my_server
|
421
|
-
end
|
422
|
-
|
423
|
-
|
424
|
-
def destroy_icsp_server(action_handler, machine_spec)
|
425
|
-
my_server = get_icsp_server_by_sn(machine_spec.reference['serial_number'])
|
426
|
-
return false if my_server.nil? || my_server['uri'].nil?
|
427
|
-
|
428
|
-
action_handler.perform_action "Delete server #{machine_spec.name} from ICSP" do
|
429
|
-
task = rest_api(:icsp, :delete, my_server['uri']) # TODO: This returns nil instead of task info
|
430
|
-
|
431
|
-
if task['uri']
|
432
|
-
task_uri = task['uri']
|
433
|
-
90.times do # Wait for up to 15 minutes
|
434
|
-
task = rest_api(:icsp, :get, task_uri)
|
435
|
-
break if task['taskState'].downcase == 'completed'
|
436
|
-
print '.'
|
437
|
-
sleep 10
|
438
|
-
end
|
439
|
-
fail "Deleting os deployment server #{machine_spec.name} at icsp failed!" unless task['taskState'].downcase == 'completed'
|
440
|
-
end
|
441
|
-
end
|
442
|
-
end
|
443
|
-
|
444
|
-
|
445
144
|
def destroy_oneview_profile(action_handler, machine_spec, profile = nil)
|
446
145
|
profile ||= get_oneview_profile_by_sn(machine_spec.reference['serial_number'])
|
447
146
|
|