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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +119 -65
  3. data/chef-provisioning-oneview.gemspec +39 -0
  4. data/lib/chef/provisioning/create_machine.rb +43 -46
  5. data/lib/chef/provisioning/customize_machine.rb +50 -48
  6. data/lib/chef/provisioning/helpers.rb +18 -0
  7. data/lib/chef/provisioning/icsp/api_v104.rb +3 -2
  8. data/lib/chef/provisioning/icsp/icsp_helper.rb +288 -0
  9. data/lib/chef/provisioning/icsp/rest.rb +50 -0
  10. data/lib/chef/provisioning/oneview/oneview_helper.rb +53 -0
  11. data/lib/chef/provisioning/oneview/san_storage.rb +69 -69
  12. data/lib/chef/provisioning/oneview_driver.rb +124 -105
  13. data/lib/chef/provisioning/version.rb +1 -1
  14. metadata +23 -61
  15. data/Rakefile +0 -19
  16. data/lib/chef/provisioning/icsp/icsp_api.rb +0 -284
  17. data/lib/chef/provisioning/oneview/oneview_api.rb +0 -186
  18. data/lib/chef/provisioning/oneview/v1.2/api.rb +0 -3
  19. data/lib/chef/provisioning/oneview/v2.0/api.rb +0 -3
  20. data/lib/chef/provisioning/rest.rb +0 -52
  21. data/spec/shared_context.rb +0 -78
  22. data/spec/spec_helper.rb +0 -23
  23. data/spec/support/fake_action_handler.rb +0 -6
  24. data/spec/support/fake_icsp.rb +0 -73
  25. data/spec/support/fake_machine_spec.rb +0 -18
  26. data/spec/support/fake_oneview.rb +0 -148
  27. data/spec/support/fixtures/icsp/v102/error_404.json +0 -14
  28. data/spec/support/fixtures/icsp/v102/login.json +0 -5
  29. data/spec/support/fixtures/icsp/v102/os-deployment-build-plans.json +0 -99
  30. data/spec/support/fixtures/icsp/v102/os-deployment-servers.json +0 -179
  31. data/spec/support/fixtures/icsp/v102/os-deployment-servers_1670001.json +0 -83
  32. data/spec/support/fixtures/icsp/v102/os-deployment-servers_fakesn.json +0 -9
  33. data/spec/support/fixtures/icsp/v102/server_by_sn_VCGE9KB041.json +0 -45
  34. data/spec/support/fixtures/icsp/v102/server_by_sn_empty.json +0 -16
  35. data/spec/support/fixtures/icsp/v102/version.json +0 -4
  36. data/spec/support/fixtures/oneview/v120/error_404.json +0 -14
  37. data/spec/support/fixtures/oneview/v120/login.json +0 -5
  38. data/spec/support/fixtures/oneview/v120/server-hardware.json +0 -1476
  39. data/spec/support/fixtures/oneview/v120/server-hardware_Template-WebServer.json +0 -468
  40. data/spec/support/fixtures/oneview/v120/server-hardware_specific.json +0 -151
  41. data/spec/support/fixtures/oneview/v120/server-profiles.json +0 -369
  42. data/spec/support/fixtures/oneview/v120/server-profiles_invalid_filter.json +0 -14
  43. data/spec/support/fixtures/oneview/v120/server-profiles_name_Template-WebServer.json +0 -133
  44. data/spec/support/fixtures/oneview/v120/server-profiles_name_Template-WebServerWithSAN.json +0 -200
  45. data/spec/support/fixtures/oneview/v120/server-profiles_name_chef-web01.json +0 -133
  46. data/spec/support/fixtures/oneview/v120/server-profiles_name_chef-web03.json +0 -133
  47. data/spec/support/fixtures/oneview/v120/server-profiles_name_empty.json +0 -15
  48. data/spec/support/fixtures/oneview/v120/server-profiles_sn_VCGE9KB041.json +0 -133
  49. data/spec/support/fixtures/oneview/v120/server-profiles_sn_VCGE9KB042.json +0 -206
  50. data/spec/support/fixtures/oneview/v120/server-profiles_sn_empty.json +0 -15
  51. data/spec/support/fixtures/oneview/v120/storage-volumes_1B5D3CA2-6C5B-41C2-8B97-1821F1883F22.json +0 -26
  52. data/spec/support/fixtures/oneview/v120/tasks_fake_active.json +0 -5
  53. data/spec/support/fixtures/oneview/v120/tasks_fake_complete.json +0 -5
  54. data/spec/support/fixtures/oneview/v120/version.json +0 -4
  55. data/spec/support/fixtures/oneview/v200/server-profile-templates_WebServerTemplate.json +0 -109
  56. data/spec/support/fixtures/oneview/v200/server-profile-templates_WebServerTemplateWithSAN.json +0 -144
  57. data/spec/support/fixtures/oneview/v200/server-profile-templates_invalid.json +0 -16
  58. data/spec/support/fixtures/oneview/v200/server-profile-templates_new-profile_WebServerTemplate.json +0 -125
  59. data/spec/support/fixtures/oneview/v200/server-profile-templates_new-profile_WebServerTemplateWithSAN.json +0 -178
  60. data/spec/support/fixtures/oneview/v200/version.json +0 -4
  61. data/spec/unit/create_machine_spec.rb +0 -78
  62. data/spec/unit/destroy_spec.rb +0 -26
  63. data/spec/unit/icsp_nic_teams_spec.rb +0 -38
  64. data/spec/unit/icsp_search_spec.rb +0 -25
  65. data/spec/unit/oneview_driver_spec.rb +0 -79
  66. data/spec/unit/oneview_login_spec.rb +0 -17
  67. data/spec/unit/oneview_power_spec.rb +0 -51
  68. data/spec/unit/oneview_san_spec.rb +0 -86
  69. data/spec/unit/oneview_search_spec.rb +0 -63
  70. 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
- # Methods for configuring SAN storage on OneView
2
- module OneViewSanStorage
3
- def fill_volume_details(v)
4
- details = rest_api(:oneview, :get, v['volumeUri'])
5
- v['volumeName'] = details['name']
6
- v['permanent'] = details['isPermanent']
7
- v['volumeShareable'] = details['shareable']
8
- v['volumeProvisionType'] = details['provisionType']
9
- v['volumeProvisionedCapacityBytes'] = details['provisionedCapacity']
10
- v['volumeDescription'] = details['description']
11
- v
12
- end
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
- # Prepare profile for SAN storage
15
- def update_san_info(machine_spec, profile)
16
- san_storage = profile['sanStorage']
17
- return profile unless san_storage && !san_storage['volumeAttachments'].empty?
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
- # Sanitize old SAN entries and fill in details
20
- boot_vols = []
21
- san_storage['volumeAttachments'].each do |v|
22
- fill_volume_details(v) unless profile['serverProfileTemplateUri']
23
- raise "#{machine_spec.name}: Should know if volume is sharable:\n#{v}" unless v.key?('volumeShareable')
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
- # Match boot disks by name
26
- boot_vols.push(v['volumeName']) if v['volumeName'] =~ /^boot/i
27
- v['volumeName'] += " #{profile['name']}" unless v['volumeShareable'] # Append profile name to volume name
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
- unless profile['serverProfileTemplateUri'] # Only needed when coppied from profile
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
- unless v['volumeShareable']
35
- # It is private in the profile, so we will clone it
36
- v['volumeUri'] = nil
36
+ next if v['volumeShareable']
37
+ # It is private in the profile, so we will clone it
38
+ v['volumeUri'] = nil
37
39
 
38
- # Assumes all cloned volumes are non-permanet. Might want some global config to control this
39
- v['permanent'] = false
40
- v['lun'] = nil if v['lunType'].casecmp('auto') == 0
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
- # Make sure connections for SAN boot volumes are configured to boot from the correct SAN volume
49
- def enable_boot_from_san(action_handler, machine_spec, profile)
50
- return false if profile['connections'].nil? || profile['connections'].empty?
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
- # If there is a san volume we might need to update boot connections
53
- update_needed = false
54
- profile['sanStorage']['volumeAttachments'].each do |v|
55
- vol_details = rest_api(:oneview, :get, v['volumeUri'])
56
- next unless vol_details['name'] =~ /^boot/i
57
- # Find the enabled path(s), get target wwpn, and then update connection, setting boot targets
58
- v['storagePaths'].each do |s|
59
- next if !s['isEnabled'] || s['storageTargets'].nil? || s['storageTargets'].empty?
60
- connection = profile['connections'].find { |c| c['id'] == s['connectionId'] }
61
- raise "#{machine_spec.name}: Connection #{s['connectionId']} not found! Check SAN settings" unless connection
62
- if connection['boot'].nil? || connection['boot']['priority'] == 'NotBootable'
63
- msg = "#{machine_spec.name}: Connection #{s['connectionId']} is labeled for boot, but the connection is not marked as bootable."
64
- raise "#{msg} Set the connection boot target to Primary or Secondary"
65
- end
66
- target = {}
67
- target['arrayWwpn'] = s['storageTargets'].first.delete(':')
68
- target['lun'] = v['lun']
69
- unless connection['boot']['targets'] && connection['boot']['targets'].first &&
70
- connection['boot']['targets'].first['arrayWwpn'] == target['arrayWwpn'] &&
71
- connection['boot']['targets'].first['lun'] == target['lun']
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
- if update_needed
79
- action_handler.perform_action "Enable SAN-bootable connections for #{machine_spec.name}" do
80
- action_handler.report_progress "INFO: Enabling SAN-bootable connections for #{machine_spec.name}"
81
- power_off(action_handler, machine_spec, profile['serverHardwareUri'])
82
- task = rest_api(:oneview, :put, profile['uri'], { 'body' => profile })
83
- task = oneview_wait_for(task['uri'], 90) # Wait for up to 15 min for profile to be updated
84
- raise "Timed out waiting for enabling SAN-bootable connections on #{machine_spec.name}" if task == false
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 = rest_api(:oneview, :get, profile['uri'])
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 'rest'
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 CreateMachine
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
- if oneview_url.nil? || oneview_url == ''
29
- oneview_url = config[:knife][:oneview_url]
30
- end
31
- raise 'Must set the knife[:oneview_url] attribute!' if oneview_url.nil? || oneview_url.empty?
32
- 'oneview:' + oneview_url
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(oneview_url, config)
36
- OneViewDriver.new(oneview_url, config)
28
+ def self.from_url(url, config)
29
+ OneViewDriver.new(url, config)
37
30
  end
38
31
 
39
- def initialize(canonical_url, config)
40
- super(canonical_url, config)
41
-
42
- @oneview_base_url = config[:knife][:oneview_url]
43
- @oneview_username = config[:knife][:oneview_username]
44
- @oneview_password = config[:knife][:oneview_password]
45
- @oneview_disable_ssl = config[:knife][:oneview_ignore_ssl]
46
- @api_timeout = config[:knife][:oneview_timeout] || 10 # Default timeout: 10 seconds
47
- raise 'Must set knife[:oneview_url] attribute!' if @oneview_base_url.nil? || @oneview_base_url.empty?
48
- raise 'Must set knife[:oneview_username] attribute!' if @oneview_username.nil? || @oneview_username.empty?
49
- raise 'Must set knife[:oneview_password] attribute!' if @oneview_password.nil? || @oneview_password.empty?
50
- @oneview_api_version = 120 # Use this version for all calls that don't override it
51
- @current_oneview_api_version = get_oneview_api_version
52
- Chef::Log.debug("Logging into OneView at #{@oneview_base_url}")
53
- @oneview_key = login_to_oneview
54
-
55
- @icsp_base_url = config[:knife][:icsp_url]
56
- @icsp_username = config[:knife][:icsp_username]
57
- @icsp_password = config[:knife][:icsp_password]
58
- @icsp_disable_ssl = config[:knife][:icsp_ignore_ssl]
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 'knife[:icsp_url] not set in knife.rb!' if @icsp_base_url.nil?
62
- Chef::Log.warn 'knife[:icsp_username] not set in knife.rb!' if @icsp_username.nil?
63
- Chef::Log.warn 'knife[:icsp_password] not set in knife.rb!' if @icsp_password.nil?
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
- unless @icsp_ignore
68
- Chef::Log.debug("Logging into ICSP at #{@icsp_base_url}")
69
- @current_icsp_api_version = get_icsp_api_version
70
- @icsp_key = login_to_icsp
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
- host_name = machine_options[:driver_options][:host_name]
73
+ raise 'Machine definition missing :driver_options parameter!' unless machine_options[:driver_options]
77
74
  if machine_spec.reference
78
- if get_oneview_profile_by_sn(machine_spec.reference['serial_number']).nil? # It doesn't really exist
79
- action_handler.report_progress "Machine #{host_name} does not really exist. Recreating ..."
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
- if !machine_spec.reference
87
- action_handler.perform_action "Creating server #{machine_spec.name}" do
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 = get_oneview_profile_by_sn(machine_spec.reference['serial_number'])
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
- wait_for_profile(action_handler, machine_spec, machine_options, profile)
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
- # This function takes care of installing the operating system etc. to the machine (blade)
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[:driver_options][:ip_address]
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(action_handler, machine_spec, _machine_options)
157
- power_off(action_handler, machine_spec) if machine_spec.reference
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, _machine_options)
162
- if machine_spec.reference
163
- power_off(action_handler, machine_spec) # Power off server
164
- destroy_icsp_server(action_handler, machine_spec) unless @icsp_ignore # Delete os deployment server from ICSP
165
- destroy_oneview_profile(action_handler, machine_spec) # Delete server profile from OneView
166
-
167
- name = machine_spec.name # Save for next steps
168
-
169
- # Remove entry from known_hosts file(s)
170
- ip_address = machine_spec.data['automatic']['ipaddress'] rescue nil
171
- if ip_address
172
- action_handler.perform_action "Delete entry for #{name} (#{ip_address}) from known_hosts file(s)" do
173
- files = [File.expand_path('~/.ssh/known_hosts'), File.expand_path('/etc/ssh/known_hosts')]
174
- files.each do |f|
175
- next unless File.exist?(f)
176
- begin
177
- text = File.read(f)
178
- text.gsub!(/#{ip_address} ssh-rsa.*(\n|\r\n)/, '')
179
- File.open(f, 'w') {|file| file.puts text } if text
180
- rescue Exception => e
181
- action_handler.report_progress "WARN: Failed to delete entry for #{name} (#{ip_address}) from known_hosts file: '#{f}'! "
182
- puts "Error: #{e.message}"
183
- end
184
- end
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