chef-provisioning-oneview 1.2.1 → 1.3.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 +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
|