chef-provisioning-oneview 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|