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.
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