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
@@ -0,0 +1,53 @@
|
|
1
|
+
module OneviewChefProvisioningDriver
|
2
|
+
# Helpers for OneView actions
|
3
|
+
module OneViewHelper
|
4
|
+
# Create new Profile from template or server profile
|
5
|
+
# @return [OneviewSDK::ServerProfile] server profile
|
6
|
+
def profile_from_template(template_name, profile_name)
|
7
|
+
raise 'Template name missing! Please set machine_options[:driver_options][:server_template]' unless template_name
|
8
|
+
if @ov.api_version >= 200
|
9
|
+
# Look for Server Profile Template (OneView 2.0 or higher)
|
10
|
+
template = OneviewSDK::ServerProfileTemplate.find_by(@ov, name: template_name).first
|
11
|
+
return template.new_profile(profile_name) if template
|
12
|
+
end
|
13
|
+
|
14
|
+
# Look for Server Profile as second option
|
15
|
+
profile = OneviewSDK::ServerProfile.find_by(@ov, name: template_name).first
|
16
|
+
raise "Template '#{template_name}' not found! Please match the template name with one that exists on OneView." unless profile
|
17
|
+
profile['name'] = profile_name
|
18
|
+
|
19
|
+
# Remove unwanted fields
|
20
|
+
%w(uri serialNumber uuid taskUri enclosureBay enclosureUri).each { |key| profile.data.delete(key) }
|
21
|
+
profile['connections'].each do |c|
|
22
|
+
%w(wwnn wwpn mac deploymentStatus interconnectUri wwpnType macType).each { |key| c[key] = nil }
|
23
|
+
end
|
24
|
+
profile
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get an available hardware for a template. If a specific location is requested, find it
|
28
|
+
# @return [OneviewSDK::ServerHardware]
|
29
|
+
def available_hardware_for_profile(profile, location = nil)
|
30
|
+
Chef::Log.debug "Specific hardware requested: #{location}" if location
|
31
|
+
hw_list = profile.get_available_hardware
|
32
|
+
raise 'Error! No available blades that are compatible with the server template!' if hw_list.empty?
|
33
|
+
if location
|
34
|
+
chosen_blade = hw_list.find { |h| h['name'] == location }
|
35
|
+
return chosen_blade if chosen_blade
|
36
|
+
raise "Specified hardware '#{location}' doesn't exist or doesn't match the given template"
|
37
|
+
end
|
38
|
+
hw_list.first # If no location is specified, return the first matching HW
|
39
|
+
end
|
40
|
+
|
41
|
+
# Wait for the profile to finish being applied
|
42
|
+
# @return [TrueClass, FalseClass]
|
43
|
+
def wait_for_profile(action_handler, machine_name, profile)
|
44
|
+
return true if profile['state'] == 'Normal'
|
45
|
+
action_handler.perform_action "Apply profile '#{profile['name']}' for machine '#{machine_name}'" do
|
46
|
+
action_handler.report_progress "INFO: Applying profile '#{profile['name']}' for machine '#{machine_name}'"
|
47
|
+
@ov.wait_for(profile['taskUri'])
|
48
|
+
end
|
49
|
+
profile.refresh
|
50
|
+
raise "Server profile state '#{profile['state']}' not 'Normal'" unless profile['state'] == 'Normal'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1,91 +1,91 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
module OneviewChefProvisioningDriver
|
2
|
+
# Methods for configuring SAN storage on OneView
|
3
|
+
module OneViewSanStorage
|
4
|
+
def fill_volume_details(v)
|
5
|
+
response = @ov.rest_get(v['volumeUri'])
|
6
|
+
details = @ov.response_handler(response)
|
7
|
+
v['volumeName'] = details['name']
|
8
|
+
v['permanent'] = details['isPermanent']
|
9
|
+
v['volumeShareable'] = details['shareable']
|
10
|
+
v['volumeProvisionType'] = details['provisionType']
|
11
|
+
v['volumeProvisionedCapacityBytes'] = details['provisionedCapacity']
|
12
|
+
v['volumeDescription'] = details['description']
|
13
|
+
v
|
14
|
+
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
# Prepare profile for SAN storage
|
17
|
+
def update_san_info(machine_name, profile)
|
18
|
+
san_storage = profile['sanStorage']
|
19
|
+
return profile unless san_storage && !san_storage['volumeAttachments'].empty?
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# Sanitize old SAN entries and fill in details
|
22
|
+
boot_vols = []
|
23
|
+
san_storage['volumeAttachments'].each do |v|
|
24
|
+
fill_volume_details(v) unless profile['serverProfileTemplateUri']
|
25
|
+
raise "#{machine_name}: Should know if volume is sharable:\n#{v}" unless v.key?('volumeShareable')
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
# Match boot disks by name
|
28
|
+
boot_vols.push(v['volumeName']) if v['volumeName'] =~ /^boot/i
|
29
|
+
v['volumeName'] += " #{profile['name']}" unless v['volumeShareable'] # Append profile name to volume name
|
28
30
|
|
29
|
-
|
31
|
+
next if profile['serverProfileTemplateUri'] # Only needed when coppied from profile
|
30
32
|
v['state'] = nil
|
31
33
|
v['status'] = nil
|
32
34
|
v['storagePaths'].each { |s| s['status'] = nil }
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
next if v['volumeShareable']
|
37
|
+
# It is private in the profile, so we will clone it
|
38
|
+
v['volumeUri'] = nil
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
40
|
+
# Assumes all cloned volumes are non-permanet. Might want some global config to control this
|
41
|
+
v['permanent'] = false
|
42
|
+
v['lun'] = nil if v['lunType'].casecmp('auto') == 0
|
42
43
|
end
|
44
|
+
raise "#{machine_name}: There should only be 1 SAN boot volume. Boot volumes: #{boot_vols}" if boot_vols.size > 1
|
45
|
+
profile
|
43
46
|
end
|
44
|
-
raise "#{machine_spec.name}: There should only be 1 SAN boot volume. Boot volumes: #{boot_vols}" if boot_vols.size > 1
|
45
|
-
profile
|
46
|
-
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
# Make sure connections for SAN boot volumes are configured to boot from the correct SAN volume
|
49
|
+
# @return false if no connections are available to configure
|
50
|
+
def enable_boot_from_san(action_handler, machine_name, profile)
|
51
|
+
return false if profile['connections'].nil? || profile['connections'].empty?
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
53
|
+
# If there is a san volume we might need to update boot connections
|
54
|
+
update_needed = false
|
55
|
+
profile['sanStorage']['volumeAttachments'].each do |v|
|
56
|
+
response = @ov.rest_get(v['volumeUri'])
|
57
|
+
vol_details = @ov.response_handler(response)
|
58
|
+
next unless vol_details['name'] =~ /^boot/i
|
59
|
+
# Find the enabled path(s), get target wwpn, and then update connection, setting boot targets
|
60
|
+
v['storagePaths'].each do |s|
|
61
|
+
next if !s['isEnabled'] || s['storageTargets'].nil? || s['storageTargets'].empty?
|
62
|
+
connection = profile['connections'].find { |c| c['id'] == s['connectionId'] }
|
63
|
+
raise "#{machine_name}: Connection #{s['connectionId']} not found! Check SAN settings" unless connection
|
64
|
+
if connection['boot'].nil? || connection['boot']['priority'] == 'NotBootable'
|
65
|
+
msg = "#{machine_name}: Connection #{s['connectionId']} is labeled for boot, but the connection is not marked as bootable."
|
66
|
+
raise "#{msg} Set the connection boot target to Primary or Secondary"
|
67
|
+
end
|
68
|
+
target = {}
|
69
|
+
target['arrayWwpn'] = s['storageTargets'].first.delete(':')
|
70
|
+
target['lun'] = v['lun']
|
71
|
+
unchanged = connection['boot']['targets'] && connection['boot']['targets'].first &&
|
72
|
+
connection['boot']['targets'].first['arrayWwpn'] == target['arrayWwpn'] &&
|
73
|
+
connection['boot']['targets'].first['lun'] == target['lun']
|
74
|
+
next if unchanged
|
72
75
|
connection['boot']['targets'] = [target]
|
73
76
|
update_needed = true
|
74
77
|
end
|
75
78
|
end
|
76
|
-
end
|
77
79
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
raise "Error enabling SAN-bootable connections on #{machine_spec.name}. Response: #{task}" unless task == true
|
80
|
+
if update_needed
|
81
|
+
action_handler.perform_action "Enable SAN-bootable connections for #{machine_name}" do
|
82
|
+
action_handler.report_progress "INFO: Enabling SAN-bootable connections for #{machine_name}"
|
83
|
+
profile.get_server_hardware.power_off
|
84
|
+
profile.update
|
85
|
+
end
|
86
|
+
profile.refresh
|
86
87
|
end
|
87
|
-
profile
|
88
|
+
profile # Return profile
|
88
89
|
end
|
89
|
-
profile # Return profile
|
90
90
|
end
|
91
91
|
end
|
@@ -6,90 +6,91 @@ require 'chef/provisioning/driver'
|
|
6
6
|
require 'chef/provisioning/transport/ssh'
|
7
7
|
require 'chef/provisioning/machine/unix_machine'
|
8
8
|
require 'json'
|
9
|
+
require 'oneview-sdk'
|
9
10
|
require_relative 'driver_init/oneview'
|
10
11
|
require_relative 'version'
|
11
|
-
require_relative '
|
12
|
-
require_relative 'create_machine'
|
13
|
-
require_relative 'customize_machine'
|
14
|
-
require_relative 'oneview/oneview_api'
|
15
|
-
require_relative 'icsp/icsp_api'
|
12
|
+
require_relative 'helpers'
|
16
13
|
|
17
14
|
module Chef::Provisioning
|
15
|
+
# Provisioning driver for HPE OneView
|
18
16
|
class OneViewDriver < Chef::Provisioning::Driver
|
19
|
-
include
|
20
|
-
include CustomizeMachine
|
21
|
-
include RestAPI
|
22
|
-
include OneViewAPI
|
23
|
-
include ICspAPI
|
24
|
-
|
17
|
+
include OneviewChefProvisioningDriver::Helpers
|
25
18
|
|
26
19
|
def self.canonicalize_url(url, config)
|
27
20
|
_scheme, oneview_url = url.split(':', 2)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
raise 'Must set the
|
32
|
-
|
21
|
+
oneview_url ||= config[:driver_options][:oneview][:url] rescue nil
|
22
|
+
oneview_url ||= config[:knife][:oneview_url] rescue nil
|
23
|
+
oneview_url ||= ENV['ONEVIEWSDK_URL']
|
24
|
+
raise 'Must set the oneview driver url! See docs for more info' if oneview_url.nil? || oneview_url.empty?
|
25
|
+
"oneview:#{oneview_url}"
|
33
26
|
end
|
34
27
|
|
35
|
-
def self.from_url(
|
36
|
-
OneViewDriver.new(
|
28
|
+
def self.from_url(url, config)
|
29
|
+
OneViewDriver.new(url, config)
|
37
30
|
end
|
38
31
|
|
39
|
-
def initialize(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@
|
32
|
+
def initialize(url, config)
|
33
|
+
_scheme, oneview_url = url.split(':', 2)
|
34
|
+
super(url, config)
|
35
|
+
|
36
|
+
ov_config = config[:driver_options][:oneview] || {} rescue {}
|
37
|
+
ov_config = Hash[ov_config.map { |k, v| [k.to_sym, v] }] # Convert string keys to symbols
|
38
|
+
|
39
|
+
ov_config[:url] = oneview_url
|
40
|
+
ov_config[:user] ||= config[:knife][:oneview_username] || ENV['ONEVIEWSDK_USER']
|
41
|
+
ov_config[:password] ||= config[:knife][:oneview_password] || ENV['ONEVIEWSDK_PASSWORD']
|
42
|
+
ov_config[:token] ||= config[:knife][:oneview_token] || ENV['ONEVIEWSDK_TOKEN']
|
43
|
+
ov_config[:ssl_enabled] = false if ov_config[:ssl_enabled] == false || (ov_config[:ssl_enabled].nil? && config[:knife][:oneview_ignore_ssl])
|
44
|
+
ov_config[:timeout] ||= config[:knife][:oneview_timeout] if config[:knife][:oneview_timeout]
|
45
|
+
ov_config[:print_wait_dots] = true if ov_config[:print_wait_dots].nil?
|
46
|
+
ov_config[:logger] = Chef::Log
|
47
|
+
@ov = OneviewSDK::Client.new(ov_config) # OneView client object
|
48
|
+
|
49
|
+
icsp_config = config[:driver_options][:icsp] || {} rescue {}
|
50
|
+
|
51
|
+
@icsp_base_url = icsp_config[:url] || config[:knife][:icsp_url]
|
52
|
+
@icsp_username = icsp_config[:user] || config[:knife][:icsp_username]
|
53
|
+
@icsp_password = icsp_config[:password] || config[:knife][:icsp_password]
|
54
|
+
@icsp_disable_ssl = false
|
55
|
+
@icsp_disable_ssl = true if icsp_config[:ssl_enabled] == false || config[:knife][:icsp_ignore_ssl] == true
|
59
56
|
@icsp_api_version = 102 # Use this version for all calls that don't override it
|
57
|
+
@icsp_timeout = icsp_config[:timeout] || config[:knife][:icsp_timeout]
|
60
58
|
|
61
|
-
Chef::Log.warn '
|
62
|
-
Chef::Log.warn '
|
63
|
-
Chef::Log.warn '
|
59
|
+
Chef::Log.warn 'ICSP url not set! ICSP will be ignored' if @icsp_base_url.nil?
|
60
|
+
Chef::Log.warn 'ICSP user not set! ICSP will be ignored' if @icsp_username.nil?
|
61
|
+
Chef::Log.warn 'ICSP password not set! ICSP will be ignored' if @icsp_password.nil?
|
64
62
|
|
65
63
|
@icsp_ignore = @icsp_base_url.nil? || @icsp_username.nil? || @icsp_password.nil?
|
66
64
|
# If the config is not specified, skip ICSP
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
65
|
+
return if @icsp_ignore
|
66
|
+
Chef::Log.debug("Logging into ICSP at #{@icsp_base_url}")
|
67
|
+
@current_icsp_api_version = get_icsp_api_version
|
68
|
+
@icsp_key = login_to_icsp
|
72
69
|
end
|
73
70
|
|
74
71
|
|
75
72
|
def allocate_machine(action_handler, machine_spec, machine_options)
|
76
|
-
|
73
|
+
raise 'Machine definition missing :driver_options parameter!' unless machine_options[:driver_options]
|
77
74
|
if machine_spec.reference
|
78
|
-
|
79
|
-
|
80
|
-
machine_spec.reference = nil
|
81
|
-
else # Update reference data
|
75
|
+
profile = OneviewSDK::ServerProfile.find_by(@ov, serialNumber: machine_spec.reference['serial_number']).first
|
76
|
+
if profile # Update reference data
|
82
77
|
machine_spec.reference['driver_url'] = driver_url
|
83
78
|
machine_spec.reference['driver_version'] = ONEVIEW_DRIVER_VERSION
|
79
|
+
# TODO: Update profile if differs from Chef and/or Template config
|
80
|
+
machine_spec.reference['profile_name'] = profile['name']
|
81
|
+
else # It doesn't really exist
|
82
|
+
action_handler.report_progress "Machine #{machine_spec.name} does not really exist. Recreating ..."
|
83
|
+
machine_spec.reference = nil
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
87
|
-
action_handler.perform_action "
|
88
|
-
profile = create_machine(action_handler, machine_spec, machine_options)
|
86
|
+
unless machine_spec.reference
|
87
|
+
action_handler.perform_action "Allocate server #{machine_spec.name}" do
|
88
|
+
profile = create_machine(action_handler, machine_spec.name, machine_options)
|
89
89
|
machine_spec.reference = {
|
90
90
|
'driver_url' => driver_url,
|
91
91
|
'driver_version' => ONEVIEW_DRIVER_VERSION,
|
92
|
-
'serial_number' => profile['serialNumber']
|
92
|
+
'serial_number' => profile['serialNumber'],
|
93
|
+
'profile_name' => profile['name']
|
93
94
|
}
|
94
95
|
end
|
95
96
|
end
|
@@ -102,37 +103,22 @@ module Chef::Provisioning
|
|
102
103
|
end
|
103
104
|
end
|
104
105
|
|
106
|
+
|
105
107
|
def ready_machine(action_handler, machine_spec, machine_options)
|
106
|
-
profile =
|
108
|
+
profile = OneviewSDK::ServerProfile.find_by(@ov, serialNumber: machine_spec.reference['serial_number']).first
|
107
109
|
raise "Failed to retrieve Server Profile for #{machine_spec.name}. Serial Number used to search: #{machine_spec.reference['serial_number']}" unless profile
|
110
|
+
customize_machine(action_handler, machine_spec, machine_options, profile)
|
108
111
|
if @icsp_ignore == true
|
109
|
-
|
110
|
-
Chef::Log.warn('Action converge action being used, without an ICSP configuration')
|
112
|
+
Chef::Log.warn("Skipping ICSP configuration for machine '#{machine_spec.name}'")
|
111
113
|
Machine::BasicMachine.new(machine_spec, OneViewNilTransport.new, OneViewNilConvergence.new)
|
112
|
-
else
|
113
|
-
|
114
|
-
customize_machine(action_handler, machine_spec, machine_options, profile)
|
115
|
-
# This is a provisining function and handles installing a chef-client
|
116
|
-
machine_for(machine_spec, machine_options) # Return the Machine object
|
114
|
+
else # Return a machine object that Chef can connect to (to install chef-client)
|
115
|
+
machine_for(machine_spec, machine_options)
|
117
116
|
end
|
118
117
|
end
|
119
118
|
|
120
119
|
|
121
120
|
def machine_for(machine_spec, machine_options)
|
122
|
-
bootstrap_ip_address = machine_options
|
123
|
-
unless bootstrap_ip_address
|
124
|
-
id, connection = machine_options[:driver_options][:connections].find { |_id, c| c[:bootstrap] == true }
|
125
|
-
raise 'Must specify a connection to use to bootstrap!' unless id && connection
|
126
|
-
bootstrap_ip_address = connection[:ip4Address] # For static IPs
|
127
|
-
unless bootstrap_ip_address # Look for dhcp address given to this connection
|
128
|
-
profile = get_oneview_profile_by_sn(machine_spec.reference['serial_number'])
|
129
|
-
my_server = get_icsp_server_by_sn(machine_spec.reference['serial_number'])
|
130
|
-
mac = profile['connections'].find {|x| x['id'] == id}['mac']
|
131
|
-
interface = my_server['interfaces'].find { |i| i['macAddr'] == mac }
|
132
|
-
bootstrap_ip_address = interface['ipv4Addr'] || interface['ipv6Addr']
|
133
|
-
end
|
134
|
-
bootstrap_ip_address ||= my_server['hostName'] # Fall back on hostName
|
135
|
-
end
|
121
|
+
bootstrap_ip_address = ip_from_machine(machine_spec, machine_options)
|
136
122
|
raise 'Server IP address not specified and could not be retrieved!' unless bootstrap_ip_address
|
137
123
|
username = machine_options[:transport_options][:user] || 'root' rescue 'root'
|
138
124
|
default_ssh_options = {
|
@@ -153,39 +139,46 @@ module Chef::Provisioning
|
|
153
139
|
Chef::Provisioning::Machine::UnixMachine.new(machine_spec, transport, convergence_strategy)
|
154
140
|
end
|
155
141
|
|
156
|
-
def stop_machine(
|
157
|
-
|
142
|
+
def stop_machine(_action_handler, machine_spec, _machine_options)
|
143
|
+
return unless machine_spec.reference
|
144
|
+
profile = OneviewSDK::ServerProfile.find_by(@ov, serialNumber: machine_spec.reference['serial_number']).first
|
145
|
+
profile.get_server_hardware.power_off
|
158
146
|
end
|
159
147
|
|
160
148
|
|
161
|
-
def destroy_machine(action_handler, machine_spec,
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
149
|
+
def destroy_machine(action_handler, machine_spec, machine_options)
|
150
|
+
return unless machine_spec.reference
|
151
|
+
profile = OneviewSDK::ServerProfile.find_by(@ov, serialNumber: machine_spec.reference['serial_number']).first
|
152
|
+
if profile
|
153
|
+
profile.get_server_hardware.power_off
|
154
|
+
action_handler.perform_action "Delete server profile #{machine_spec.name}" do
|
155
|
+
action_handler.report_progress "INFO: Deleting server profile #{machine_spec.name}"
|
156
|
+
profile.delete
|
157
|
+
end
|
158
|
+
else
|
159
|
+
action_handler.report_progress "INFO: #{machine_spec.name} is already deleted."
|
160
|
+
end
|
161
|
+
destroy_icsp_server(action_handler, machine_spec) unless @icsp_ignore # Delete os deployment server from ICSP
|
162
|
+
|
163
|
+
name = machine_spec.name # Save for next steps
|
164
|
+
|
165
|
+
# Remove entry from known_hosts file(s)
|
166
|
+
ip_address = ip_from_machine(machine_spec, machine_options)
|
167
|
+
return unless ip_address
|
168
|
+
action_handler.perform_action "Delete entries for #{name} (#{ip_address}) from known_hosts file(s)" do
|
169
|
+
files = [File.expand_path('~/.ssh/known_hosts'), File.expand_path('/etc/ssh/known_hosts')]
|
170
|
+
files.each do |f|
|
171
|
+
next unless File.exist?(f)
|
172
|
+
begin
|
173
|
+
text = File.read(f)
|
174
|
+
text.gsub!(/#{ip_address} ssh-rsa.*(\n|\r\n)/, '')
|
175
|
+
File.open(f, 'w') { |file| file.puts text } if text
|
176
|
+
rescue Exception => e
|
177
|
+
action_handler.report_progress "WARN: Failed to delete entries for #{name} (#{ip_address}) from known_hosts file: '#{f}'! "
|
178
|
+
puts "Error: #{e.message}"
|
185
179
|
end
|
186
180
|
end
|
187
|
-
|
188
|
-
end # End if machine_spec.reference
|
181
|
+
end
|
189
182
|
end # destroy_machine method end
|
190
183
|
|
191
184
|
|
@@ -193,6 +186,32 @@ module Chef::Provisioning
|
|
193
186
|
machine_for(machine_spec, machine_options)
|
194
187
|
end
|
195
188
|
|
189
|
+
private
|
190
|
+
|
191
|
+
def ip_from_machine(machine_spec, machine_options)
|
192
|
+
return machine_options[:driver_options][:ip_address] if machine_options[:driver_options][:ip_address]
|
193
|
+
|
194
|
+
id, connection = machine_options[:driver_options][:connections].find { |_id, c| c[:bootstrap] == true }
|
195
|
+
raise 'Must specify a connection to use to bootstrap!' unless id && connection # TODO: Try first connection anyways?
|
196
|
+
return connection[:ip4Address] if connection[:ip4Address] # Return static IP if set
|
197
|
+
# Look for dhcp address given to this connection
|
198
|
+
if machine_spec.data['normal']['icsp'] && machine_spec.data['normal']['icsp']['interfaces']
|
199
|
+
interface = machine_spec.data['normal']['icsp']['interfaces'].find { |i| i['oneViewId'] == id }
|
200
|
+
if interface
|
201
|
+
addr = interface['ipv4Addr'] || interface['ipv6Addr']
|
202
|
+
return addr if addr
|
203
|
+
end
|
204
|
+
end
|
205
|
+
profile = OneviewSDK::ServerProfile.find_by(@ov, serialNumber: machine_spec.reference['serial_number']).first
|
206
|
+
my_server = get_icsp_server_by_sn(machine_spec.reference['serial_number'])
|
207
|
+
mac = profile['connections'].find { |x| x['id'] == id }['mac']
|
208
|
+
interface = my_server['interfaces'].find { |i| i['macAddr'] == mac }
|
209
|
+
addr = interface['ipv4Addr'] || interface['ipv6Addr']
|
210
|
+
addr ||= my_server['hostName'] # Fall back on hostName
|
211
|
+
Chef::Log.warn "IP address for '#{machine_spec.name}' not specified and could not be retrieved!" unless addr
|
212
|
+
addr
|
213
|
+
end
|
214
|
+
|
196
215
|
end # class end
|
197
216
|
|
198
217
|
# Additional No-Op classes to nil return when a :converge is called
|