module OneviewChefProvisioningDriver::IcspHelper
Helpers
for ICSP actions
Public Instance Methods
destroy_icsp_server(action_handler, machine_spec)
click to toggle source
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 242 def destroy_icsp_server(action_handler, machine_spec) my_server = get_icsp_server_by_sn(machine_spec.reference['serial_number']) return false if my_server.nil? || my_server['uri'].nil? action_handler.perform_action "Delete server #{machine_spec.name} from ICSP" do task = rest_api(:icsp, :delete, my_server['uri']) # TODO: This returns nil instead of task info if task['uri'] task_uri = task['uri'] 90.times do # Wait for up to 15 minutes task = rest_api(:icsp, :get, task_uri) break if task['taskState'].casecmp('completed') == 0 print '.' sleep 10 end raise "Deleting os deployment server #{machine_spec.name} at icsp failed!" unless task['taskState'].casecmp('completed') == 0 end end end
get_icsp_api_version()
click to toggle source
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 10 def get_icsp_api_version begin version = rest_api(:icsp, :get, '/rest/version', 'Content-Type' => :none, 'X-API-Version' => :none, 'auth' => :none)['currentVersion'] raise "Couldn't get API version" unless version if version.class != Fixnum version = version.to_i raise 'API version type mismatch' if !version > 0 end rescue puts 'Failed to get ICSP API version. Setting to default (102)' version = 102 end version end
get_icsp_server_by_sn(serial_number)
click to toggle source
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 39 def get_icsp_server_by_sn(serial_number) raise 'Must specify a serialNumber!' if serial_number.nil? || serial_number.empty? search_result = rest_api(:icsp, :get, "/rest/index/resources?category=osdserver&query='osdServerSerialNumber:\"#{serial_number}\"'")['members'] rescue nil if search_result && search_result.size == 1 && search_result.first['attributes']['osdServerSerialNumber'] == serial_number my_server_uri = search_result.first['uri'] my_server = rest_api(:icsp, :get, my_server_uri) end unless my_server && my_server['uri'] os_deployment_servers = rest_api(:icsp, :get, '/rest/os-deployment-servers') # Pick the relevant os deployment server from icsp my_server = nil os_deployment_servers['members'].each do |server| if server['serialNumber'] == serial_number my_server = server break end end end my_server end
icsp_build_personality_data(machine_options, profile)
click to toggle source
Build options for the network configuration
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 203 def icsp_build_personality_data(machine_options, profile) nics = [] if machine_options[:driver_options][:connections] machine_options[:driver_options][:connections].each do |id, data| c = Marshal.load(Marshal.dump(data)) next unless c[:dhcp] || c[:dhcpv4] || c[:ip4Address] || c[:ipv6autoconfig] || c[:staticNetworks] # Invalid network or only switch networks specified c.delete_if { |k, _v| k.to_s == 'bootstrap' } begin c[:macAddress] = profile['connections'].find { |x| x['id'] == id }['mac'] rescue NoMethodError ids = [] profile['connections'].each { |x| ids.push x['id'] } 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." end if @current_icsp_api_version.between?(104, 108) icsp_v104_parse_connection(machine_options, c) else c[:mask] ||= machine_options[:driver_options][:mask] c[:dhcp] ||= false c[:gateway] ||= machine_options[:driver_options][:gateway] c[:dns] ||= machine_options[:driver_options][:dns] end nics.push c end end if @current_icsp_api_version.between?(104, 108) personality_data = icsp_v104_build_personality_data(machine_options, nics) else personality_data = { 'hostName' => machine_options[:driver_options][:host_name], 'domainType' => machine_options[:driver_options][:domainType], 'domainName' => machine_options[:driver_options][:domainName], 'nics' => nics } end personality_data end
icsp_configure_networking(action_handler, machine_spec, machine_options, my_server, profile)
click to toggle source
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 158 def icsp_configure_networking(action_handler, machine_spec, machine_options, my_server, profile) return if machine_options[:driver_options][:skip_network_configuration] == true action_handler.perform_action "Configure networking on #{machine_spec.name}" do action_handler.report_progress "INFO: Configuring networking on #{machine_spec.name}" personality_data = icsp_build_personality_data(machine_options, profile) options = {} options['X-API-Version'] = 104 if @current_icsp_api_version.between?(104, 108) options['body'] = { 'serverData' => [{ 'serverUri' => my_server['uri'], 'personalityData' => personality_data }] } task = rest_api(:icsp, :post, '/rest/os-deployment-jobs/?force=true', options) task_uri = task['uri'] raise "Failed to start network personalization job. Details: #{task['details'] || task['message'] || task}" unless task_uri task = icsp_wait_for(task_uri, 60) # Wait for up to 10 min raise "Error running network personalization job: #{task['jobResult'].first['jobMessage']}\n#{task['jobResult'].first['jobResultErrorDetails']}" unless task == true # Check if ICsp IP config matches machine options requested_ips = [] machine_options[:driver_options][:connections].each do |_id, c| requested_ips.push c[:ip4Address] if c[:ip4Address] && c[:dhcp] == false end my_server_connections = [] 10.times do my_server_connections = rest_api(:icsp, :get, my_server['uri'])['interfaces'] my_server_connections.each { |c| requested_ips.delete c['ipv4Addr'] } break if requested_ips.empty? print ',' sleep 10 end puts "\nWARN: The following IPs are not visible on ICsp, so they may not have gotten configured correctly: #{requested_ips}" unless requested_ips.empty? # Set interface data as normal node attributes my_server_connections.each do |c| c['oneViewId'] = profile['connections'].find { |x| x['mac'] == c['macAddr'] }['id'] rescue nil end machine_spec.data['normal']['icsp'] ||= {} machine_spec.data['normal']['icsp']['interfaces'] = my_server_connections end end
icsp_configure_nic_teams(machine_options, profile)
click to toggle source
Sets ICSP custom attributes to enable nic teaming
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 262 def icsp_configure_nic_teams(machine_options, profile) return false if machine_options[:driver_options][:connections].nil? teams = {} machine_options[:driver_options][:connections].each do |id, options| next unless options.is_a?(Hash) && options[:team] raise "#{options[:team]}: Team names must not include hyphens" if options[:team].to_s.include?('-') teams[options[:team].to_s] ||= [] begin mac = profile['connections'].find { |x| x['id'] == id }['mac'] teams[options[:team].to_s].push mac rescue NoMethodError ids = [] profile['connections'].each { |x| ids.push x['id'] } 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." end end team_strings = [] teams.each do |name, macs| raise "Team '#{name}' must have at least 2 associated connections to form a NIC team" unless macs.size >= 2 team_strings.push "#{name}-#{macs.join(',')}" end machine_options[:driver_options][:custom_attributes] ||= {} machine_options[:driver_options][:custom_attributes][:teams] = team_strings.join('|') end
icsp_run_os_install(action_handler, machine_spec, machine_options, my_server, profile)
click to toggle source
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 100 def icsp_run_os_install(action_handler, machine_spec, machine_options, my_server, profile) return if my_server['state'] == 'OK' # Skip if the OS has already been deployed # Wait for my_server['state'] to be in MAINTENANCE mode if my_server['state'] != 'MAINTENANCE' action_handler.perform_action "Wait for #{machine_spec.name} to go into maintenance mode in ICsp" do action_handler.report_progress "INFO: Waiting for #{machine_spec.name} to go into maintenance mode in ICsp" 120.times do # Wait for up to 20 min my_server = get_icsp_server_by_sn(profile['serialNumber']) break if my_server['state'] != 'MAINTENANCE' print '.' sleep 10 end raise "Timed out waiting for #{machine_spec.name} to go into maintenance mode in ICsp. State: #{my_server['state']}" unless my_server['state'] == 'MAINTENANCE' end end # Get the specified OS Build Plan(s) os_builds = machine_options[:driver_options][:os_build] os_builds = [os_builds] if os_builds.class == String build_plan_uris = [] action_handler.perform_action "Get OS Build Plan(s) info for #{machine_spec.name}" do action_handler.report_progress "INFO: Getting OS Build Plan(s) for #{machine_spec.name}" os_builds.each do |os_build| uri = "/rest/index/resources?userQuery=\"'#{os_build}'\"&category=osdbuildplan" while uri matching_plans = rest_api(:icsp, :get, uri) raise "Search failed for OSBP '#{os_build}'. Response: #{matching_plans}" unless matching_plans['members'] build_plan_uri = matching_plans['members'].find { |bp| bp['name'] == os_build }['uri'] rescue nil break unless build_plan_uri.nil? uri = URI.unescape(matching_plans['nextPageUri']) rescue nil end raise "OS build plan #{os_build} not found!" if build_plan_uri.nil? build_plan_uris.push build_plan_uri end end # Build options for the OS deployment options = {} options['X-API-Version'] = 104 if @current_icsp_api_version.between?(104, 108) options['body'] = { 'osbpUris' => build_plan_uris, 'serverData' => [{ 'serverUri' => my_server['uri'] }] } # Do the OS deployment action_handler.perform_action "Run: #{os_builds} OS Build Plan(s) on #{machine_spec.name}" do action_handler.report_progress "INFO: Running: #{os_builds} OS Build Plan(s) on #{machine_spec.name}" task = rest_api(:icsp, :post, '/rest/os-deployment-jobs/?force=true', options) task_uri = task['uri'] raise "Failed to start OS Deployment Job. Details: #{task['details'] || task['message'] || task}" unless task_uri task = icsp_wait_for(task_uri, 720) raise "Error running OS build plan(s) #{os_builds}: #{task['jobResult'].first['jobMessage']}\n#{task['jobResult'].first['jobResultErrorDetails']}" unless task == true end end
icsp_set_custom_attributes(machine_options, my_server)
click to toggle source
Consume and set any custom attributes that were specified
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 86 def icsp_set_custom_attributes(machine_options, my_server) if machine_options[:driver_options][:custom_attributes] curr_server = rest_api(:icsp, :get, my_server['uri']) machine_options[:driver_options][:custom_attributes].each do |key, val| curr_server['customAttributes'].push( 'values' => [{ 'scope' => 'server', 'value' => val.to_s }], 'key' => key.to_s ) end options = { 'body' => curr_server } rest_api(:icsp, :put, my_server['uri'], options) end end
icsp_wait_for(task_uri, wait_iterations = 60, sleep_seconds = 10)
click to toggle source
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 61 def icsp_wait_for(task_uri, wait_iterations = 60, sleep_seconds = 10) raise 'Must specify a task_uri!' if task_uri.nil? || task_uri.empty? wait_iterations.times do task = rest_api(:icsp, :get, task_uri) if task['taskState'] case task['taskState'].downcase when 'completed' return true when 'error', 'killed', 'terminated' return task end elsif task['running'] == 'false' && task['jobResult'] if task['state'] == 'STATUS_SUCCESS' return true else return task end end print '.' sleep sleep_seconds end false end
login_to_icsp()
click to toggle source
# File lib/chef/provisioning/icsp/icsp_helper.rb, line 25 def login_to_icsp path = '/rest/login-sessions' options = { 'body' => { 'userName' => @icsp_username, 'password' => @icsp_password, 'authLoginDomain' => 'LOCAL' } } response = rest_api(:icsp, :post, path, options) return response['sessionID'] if response['sessionID'] raise("\nERROR! Couldn't log into ICSP server at #{@icsp_base_url}. Response:\n#{response}") end