chef-provisioning-oneview 1.2.1 → 1.3.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 +119 -65
- data/chef-provisioning-oneview.gemspec +39 -0
- data/lib/chef/provisioning/create_machine.rb +43 -46
- data/lib/chef/provisioning/customize_machine.rb +50 -48
- data/lib/chef/provisioning/helpers.rb +18 -0
- data/lib/chef/provisioning/icsp/api_v104.rb +3 -2
- data/lib/chef/provisioning/icsp/icsp_helper.rb +288 -0
- data/lib/chef/provisioning/icsp/rest.rb +50 -0
- data/lib/chef/provisioning/oneview/oneview_helper.rb +53 -0
- data/lib/chef/provisioning/oneview/san_storage.rb +69 -69
- data/lib/chef/provisioning/oneview_driver.rb +124 -105
- data/lib/chef/provisioning/version.rb +1 -1
- metadata +23 -61
- data/Rakefile +0 -19
- data/lib/chef/provisioning/icsp/icsp_api.rb +0 -284
- data/lib/chef/provisioning/oneview/oneview_api.rb +0 -186
- data/lib/chef/provisioning/oneview/v1.2/api.rb +0 -3
- data/lib/chef/provisioning/oneview/v2.0/api.rb +0 -3
- data/lib/chef/provisioning/rest.rb +0 -52
- data/spec/shared_context.rb +0 -78
- data/spec/spec_helper.rb +0 -23
- data/spec/support/fake_action_handler.rb +0 -6
- data/spec/support/fake_icsp.rb +0 -73
- data/spec/support/fake_machine_spec.rb +0 -18
- data/spec/support/fake_oneview.rb +0 -148
- data/spec/support/fixtures/icsp/v102/error_404.json +0 -14
- data/spec/support/fixtures/icsp/v102/login.json +0 -5
- data/spec/support/fixtures/icsp/v102/os-deployment-build-plans.json +0 -99
- data/spec/support/fixtures/icsp/v102/os-deployment-servers.json +0 -179
- data/spec/support/fixtures/icsp/v102/os-deployment-servers_1670001.json +0 -83
- data/spec/support/fixtures/icsp/v102/os-deployment-servers_fakesn.json +0 -9
- data/spec/support/fixtures/icsp/v102/server_by_sn_VCGE9KB041.json +0 -45
- data/spec/support/fixtures/icsp/v102/server_by_sn_empty.json +0 -16
- data/spec/support/fixtures/icsp/v102/version.json +0 -4
- data/spec/support/fixtures/oneview/v120/error_404.json +0 -14
- data/spec/support/fixtures/oneview/v120/login.json +0 -5
- data/spec/support/fixtures/oneview/v120/server-hardware.json +0 -1476
- data/spec/support/fixtures/oneview/v120/server-hardware_Template-WebServer.json +0 -468
- data/spec/support/fixtures/oneview/v120/server-hardware_specific.json +0 -151
- data/spec/support/fixtures/oneview/v120/server-profiles.json +0 -369
- data/spec/support/fixtures/oneview/v120/server-profiles_invalid_filter.json +0 -14
- data/spec/support/fixtures/oneview/v120/server-profiles_name_Template-WebServer.json +0 -133
- data/spec/support/fixtures/oneview/v120/server-profiles_name_Template-WebServerWithSAN.json +0 -200
- data/spec/support/fixtures/oneview/v120/server-profiles_name_chef-web01.json +0 -133
- data/spec/support/fixtures/oneview/v120/server-profiles_name_chef-web03.json +0 -133
- data/spec/support/fixtures/oneview/v120/server-profiles_name_empty.json +0 -15
- data/spec/support/fixtures/oneview/v120/server-profiles_sn_VCGE9KB041.json +0 -133
- data/spec/support/fixtures/oneview/v120/server-profiles_sn_VCGE9KB042.json +0 -206
- data/spec/support/fixtures/oneview/v120/server-profiles_sn_empty.json +0 -15
- data/spec/support/fixtures/oneview/v120/storage-volumes_1B5D3CA2-6C5B-41C2-8B97-1821F1883F22.json +0 -26
- data/spec/support/fixtures/oneview/v120/tasks_fake_active.json +0 -5
- data/spec/support/fixtures/oneview/v120/tasks_fake_complete.json +0 -5
- data/spec/support/fixtures/oneview/v120/version.json +0 -4
- data/spec/support/fixtures/oneview/v200/server-profile-templates_WebServerTemplate.json +0 -109
- data/spec/support/fixtures/oneview/v200/server-profile-templates_WebServerTemplateWithSAN.json +0 -144
- data/spec/support/fixtures/oneview/v200/server-profile-templates_invalid.json +0 -16
- data/spec/support/fixtures/oneview/v200/server-profile-templates_new-profile_WebServerTemplate.json +0 -125
- data/spec/support/fixtures/oneview/v200/server-profile-templates_new-profile_WebServerTemplateWithSAN.json +0 -178
- data/spec/support/fixtures/oneview/v200/version.json +0 -4
- data/spec/unit/create_machine_spec.rb +0 -78
- data/spec/unit/destroy_spec.rb +0 -26
- data/spec/unit/icsp_nic_teams_spec.rb +0 -38
- data/spec/unit/icsp_search_spec.rb +0 -25
- data/spec/unit/oneview_driver_spec.rb +0 -79
- data/spec/unit/oneview_login_spec.rb +0 -17
- data/spec/unit/oneview_power_spec.rb +0 -51
- data/spec/unit/oneview_san_spec.rb +0 -86
- data/spec/unit/oneview_search_spec.rb +0 -63
- data/spec/unit/rest_api_spec.rb +0 -115
@@ -1,64 +1,66 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module OneviewChefProvisioningDriver
|
2
|
+
# Handles OS install and network configuration
|
3
|
+
module CustomizeMachine
|
4
|
+
# Use ICSP to install OS
|
5
|
+
def customize_machine(action_handler, machine_spec, machine_options, profile)
|
6
|
+
machine_name = machine_spec.name
|
7
|
+
# Wait for server profile to finish building
|
8
|
+
wait_for_profile(action_handler, machine_name, profile)
|
9
|
+
profile.refresh
|
3
10
|
|
4
|
-
|
5
|
-
|
6
|
-
# Wait for server profile to finish building
|
7
|
-
wait_for_profile(action_handler, machine_spec, machine_options, profile)
|
11
|
+
# Configure SAN storage (if applicable)
|
12
|
+
enable_boot_from_san(action_handler, machine_name, profile) unless machine_spec.reference['network_personalitation_finished']
|
8
13
|
|
9
|
-
|
10
|
-
|
14
|
+
# Make sure server is started
|
15
|
+
profile.get_server_hardware.power_on
|
11
16
|
|
12
|
-
|
13
|
-
power_on(action_handler, machine_spec, profile['serverHardwareUri'])
|
17
|
+
return if @icsp_ignore == true
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
# Get ICSP servers to poll and wait until server PXE complete (to make sure ICSP is available).
|
20
|
+
my_server = nil
|
21
|
+
action_handler.perform_action "Wait for #{machine_name} to boot into HP Intelligent Provisioning" do
|
22
|
+
action_handler.report_progress "INFO: Waiting for #{machine_name} to PXE boot into HP Intelligent Provisioning"
|
23
|
+
360.times do # Wait for up to 1 hr
|
24
|
+
my_server = get_icsp_server_by_sn(profile['serialNumber'])
|
25
|
+
break unless my_server.nil?
|
26
|
+
print '.'
|
27
|
+
sleep 10
|
28
|
+
end
|
29
|
+
raise "Timeout waiting for server #{machine_name} to register with ICSP" if my_server.nil?
|
24
30
|
end
|
25
|
-
raise "Timeout waiting for server #{machine_spec.name} to register with ICSP" if my_server.nil?
|
26
|
-
end
|
27
31
|
|
28
|
-
|
32
|
+
icsp_configure_nic_teams(machine_options, profile)
|
29
33
|
|
30
|
-
|
34
|
+
icsp_set_custom_attributes(machine_options, my_server)
|
31
35
|
|
32
|
-
|
36
|
+
icsp_run_os_install(action_handler, machine_spec, machine_options, my_server, profile)
|
33
37
|
|
34
|
-
|
35
|
-
|
38
|
+
# Customize networking
|
39
|
+
if !machine_spec.reference['network_personalitation_finished'] || machine_options[:driver_options][:force_network_update]
|
36
40
|
|
37
|
-
|
41
|
+
icsp_configure_networking(action_handler, machine_spec, machine_options, my_server, profile)
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
raise "Timed out waiting for network flipping on #{machine_spec.name}" if task == false
|
56
|
-
raise "Error performing network flip on #{machine_spec.name}. Response: #{task}" unless task == true
|
43
|
+
# Switch deploy networks to post-deploy networks if specified
|
44
|
+
if machine_options[:driver_options][:connections]
|
45
|
+
available_networks = profile.available_networks
|
46
|
+
machine_options[:driver_options][:connections].each do |id, data|
|
47
|
+
next unless data && data[:net] && data[:deployNet]
|
48
|
+
action_handler.perform_action "Perform network flipping on #{machine_name}, connection #{id}" do
|
49
|
+
action_handler.report_progress "INFO: Performing network flipping on #{machine_name}, connection #{id}"
|
50
|
+
deploy_network = available_networks['ethernetNetworks'].find { |n| n['name'] == data[:deployNet] }
|
51
|
+
new_network = available_networks['ethernetNetworks'].find { |n| n['name'] == data[:net] }
|
52
|
+
raise "Failed to perform network flipping on #{machine_name}, connection #{id}. '#{data[:net]}' network not found" if new_network.nil?
|
53
|
+
raise "Failed to perform network flipping on #{machine_name}, connection #{id}. '#{data[:deployNet]}' network not found" if deploy_network.nil?
|
54
|
+
profile.refresh
|
55
|
+
profile['connections'].find { |c| c['networkUri'] == deploy_network['uri'] }['networkUri'] = new_network['uri']
|
56
|
+
profile.update
|
57
|
+
end
|
58
|
+
end
|
57
59
|
end
|
60
|
+
machine_spec.reference['network_personalitation_finished'] = true
|
58
61
|
end
|
59
|
-
machine_spec.reference['network_personalitation_finished'] = true
|
60
|
-
end
|
61
62
|
|
62
|
-
|
63
|
+
my_server = rest_api(:icsp, :get, my_server['uri'])
|
64
|
+
end
|
63
65
|
end
|
64
66
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'create_machine'
|
2
|
+
require_relative 'customize_machine'
|
3
|
+
require_relative 'oneview/oneview_helper'
|
4
|
+
require_relative 'oneview/san_storage'
|
5
|
+
require_relative 'icsp/icsp_helper'
|
6
|
+
|
7
|
+
module OneviewChefProvisioningDriver
|
8
|
+
# Module that just includes all other helper modules
|
9
|
+
module Helpers
|
10
|
+
include CreateMachine # Handles allocation of OneView ServerProfile
|
11
|
+
include CustomizeMachine # Handles OS install and network configuration
|
12
|
+
|
13
|
+
include OneViewHelper # Helpers for OneView actions
|
14
|
+
include OneViewSanStorage # Helpers for OneView SAN storage actions
|
15
|
+
|
16
|
+
include IcspHelper # Helpers for ICSP actions
|
17
|
+
end
|
18
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# Helper module for ICSP v104 API requests
|
1
2
|
module ICspAPIv104
|
2
3
|
# Parse and clean connection data for api call
|
3
4
|
def icsp_v104_parse_connection(machine_options, c)
|
@@ -11,14 +12,14 @@ module ICspAPIv104
|
|
11
12
|
c[:dnsServers] = nil if c[:dnsServers] == :none
|
12
13
|
c[:dnsServers] = c[:dnsServers].split(',') if c[:dnsServers].class == String
|
13
14
|
c[:staticNetworks] ||= ["#{c[:ip4Address]}/#{c[:mask] || machine_options[:driver_options][:mask] || '24'}"] if c[:ip4Address]
|
14
|
-
c.keep_if {|k, _v| allowed_keys.include? k.to_s }
|
15
|
+
c.keep_if { |k, _v| allowed_keys.include? k.to_s }
|
15
16
|
end
|
16
17
|
|
17
18
|
# Parse and clean personality_data data for api call
|
18
19
|
def icsp_v104_build_personality_data(machine_options, nics)
|
19
20
|
allowed_keys = %w(hostname domain workgroup)
|
20
21
|
personality_data = Marshal.load(Marshal.dump(machine_options[:driver_options])) || {}
|
21
|
-
personality_data.keep_if {|k, _v| allowed_keys.include? k.to_s }
|
22
|
+
personality_data.keep_if { |k, _v| allowed_keys.include? k.to_s }
|
22
23
|
personality_data['hostname'] ||= machine_options[:driver_options][:host_name]
|
23
24
|
personality_data['domain'] ||= machine_options[:driver_options][:domainName]
|
24
25
|
personality_data['interfaces'] = nics
|
@@ -0,0 +1,288 @@
|
|
1
|
+
require_relative 'rest'
|
2
|
+
require_relative 'api_v104'
|
3
|
+
|
4
|
+
module OneviewChefProvisioningDriver
|
5
|
+
# Helpers for ICSP actions
|
6
|
+
module IcspHelper
|
7
|
+
include RestAPI
|
8
|
+
include ICspAPIv104
|
9
|
+
|
10
|
+
def get_icsp_api_version
|
11
|
+
begin
|
12
|
+
version = rest_api(:icsp, :get, '/rest/version', 'Content-Type' => :none, 'X-API-Version' => :none, 'auth' => :none)['currentVersion']
|
13
|
+
raise "Couldn't get API version" unless version
|
14
|
+
if version.class != Fixnum
|
15
|
+
version = version.to_i
|
16
|
+
raise 'API version type mismatch' if !version > 0
|
17
|
+
end
|
18
|
+
rescue
|
19
|
+
puts 'Failed to get ICSP API version. Setting to default (102)'
|
20
|
+
version = 102
|
21
|
+
end
|
22
|
+
version
|
23
|
+
end
|
24
|
+
|
25
|
+
def login_to_icsp
|
26
|
+
path = '/rest/login-sessions'
|
27
|
+
options = {
|
28
|
+
'body' => {
|
29
|
+
'userName' => @icsp_username,
|
30
|
+
'password' => @icsp_password,
|
31
|
+
'authLoginDomain' => 'LOCAL'
|
32
|
+
}
|
33
|
+
}
|
34
|
+
response = rest_api(:icsp, :post, path, options)
|
35
|
+
return response['sessionID'] if response['sessionID']
|
36
|
+
raise("\nERROR! Couldn't log into ICSP server at #{@icsp_base_url}. Response:\n#{response}")
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_icsp_server_by_sn(serial_number)
|
40
|
+
raise 'Must specify a serialNumber!' if serial_number.nil? || serial_number.empty?
|
41
|
+
search_result = rest_api(:icsp, :get,
|
42
|
+
"/rest/index/resources?category=osdserver&query='osdServerSerialNumber:\"#{serial_number}\"'")['members'] rescue nil
|
43
|
+
if search_result && search_result.size == 1 && search_result.first['attributes']['osdServerSerialNumber'] == serial_number
|
44
|
+
my_server_uri = search_result.first['uri']
|
45
|
+
my_server = rest_api(:icsp, :get, my_server_uri)
|
46
|
+
end
|
47
|
+
unless my_server && my_server['uri']
|
48
|
+
os_deployment_servers = rest_api(:icsp, :get, '/rest/os-deployment-servers')
|
49
|
+
# Pick the relevant os deployment server from icsp
|
50
|
+
my_server = nil
|
51
|
+
os_deployment_servers['members'].each do |server|
|
52
|
+
if server['serialNumber'] == serial_number
|
53
|
+
my_server = server
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
my_server
|
59
|
+
end
|
60
|
+
|
61
|
+
def icsp_wait_for(task_uri, wait_iterations = 60, sleep_seconds = 10)
|
62
|
+
raise 'Must specify a task_uri!' if task_uri.nil? || task_uri.empty?
|
63
|
+
wait_iterations.times do
|
64
|
+
task = rest_api(:icsp, :get, task_uri)
|
65
|
+
if task['taskState']
|
66
|
+
case task['taskState'].downcase
|
67
|
+
when 'completed'
|
68
|
+
return true
|
69
|
+
when 'error', 'killed', 'terminated'
|
70
|
+
return task
|
71
|
+
end
|
72
|
+
elsif task['running'] == 'false' && task['jobResult']
|
73
|
+
if task['state'] == 'STATUS_SUCCESS'
|
74
|
+
return true
|
75
|
+
else
|
76
|
+
return task
|
77
|
+
end
|
78
|
+
end
|
79
|
+
print '.'
|
80
|
+
sleep sleep_seconds
|
81
|
+
end
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
# Consume and set any custom attributes that were specified
|
86
|
+
def icsp_set_custom_attributes(machine_options, my_server)
|
87
|
+
if machine_options[:driver_options][:custom_attributes]
|
88
|
+
curr_server = rest_api(:icsp, :get, my_server['uri'])
|
89
|
+
machine_options[:driver_options][:custom_attributes].each do |key, val|
|
90
|
+
curr_server['customAttributes'].push(
|
91
|
+
'values' => [{ 'scope' => 'server', 'value' => val.to_s }],
|
92
|
+
'key' => key.to_s
|
93
|
+
)
|
94
|
+
end
|
95
|
+
options = { 'body' => curr_server }
|
96
|
+
rest_api(:icsp, :put, my_server['uri'], options)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def icsp_run_os_install(action_handler, machine_spec, machine_options, my_server, profile)
|
101
|
+
return if my_server['state'] == 'OK' # Skip if the OS has already been deployed
|
102
|
+
|
103
|
+
# Wait for my_server['state'] to be in MAINTENANCE mode
|
104
|
+
if my_server['state'] != 'MAINTENANCE'
|
105
|
+
action_handler.perform_action "Wait for #{machine_spec.name} to go into maintenance mode in ICsp" do
|
106
|
+
action_handler.report_progress "INFO: Waiting for #{machine_spec.name} to go into maintenance mode in ICsp"
|
107
|
+
120.times do # Wait for up to 20 min
|
108
|
+
my_server = get_icsp_server_by_sn(profile['serialNumber'])
|
109
|
+
break if my_server['state'] != 'MAINTENANCE'
|
110
|
+
print '.'
|
111
|
+
sleep 10
|
112
|
+
end
|
113
|
+
raise "Timed out waiting for #{machine_spec.name} to go into maintenance mode in ICsp. State: #{my_server['state']}" unless my_server['state'] == 'MAINTENANCE'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Get the specified OS Build Plan(s)
|
118
|
+
os_builds = machine_options[:driver_options][:os_build]
|
119
|
+
os_builds = [os_builds] if os_builds.class == String
|
120
|
+
build_plan_uris = []
|
121
|
+
action_handler.perform_action "Get OS Build Plan(s) info for #{machine_spec.name}" do
|
122
|
+
action_handler.report_progress "INFO: Getting OS Build Plan(s) for #{machine_spec.name}"
|
123
|
+
os_builds.each do |os_build|
|
124
|
+
uri = "/rest/index/resources?userQuery=\"'#{os_build}'\"&category=osdbuildplan"
|
125
|
+
while uri
|
126
|
+
matching_plans = rest_api(:icsp, :get, uri)
|
127
|
+
raise "Search failed for OSBP '#{os_build}'. Response: #{matching_plans}" unless matching_plans['members']
|
128
|
+
build_plan_uri = matching_plans['members'].find { |bp| bp['name'] == os_build }['uri'] rescue nil
|
129
|
+
break unless build_plan_uri.nil?
|
130
|
+
uri = URI.unescape(matching_plans['nextPageUri']) rescue nil
|
131
|
+
end
|
132
|
+
raise "OS build plan #{os_build} not found!" if build_plan_uri.nil?
|
133
|
+
build_plan_uris.push build_plan_uri
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Build options for the OS deployment
|
138
|
+
options = {}
|
139
|
+
options['X-API-Version'] = 104 if @current_icsp_api_version.between?(104, 108)
|
140
|
+
options['body'] = {
|
141
|
+
'osbpUris' => build_plan_uris,
|
142
|
+
'serverData' => [{
|
143
|
+
'serverUri' => my_server['uri']
|
144
|
+
}]
|
145
|
+
}
|
146
|
+
|
147
|
+
# Do the OS deployment
|
148
|
+
action_handler.perform_action "Run: #{os_builds} OS Build Plan(s) on #{machine_spec.name}" do
|
149
|
+
action_handler.report_progress "INFO: Running: #{os_builds} OS Build Plan(s) on #{machine_spec.name}"
|
150
|
+
task = rest_api(:icsp, :post, '/rest/os-deployment-jobs/?force=true', options)
|
151
|
+
task_uri = task['uri']
|
152
|
+
raise "Failed to start OS Deployment Job. Details: #{task['details'] || task['message'] || task}" unless task_uri
|
153
|
+
task = icsp_wait_for(task_uri, 720)
|
154
|
+
raise "Error running OS build plan(s) #{os_builds}: #{task['jobResult'].first['jobMessage']}\n#{task['jobResult'].first['jobResultErrorDetails']}" unless task == true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def icsp_configure_networking(action_handler, machine_spec, machine_options, my_server, profile)
|
159
|
+
return if machine_options[:driver_options][:skip_network_configuration] == true
|
160
|
+
action_handler.perform_action "Configure networking on #{machine_spec.name}" do
|
161
|
+
action_handler.report_progress "INFO: Configuring networking on #{machine_spec.name}"
|
162
|
+
personality_data = icsp_build_personality_data(machine_options, profile)
|
163
|
+
options = {}
|
164
|
+
options['X-API-Version'] = 104 if @current_icsp_api_version.between?(104, 108)
|
165
|
+
options['body'] = {
|
166
|
+
'serverData' => [{
|
167
|
+
'serverUri' => my_server['uri'],
|
168
|
+
'personalityData' => personality_data
|
169
|
+
}]
|
170
|
+
}
|
171
|
+
|
172
|
+
task = rest_api(:icsp, :post, '/rest/os-deployment-jobs/?force=true', options)
|
173
|
+
task_uri = task['uri']
|
174
|
+
raise "Failed to start network personalization job. Details: #{task['details'] || task['message'] || task}" unless task_uri
|
175
|
+
task = icsp_wait_for(task_uri, 60) # Wait for up to 10 min
|
176
|
+
raise "Error running network personalization job: #{task['jobResult'].first['jobMessage']}\n#{task['jobResult'].first['jobResultErrorDetails']}" unless task == true
|
177
|
+
|
178
|
+
# Check if ICsp IP config matches machine options
|
179
|
+
requested_ips = []
|
180
|
+
machine_options[:driver_options][:connections].each do |_id, c|
|
181
|
+
requested_ips.push c[:ip4Address] if c[:ip4Address] && c[:dhcp] == false
|
182
|
+
end
|
183
|
+
my_server_connections = []
|
184
|
+
10.times do
|
185
|
+
my_server_connections = rest_api(:icsp, :get, my_server['uri'])['interfaces']
|
186
|
+
my_server_connections.each { |c| requested_ips.delete c['ipv4Addr'] }
|
187
|
+
break if requested_ips.empty?
|
188
|
+
print ','
|
189
|
+
sleep 10
|
190
|
+
end
|
191
|
+
puts "\nWARN: The following IPs are not visible on ICsp, so they may not have gotten configured correctly: #{requested_ips}" unless requested_ips.empty?
|
192
|
+
|
193
|
+
# Set interface data as normal node attributes
|
194
|
+
my_server_connections.each do |c|
|
195
|
+
c['oneViewId'] = profile['connections'].find { |x| x['mac'] == c['macAddr'] }['id'] rescue nil
|
196
|
+
end
|
197
|
+
machine_spec.data['normal']['icsp'] ||= {}
|
198
|
+
machine_spec.data['normal']['icsp']['interfaces'] = my_server_connections
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Build options for the network configuration
|
203
|
+
def icsp_build_personality_data(machine_options, profile)
|
204
|
+
nics = []
|
205
|
+
if machine_options[:driver_options][:connections]
|
206
|
+
machine_options[:driver_options][:connections].each do |id, data|
|
207
|
+
c = Marshal.load(Marshal.dump(data))
|
208
|
+
next unless c[:dhcp] || c[:dhcpv4] || c[:ip4Address] || c[:ipv6autoconfig] || c[:staticNetworks] # Invalid network or only switch networks specified
|
209
|
+
c.delete_if { |k, _v| k.to_s == 'bootstrap' }
|
210
|
+
begin
|
211
|
+
c[:macAddress] = profile['connections'].find { |x| x['id'] == id }['mac']
|
212
|
+
rescue NoMethodError
|
213
|
+
ids = []
|
214
|
+
profile['connections'].each { |x| ids.push x['id'] }
|
215
|
+
raise "Could not find connection id #{id} for #{profile['name']}. Available connection ids are: #{ids}. Please make sure the connection ids map to those on OneView."
|
216
|
+
end
|
217
|
+
if @current_icsp_api_version.between?(104, 108)
|
218
|
+
icsp_v104_parse_connection(machine_options, c)
|
219
|
+
else
|
220
|
+
c[:mask] ||= machine_options[:driver_options][:mask]
|
221
|
+
c[:dhcp] ||= false
|
222
|
+
c[:gateway] ||= machine_options[:driver_options][:gateway]
|
223
|
+
c[:dns] ||= machine_options[:driver_options][:dns]
|
224
|
+
end
|
225
|
+
nics.push c
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
if @current_icsp_api_version.between?(104, 108)
|
230
|
+
personality_data = icsp_v104_build_personality_data(machine_options, nics)
|
231
|
+
else
|
232
|
+
personality_data = {
|
233
|
+
'hostName' => machine_options[:driver_options][:host_name],
|
234
|
+
'domainType' => machine_options[:driver_options][:domainType],
|
235
|
+
'domainName' => machine_options[:driver_options][:domainName],
|
236
|
+
'nics' => nics
|
237
|
+
}
|
238
|
+
end
|
239
|
+
personality_data
|
240
|
+
end
|
241
|
+
|
242
|
+
def destroy_icsp_server(action_handler, machine_spec)
|
243
|
+
my_server = get_icsp_server_by_sn(machine_spec.reference['serial_number'])
|
244
|
+
return false if my_server.nil? || my_server['uri'].nil?
|
245
|
+
|
246
|
+
action_handler.perform_action "Delete server #{machine_spec.name} from ICSP" do
|
247
|
+
task = rest_api(:icsp, :delete, my_server['uri']) # TODO: This returns nil instead of task info
|
248
|
+
if task['uri']
|
249
|
+
task_uri = task['uri']
|
250
|
+
90.times do # Wait for up to 15 minutes
|
251
|
+
task = rest_api(:icsp, :get, task_uri)
|
252
|
+
break if task['taskState'].casecmp('completed') == 0
|
253
|
+
print '.'
|
254
|
+
sleep 10
|
255
|
+
end
|
256
|
+
raise "Deleting os deployment server #{machine_spec.name} at icsp failed!" unless task['taskState'].casecmp('completed') == 0
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Sets ICSP custom attributes to enable nic teaming
|
262
|
+
def icsp_configure_nic_teams(machine_options, profile)
|
263
|
+
return false if machine_options[:driver_options][:connections].nil?
|
264
|
+
teams = {}
|
265
|
+
|
266
|
+
machine_options[:driver_options][:connections].each do |id, options|
|
267
|
+
next unless options.is_a?(Hash) && options[:team]
|
268
|
+
raise "#{options[:team]}: Team names must not include hyphens" if options[:team].to_s.include?('-')
|
269
|
+
teams[options[:team].to_s] ||= []
|
270
|
+
begin
|
271
|
+
mac = profile['connections'].find { |x| x['id'] == id }['mac']
|
272
|
+
teams[options[:team].to_s].push mac
|
273
|
+
rescue NoMethodError
|
274
|
+
ids = []
|
275
|
+
profile['connections'].each { |x| ids.push x['id'] }
|
276
|
+
raise "Failed to configure nic teams: Could not find connection id #{id} for #{profile['name']}. Available connection ids are: #{ids}. Please make sure the connection ids map to those on OneView."
|
277
|
+
end
|
278
|
+
end
|
279
|
+
team_strings = []
|
280
|
+
teams.each do |name, macs|
|
281
|
+
raise "Team '#{name}' must have at least 2 associated connections to form a NIC team" unless macs.size >= 2
|
282
|
+
team_strings.push "#{name}-#{macs.join(',')}"
|
283
|
+
end
|
284
|
+
machine_options[:driver_options][:custom_attributes] ||= {}
|
285
|
+
machine_options[:driver_options][:custom_attributes][:teams] = team_strings.join('|')
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module OneviewChefProvisioningDriver
|
2
|
+
# Helpers for REST API calls
|
3
|
+
module RestAPI
|
4
|
+
# API calls for OneView and ICsp
|
5
|
+
def rest_api(host, type, path, options = {})
|
6
|
+
disable_ssl = false
|
7
|
+
case host
|
8
|
+
when 'icsp', :icsp
|
9
|
+
uri = URI.parse(URI.escape(@icsp_base_url + path))
|
10
|
+
options['X-API-Version'] ||= @icsp_api_version unless [:put, 'put'].include?(type.downcase)
|
11
|
+
options['auth'] ||= @icsp_key
|
12
|
+
disable_ssl = true if @icsp_disable_ssl
|
13
|
+
else
|
14
|
+
raise "Invalid rest host: #{host}"
|
15
|
+
end
|
16
|
+
|
17
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
18
|
+
http.read_timeout = @icsp_timeout if @icsp_timeout # timeout for a request
|
19
|
+
http.open_timeout = @icsp_timeout if @icsp_timeout # timeout for a connection
|
20
|
+
http.use_ssl = true if uri.scheme == 'https'
|
21
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if disable_ssl
|
22
|
+
case type.downcase
|
23
|
+
when 'get', :get
|
24
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
25
|
+
when 'post', :post
|
26
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
27
|
+
when 'put', :put
|
28
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
29
|
+
when 'delete', :delete
|
30
|
+
request = Net::HTTP::Delete.new(uri.request_uri)
|
31
|
+
else
|
32
|
+
raise "Invalid rest call: #{type}"
|
33
|
+
end
|
34
|
+
options['Content-Type'] ||= 'application/json'
|
35
|
+
options.delete('Content-Type') if [:none, 'none', nil].include?(options['Content-Type'])
|
36
|
+
options.delete('X-API-Version') if [:none, 'none', nil].include?(options['X-API-Version'])
|
37
|
+
options.delete('auth') if [:none, 'none', nil].include?(options['auth'])
|
38
|
+
options.each do |key, val|
|
39
|
+
if key.casecmp('body') == 0
|
40
|
+
request.body = val.to_json rescue val
|
41
|
+
else
|
42
|
+
request[key] = val
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
response = http.request(request)
|
47
|
+
JSON.parse(response.body) rescue response
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|