34 import time |
35 import time |
35 import urllib2 |
36 import urllib2 |
36 from urlparse import urlparse |
37 from urlparse import urlparse |
37 |
38 |
38 from lockfile import LockFile, LockTimeout |
39 from lockfile import LockFile, LockTimeout |
|
40 from oslo_concurrency import processutils |
39 from oslo.config import cfg |
41 from oslo.config import cfg |
|
42 from oslo_utils import excutils |
40 from scp import SCPClient |
43 from scp import SCPClient |
41 |
44 |
42 from ironic.common import boot_devices, exception, images, keystone, states, \ |
45 from ironic.common import boot_devices, exception, images, keystone, states, \ |
43 utils |
46 utils |
44 from ironic.common.i18n import _, _LW |
47 from ironic.common.i18n import _, _LE, _LI, _LW |
45 from ironic.conductor import task_manager |
48 from ironic.conductor import task_manager |
46 from ironic.conductor import utils as manager_utils |
49 from ironic.conductor import utils as manager_utils |
47 from ironic.db import api as dbapi |
50 from ironic.db import api as dbapi |
48 from ironic.drivers import base |
51 from ironic.drivers import base |
49 from ironic.drivers.modules import ipmitool |
52 from ironic.drivers.modules import ipmitool |
50 from ironic.drivers import utils as driver_utils |
53 from ironic.drivers import utils as driver_utils |
51 from ironic.openstack.common import log as logging |
54 from ironic.openstack.common import log as logging |
52 from ironic.openstack.common import loopingcall, processutils |
55 from ironic.openstack.common import loopingcall |
53 |
56 |
54 PLATFORM = platform.system() |
57 PLATFORM = platform.system() |
55 if PLATFORM != "SunOS": |
58 if PLATFORM != "SunOS": |
56 import tarfile |
59 import tarfile |
57 else: |
60 else: |
168 } |
169 } |
169 |
170 |
170 COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy() |
171 COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy() |
171 COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES) |
172 COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES) |
172 |
173 |
|
174 IPMI_PROPERTIES = [ |
|
175 ('mac', '/System/host_primary_mac_address'), |
|
176 ('serial', '/System/serial_number'), |
|
177 ('model', '/System/model'), |
|
178 ('cpu_arch', '/System/Processors/architecture'), |
|
179 ('memory_mb', '/System/Memory/installed_memory'), |
|
180 ('cpus', '/System/Processors/installed_cpus'), |
|
181 ('datalinks', '/System/Networking/installed_eth_nics'), |
|
182 ('disks', '/System/Storage/installed_disks'), |
|
183 ('local_gb', '/System/Storage/installed_disk_size') |
|
184 ] |
|
185 |
|
186 CPU_LOCATION = '/System/Processors/CPUs/CPU_%d/total_cores' |
|
187 |
173 LAST_CMD_TIME = {} |
188 LAST_CMD_TIME = {} |
174 TIMING_SUPPORT = None |
189 TIMING_SUPPORT = None |
175 SINGLE_BRIDGE_SUPPORT = None |
190 SINGLE_BRIDGE_SUPPORT = None |
176 DUAL_BRIDGE_SUPPORT = None |
191 DUAL_BRIDGE_SUPPORT = None |
177 |
192 |
331 args = ['/usr/sbin/ipmitool', |
347 args = ['/usr/sbin/ipmitool', |
332 '-I', |
348 '-I', |
333 'lanplus', |
349 'lanplus', |
334 '-H', |
350 '-H', |
335 driver_info['address'], |
351 driver_info['address'], |
336 '-L', driver_info.get('priv_level') |
352 '-L', driver_info['priv_level'] |
337 ] |
353 ] |
338 |
|
339 if driver_info['username']: |
354 if driver_info['username']: |
340 args.append('-U') |
355 args.append('-U') |
341 args.append(driver_info['username']) |
356 args.append(driver_info['username']) |
342 |
357 |
343 for name, option in ipmitool.BRIDGING_OPTIONS: |
358 for name, option in ipmitool.BRIDGING_OPTIONS: |
344 if driver_info[name] is not None: |
359 if driver_info[name] is not None: |
345 args.append(option) |
360 args.append(option) |
346 args.append(driver_info[name]) |
361 args.append(driver_info[name]) |
347 |
362 |
348 # specify retry timing more precisely, if supported |
363 # specify retry timing more precisely, if supported |
|
364 num_tries = max( |
|
365 (CONF.ipmi.retry_timeout // CONF.ipmi.min_command_interval), 1) |
|
366 |
349 if ipmitool._is_option_supported('timing'): |
367 if ipmitool._is_option_supported('timing'): |
350 num_tries = max( |
|
351 (CONF.ipmi.retry_timeout // CONF.ipmi.min_command_interval), 1) |
|
352 args.append('-R') |
368 args.append('-R') |
353 args.append(str(num_tries)) |
369 args.append(str(num_tries)) |
354 |
370 |
355 args.append('-N') |
371 args.append('-N') |
356 args.append(str(CONF.ipmi.min_command_interval)) |
372 args.append(str(CONF.ipmi.min_command_interval)) |
357 |
373 |
358 # 'ipmitool' command will prompt password if there is no '-f' option, |
374 end_time = (time.time() + CONF.ipmi.retry_timeout) |
359 # we set it to '\0' to write a password file to support empty password |
375 |
360 with ipmitool._make_password_file(driver_info['password'] or '\0') \ |
376 while True: |
361 as pw_file: |
377 num_tries = num_tries - 1 |
362 args.append('-f') |
|
363 args.append(pw_file) |
|
364 args = args + list(command) # Append as a list don't split(" ") |
|
365 |
|
366 # NOTE(deva): ensure that no communications are sent to a BMC more |
378 # NOTE(deva): ensure that no communications are sent to a BMC more |
367 # often than once every min_command_interval seconds. |
379 # often than once every min_command_interval seconds. |
368 time_till_next_poll = CONF.ipmi.min_command_interval - ( |
380 time_till_next_poll = CONF.ipmi.min_command_interval - ( |
369 time.time() - LAST_CMD_TIME.get(driver_info['address'], 0)) |
381 time.time() - LAST_CMD_TIME.get(driver_info['address'], 0)) |
370 if time_till_next_poll > 0: |
382 if time_till_next_poll > 0: |
371 time.sleep(time_till_next_poll) |
383 time.sleep(time_till_next_poll) |
372 try: |
384 # Resetting the list that will be utilized so the password arguments |
373 out, err = utils.execute(*args) |
385 # from any previous execution are preserved. |
374 finally: |
386 cmd_args = args[:] |
375 LAST_CMD_TIME[driver_info['address']] = time.time() |
387 # 'ipmitool' command will prompt password if there is no '-f' |
376 return out, err |
388 # option, we set it to '\0' to write a password file to support |
|
389 # empty password |
|
390 with ipmitool._make_password_file( |
|
391 driver_info['password'] or '\0' |
|
392 ) as pw_file: |
|
393 cmd_args.append('-f') |
|
394 cmd_args.append(pw_file) |
|
395 cmd_args = cmd_args + list(command) # Append list, don't split |
|
396 try: |
|
397 out, err = utils.execute(*cmd_args) |
|
398 return out, err |
|
399 except processutils.ProcessExecutionError as e: |
|
400 with excutils.save_and_reraise_exception() as ctxt: |
|
401 err_list = [x for x in ipmitool.IPMITOOL_RETRYABLE_FAILURES |
|
402 if x in e.message] |
|
403 if ((time.time() > end_time) or |
|
404 (num_tries == 0) or |
|
405 not err_list): |
|
406 LOG.error(_LE('IPMI Error while attempting ' |
|
407 '"%(cmd)s" for node %(node)s. ' |
|
408 'Error: %(error)s'), |
|
409 { |
|
410 'node': driver_info['uuid'], |
|
411 'cmd': e.cmd, |
|
412 'error': e |
|
413 }) |
|
414 else: |
|
415 ctxt.reraise = False |
|
416 LOG.warning(_LW('IPMI Error encountered, retrying ' |
|
417 '"%(cmd)s" for node %(node)s. ' |
|
418 'Error: %(error)s'), |
|
419 { |
|
420 'node': driver_info['uuid'], |
|
421 'cmd': e.cmd, |
|
422 'error': e |
|
423 }) |
|
424 finally: |
|
425 LAST_CMD_TIME[driver_info['address']] = time.time() |
377 |
426 |
378 |
427 |
379 def _get_node_architecture(node): |
428 def _get_node_architecture(node): |
380 """Queries the node for architecture type |
429 """Queries the node for architecture type |
381 |
430 |
382 :param node: the Node of interest. |
431 :param node: the Node of interest. |
383 :returns: SPARC or X86 depending on architecture discovered |
432 :returns: SPARC or X86 depending on architecture discovered |
384 :raises: IPMIFailure if ipmitool command fails |
433 :raises: IPMIFailure if ipmitool command fails |
385 """ |
434 """ |
386 LOG.debug("SolarisDeploy._get_node_architecture") |
435 LOG.debug("SolarisDeploy._get_node_architecture") |
387 ipmi_cmd_args = ['sunoem', 'getval', '/System/Processors/architecture'] |
436 cpu_arch = node.properties.get('cpu_arch', None) |
388 driver_info = _parse_driver_info(node) |
437 if cpu_arch is None: |
389 try: |
438 LOG.info(_LI("Inspection not performed, retrieving architecture via " |
390 out, _err = _exec_ipmitool(driver_info, ipmi_cmd_args) |
439 "IPMI for node: %s"), node.uuid) |
391 except Exception: |
440 ipmi_cmd_args = ['sunoem', 'getval', '/System/Processors/architecture'] |
392 raise exception.IPMIFailure(cmd=ipmi_cmd_args) |
441 driver_info = _parse_driver_info(node) |
393 |
442 try: |
394 LOG.debug("SolarisDeploy._get_node_architecture: arch: '%s'" % (out)) |
443 cpu_arch, _err = _exec_ipmitool(driver_info, ipmi_cmd_args) |
395 |
444 except Exception as err: |
396 if 'SPARC' in out: |
445 LOG.error(_LE("Failed to get node architecture from IPMI : %s" % |
|
446 (err))) |
|
447 raise exception.IPMIFailure(cmd=err) |
|
448 |
|
449 propdict = {'cpu_arch': cpu_arch} |
|
450 node_properties = node.properties |
|
451 node_properties.update(propdict) |
|
452 node.properties = node_properties |
|
453 node.save() |
|
454 |
|
455 LOG.debug("SolarisDeploy._get_node_architecture: cpu_arch: '%s'" |
|
456 % (cpu_arch)) |
|
457 |
|
458 if 'SPARC' in cpu_arch: |
397 return 'SPARC' |
459 return 'SPARC' |
398 elif 'x86' in out: |
460 elif 'x86' in cpu_arch: |
399 return 'x86' |
461 return 'x86' |
400 else: |
462 else: |
401 raise SolarisIPMIError(msg="Unknown node architecture: %s" % (out)) |
463 raise SolarisIPMIError(msg="Unknown node architecture: %s" |
|
464 % (cpu_arch)) |
402 |
465 |
403 |
466 |
404 def _check_deploy_state(task, node_uuid, deploy_thread): |
467 def _check_deploy_state(task, node_uuid, deploy_thread): |
405 """ Check deployment state of a running install |
468 """ Check deployment state of a running install |
406 |
469 |
434 deploy_thread.stop() |
497 deploy_thread.stop() |
435 if deploy_thread.state in [states.DEPLOYING, states.DEPLOYWAIT]: |
498 if deploy_thread.state in [states.DEPLOYING, states.DEPLOYWAIT]: |
436 # Update node with done/fail state |
499 # Update node with done/fail state |
437 if task.node: |
500 if task.node: |
438 task.node.provision_state = states.DEPLOYFAIL |
501 task.node.provision_state = states.DEPLOYFAIL |
439 task.node.last_error = "Failed to find node." |
502 task.node.last_error = "Failed to find node whilst " + \ |
|
503 "transitioning to '%s' state." % \ |
|
504 (task.node.target_provision_state) |
440 task.node.target_provision_state = states.NOSTATE |
505 task.node.target_provision_state = states.NOSTATE |
441 task.node.save() |
506 task.node.save() |
442 raise loopingcall.LoopingCallDone() |
507 raise loopingcall.LoopingCallDone() |
443 except Exception as err: |
508 except Exception as err: |
444 LOG.info(_("During check_deploy_state, node %(node)s could " |
509 LOG.info(_("During check_deploy_state, node %(node)s could " |
445 "not be retrieved: %(err)") % |
510 "not be retrieved: %(err)s") % |
446 {'node': node_uuid, 'err': err}) |
511 {'node': node_uuid, 'err': err}) |
447 # Thread should have stopped already, but lets make sure. |
512 # Thread should have stopped already, but lets make sure. |
448 deploy_thread.stop() |
513 deploy_thread.stop() |
449 if deploy_thread.state in [states.DEPLOYING, states.DEPLOYWAIT]: |
514 if deploy_thread.state in [states.DEPLOYING, states.DEPLOYWAIT]: |
450 # Update node with done/fail state |
515 # Update node with done/fail state |
451 if task.node: |
516 if task.node: |
452 task.node.last_error = "Failed to find node." |
517 task.node.last_error = "Failed to find node whilst " + \ |
|
518 "transitioning to '%s' state." % \ |
|
519 (task.node.target_provision_state) |
453 task.node.provision_state = states.DEPLOYFAIL |
520 task.node.provision_state = states.DEPLOYFAIL |
454 task.node.target_provision_state = states.NOSTATE |
521 task.node.target_provision_state = states.NOSTATE |
455 task.node.save() |
522 task.node.save() |
456 raise loopingcall.LoopingCallDone() |
523 raise loopingcall.LoopingCallDone() |
457 |
524 |
458 LOG.debug("_check_deploy_state().cur_node.target_provision_state: %s" % |
525 LOG.debug("_check_deploy_state().cur_node.target_provision_state: %s" % |
459 (cur_node.target_provision_state)) |
526 (cur_node.target_provision_state)) |
|
527 LOG.debug("_check_deploy_state().cur_node.provision_state: %s" % |
|
528 (cur_node.provision_state)) |
460 |
529 |
461 if deploy_thread.state not in [states.DEPLOYING, states.DEPLOYWAIT]: |
530 if deploy_thread.state not in [states.DEPLOYING, states.DEPLOYWAIT]: |
462 LOG.debug("_check_deploy_state().done: %s" % (deploy_thread.state)) |
531 LOG.debug("_check_deploy_state().done: %s" % (deploy_thread.state)) |
463 # Node has completed deployment, success or failure |
532 # Node has completed deployment, success or failure |
464 |
533 |
788 raise SolarisIPMIError(msg=err_msg) |
879 raise SolarisIPMIError(msg=err_msg) |
789 |
880 |
790 return mount_dir, temp_uar |
881 return mount_dir, temp_uar |
791 |
882 |
792 |
883 |
793 def _umount_archive(mount_dir, temp_uar): |
884 def _umount_archive(mount_dir): |
794 """ Unmount archive and remove mount point directory |
885 """ Unmount archive and remove mount point directory |
795 |
886 |
796 :param mount_dir: Path to mounted archive |
887 :param mount_dir: Path to mounted archive |
797 :param temp_uar: Path to glance local uar to remove |
888 :param temp_uar: Path to glance local uar to remove |
798 """ |
889 """ |
799 LOG.debug("SolarisDeploy._umount_archive:mount_dir: '%s', temp_uar: %s" % |
890 LOG.debug("SolarisDeploy._umount_archive:mount_dir: '%s'" % (mount_dir)) |
800 (mount_dir, temp_uar)) |
|
801 |
891 |
802 cmd = ["/usr/sbin/umount", mount_dir] |
892 cmd = ["/usr/sbin/umount", mount_dir] |
803 pc = Popen(cmd, stdout=PIPE, stderr=PIPE) |
893 pc = Popen(cmd, stdout=PIPE, stderr=PIPE) |
804 _stdout, err = pc.communicate() |
894 _stdout, err = pc.communicate() |
805 if pc.returncode != 0: |
895 if pc.returncode != 0: |
1452 :param task: a TaskManager instance. |
1542 :param task: a TaskManager instance. |
1453 :returns: deploy state DEPLOYWAIT. |
1543 :returns: deploy state DEPLOYWAIT. |
1454 """ |
1544 """ |
1455 LOG.debug("SolarisDeploy.deploy()") |
1545 LOG.debug("SolarisDeploy.deploy()") |
1456 |
1546 |
1457 arch = _get_node_architecture(task.node) |
1547 cpu_arch = _get_node_architecture(task.node) |
1458 |
1548 |
1459 # Ensure persistence is false so net boot only occurs once |
1549 # Ensure persistence is false so net boot only occurs once |
1460 if arch == 'x86': |
1550 if cpu_arch == 'x86': |
1461 # Set boot device to PXE network boot |
1551 # Set boot device to PXE network boot |
1462 dev_cmd = 'pxe' |
1552 dev_cmd = 'pxe' |
1463 elif arch == 'SPARC': |
1553 elif cpu_arch == 'SPARC': |
1464 # Set bootmode script to network DHCP |
1554 # Set bootmode script to network DHCP |
1465 dev_cmd = 'wanboot' |
1555 dev_cmd = 'wanboot' |
1466 else: |
1556 else: |
1467 raise exception.InvalidParameterValue( |
1557 raise exception.InvalidParameterValue( |
1468 _("Invalid node architecture of '%s'.") % (arch)) |
1558 _("Invalid node architecture of '%s'.") % (cpu_arch)) |
1469 |
1559 |
1470 manager_utils.node_set_boot_device(task, dev_cmd, |
1560 manager_utils.node_set_boot_device(task, dev_cmd, |
1471 persistent=False) |
1561 persistent=False) |
1472 manager_utils.node_power_action(task, states.REBOOT) |
1562 manager_utils.node_power_action(task, states.REBOOT) |
1473 |
1563 |
1523 """ |
1613 """ |
1524 LOG.debug("SolarisDeploy.prepare()") |
1614 LOG.debug("SolarisDeploy.prepare()") |
1525 |
1615 |
1526 ai_manifest = task.node.driver_info.get('ai_manifest', None) |
1616 ai_manifest = task.node.driver_info.get('ai_manifest', None) |
1527 ai_service = task.node.driver_info.get('ai_service', None) |
1617 ai_service = task.node.driver_info.get('ai_service', None) |
1528 arch = _get_node_architecture(task.node) |
1618 cpu_arch = _get_node_architecture(task.node) |
1529 archive_uri = task.node.driver_info.get('archive_uri', None) |
1619 archive_uri = task.node.driver_info.get('archive_uri', None) |
1530 fmri = task.node.driver_info.get('fmri', None) |
1620 fmri = task.node.driver_info.get('fmri', None) |
1531 install_profiles = task.node.driver_info.get('install_profiles', None) |
1621 install_profiles = task.node.driver_info.get('install_profiles', None) |
1532 publishers = task.node.driver_info.get('publishers', None) |
1622 publishers = task.node.driver_info.get('publishers', None) |
1533 sc_profiles = task.node.driver_info.get('sc_profiles', None) |
1623 sc_profiles = task.node.driver_info.get('sc_profiles', None) |
1557 elif ai_service: |
1647 elif ai_service: |
1558 # Instantiate AIService object for this node/service |
1648 # Instantiate AIService object for this node/service |
1559 aiservice = AIService(task, ai_service) |
1649 aiservice = AIService(task, ai_service) |
1560 else: |
1650 else: |
1561 # IPS Install, ensure default architecture service exists |
1651 # IPS Install, ensure default architecture service exists |
1562 if arch == "x86": |
1652 if cpu_arch == "x86": |
1563 ai_service = "default-i386" |
1653 ai_service = "default-i386" |
1564 elif arch == 'SPARC': |
1654 elif cpu_arch == 'SPARC': |
1565 ai_service = "default-sparc" |
1655 ai_service = "default-sparc" |
1566 else: |
1656 else: |
1567 raise exception.InvalidParameterValue( |
1657 raise exception.InvalidParameterValue( |
1568 _("Invalid node architecture of '%s'.") % (arch)) |
1658 _("Invalid node architecture of '%s'.") % (cpu_arch)) |
1569 |
1659 |
1570 # Instantiate AIService object for this node/service |
1660 # Instantiate AIService object for this node/service |
1571 aiservice = AIService(task, ai_service) |
1661 aiservice = AIService(task, ai_service) |
1572 |
1662 |
1573 # Check if AI Service exists, raise exception of not |
1663 # Check if AI Service exists, raise exception of not |
1712 :param task: a TaskManager instance. |
1802 :param task: a TaskManager instance. |
1713 """ |
1803 """ |
1714 LOG.debug("SolarisDeploy.clean_up()") |
1804 LOG.debug("SolarisDeploy.clean_up()") |
1715 |
1805 |
1716 ai_service = task.node.driver_info.get('ai_service', None) |
1806 ai_service = task.node.driver_info.get('ai_service', None) |
1717 arch = _get_node_architecture(task.node) |
1807 cpu_arch = _get_node_architecture(task.node) |
1718 archive_uri = task.node.driver_info.get('archive_uri', None) |
1808 archive_uri = task.node.driver_info.get('archive_uri', None) |
1719 |
1809 |
1720 # Instantiate AIService object for this node/service |
1810 # Instantiate AIService object for this node/service |
1721 if archive_uri: |
1811 if archive_uri: |
1722 aiservice = AIService(task, _get_archive_uuid(task)) |
1812 aiservice = AIService(task, _get_archive_uuid(task)) |
1723 elif ai_service: |
1813 elif ai_service: |
1724 aiservice = AIService(task, ai_service) |
1814 aiservice = AIService(task, ai_service) |
1725 else: |
1815 else: |
1726 if arch == "x86": |
1816 if cpu_arch == "x86": |
1727 ai_service = "default-i386" |
1817 ai_service = "default-i386" |
1728 elif arch == 'SPARC': |
1818 elif cpu_arch == 'SPARC': |
1729 ai_service = "default-sparc" |
1819 ai_service = "default-sparc" |
1730 else: |
1820 else: |
1731 raise exception.InvalidParameterValue( |
1821 raise exception.InvalidParameterValue( |
1732 _("Invalid node architecture of '%s'.") % (arch)) |
1822 _("Invalid node architecture of '%s'.") % (cpu_arch)) |
1733 aiservice = AIService(task, ai_service) |
1823 aiservice = AIService(task, ai_service) |
1734 |
1824 |
1735 # Check if AI Service exists, log message if already removed |
1825 # Check if AI Service exists, log message if already removed |
1736 if not aiservice.exists: |
1826 if not aiservice.exists: |
1737 # There is nothing to clean up as service removed |
1827 # There is nothing to clean up as service removed |
1815 if task is None: |
1905 if task is None: |
1816 return [boot_devices.PXE, boot_devices.DISK, boot_devices.CDROM, |
1906 return [boot_devices.PXE, boot_devices.DISK, boot_devices.CDROM, |
1817 boot_devices.BIOS, boot_devices.SAFE] |
1907 boot_devices.BIOS, boot_devices.SAFE] |
1818 else: |
1908 else: |
1819 # Get architecture of node and return supported boot devices |
1909 # Get architecture of node and return supported boot devices |
1820 arch = _get_node_architecture(task.node) |
1910 cpu_arch = _get_node_architecture(task.node) |
1821 if arch == 'x86': |
1911 if cpu_arch == 'x86': |
1822 return [boot_devices.PXE, boot_devices.DISK, |
1912 return [boot_devices.PXE, boot_devices.DISK, |
1823 boot_devices.CDROM, boot_devices.BIOS, |
1913 boot_devices.CDROM, boot_devices.BIOS, |
1824 boot_devices.SAFE] |
1914 boot_devices.SAFE] |
1825 elif arch == 'SPARC': |
1915 elif cpu_arch == 'SPARC': |
1826 return [boot_devices.DISK, 'wanboot'] |
1916 return [boot_devices.DISK, 'wanboot'] |
1827 else: |
1917 else: |
1828 raise exception.InvalidParameterValue( |
1918 raise exception.InvalidParameterValue( |
1829 _("Invalid node architecture of '%s'.") % (arch)) |
1919 _("Invalid node architecture of '%s'.") % (cpu_arch)) |
1830 |
1920 |
1831 @task_manager.require_exclusive_lock |
1921 @task_manager.require_exclusive_lock |
1832 def set_boot_device(self, task, device, persistent=False): |
1922 def set_boot_device(self, task, device, persistent=False): |
1833 """Set the boot device for the task's node. |
1923 """Set the boot device for the task's node. |
1834 |
1924 |
1845 :raises: IPMIFailure on an error from ipmitool. |
1935 :raises: IPMIFailure on an error from ipmitool. |
1846 |
1936 |
1847 """ |
1937 """ |
1848 LOG.debug("SolarisManagement.set_boot_device: %s" % device) |
1938 LOG.debug("SolarisManagement.set_boot_device: %s" % device) |
1849 |
1939 |
1850 arch = _get_node_architecture(task.node) |
1940 cpu_arch = _get_node_architecture(task.node) |
1851 archive_uri = task.node.driver_info.get('archive_uri') |
1941 archive_uri = task.node.driver_info.get('archive_uri') |
1852 publishers = task.node.driver_info.get('publishers') |
1942 publishers = task.node.driver_info.get('publishers') |
1853 fmri = task.node.driver_info.get('fmri') |
1943 fmri = task.node.driver_info.get('fmri') |
1854 |
1944 |
1855 if arch == 'x86': |
1945 if cpu_arch == 'x86': |
1856 if device not in self.get_supported_boot_devices(task=task): |
1946 if device not in self.get_supported_boot_devices(task=task): |
1857 raise exception.InvalidParameterValue(_( |
1947 raise exception.InvalidParameterValue(_( |
1858 "Invalid boot device %s specified.") % device) |
1948 "Invalid boot device %s specified.") % device) |
1859 cmd = ["chassis", "bootdev", device] |
1949 cmd = ["chassis", "bootdev", device] |
1860 if persistent: |
1950 if persistent: |
1861 cmd = cmd + " options=persistent" |
1951 cmd.append("options=persistent") |
1862 elif arch == 'SPARC': |
1952 elif cpu_arch == 'SPARC': |
1863 # Set bootmode script to network DHCP or disk |
1953 # Set bootmode script to network DHCP or disk |
1864 if device == 'wanboot': |
1954 if device == 'wanboot': |
1865 boot_cmd = 'set /HOST/bootmode script="' |
1955 boot_cmd = 'set /HOST/bootmode script="' |
1866 script_str = 'boot net:dhcp - install' |
1956 script_str = 'boot net:dhcp - install' |
1867 if archive_uri: |
1957 if archive_uri: |
1892 raise exception.InvalidParameterValue(_( |
1982 raise exception.InvalidParameterValue(_( |
1893 "SPARC firmware bootmode script length exceeds 255:" |
1983 "SPARC firmware bootmode script length exceeds 255:" |
1894 " %s") % script_str) |
1984 " %s") % script_str) |
1895 boot_cmd += script_str + '"' |
1985 boot_cmd += script_str + '"' |
1896 cmd = ['sunoem', 'cli', boot_cmd] |
1986 cmd = ['sunoem', 'cli', boot_cmd] |
1897 elif device == 'disk': |
1987 elif device == boot_devices.DISK: |
1898 cmd = ['sunoem', 'cli', |
1988 cmd = ['sunoem', 'cli', |
1899 'set /HOST/bootmode script=""'] |
1989 'set /HOST/bootmode script=""'] |
1900 else: |
1990 else: |
1901 raise exception.InvalidParameterValue(_( |
1991 raise exception.InvalidParameterValue(_( |
1902 "Invalid boot device %s specified.") % (device)) |
1992 "Invalid boot device %s specified.") % (device)) |
1903 else: |
1993 else: |
1904 raise exception.InvalidParameterValue( |
1994 raise exception.InvalidParameterValue( |
1905 _("Invalid node architecture of '%s'.") % (arch)) |
1995 _("Invalid node architecture of '%s'.") % (cpu_arch)) |
1906 |
1996 |
1907 driver_info = _parse_driver_info(task.node) |
1997 driver_info = _parse_driver_info(task.node) |
1908 try: |
1998 try: |
1909 _out, _err = _exec_ipmitool(driver_info, cmd) |
1999 _out, _err = _exec_ipmitool(driver_info, cmd) |
1910 except (exception.PasswordFileFailedToCreate, |
2000 except (exception.PasswordFileFailedToCreate, |
1933 :persistent: Whether the boot device will persist to all |
2023 :persistent: Whether the boot device will persist to all |
1934 future boots or not, None if it is unknown. |
2024 future boots or not, None if it is unknown. |
1935 |
2025 |
1936 """ |
2026 """ |
1937 LOG.debug("SolarisManagement.get_boot_device") |
2027 LOG.debug("SolarisManagement.get_boot_device") |
1938 arch = _get_node_architecture(task.node) |
2028 cpu_arch = _get_node_architecture(task.node) |
1939 driver_info = _parse_driver_info(task.node) |
2029 driver_info = _parse_driver_info(task.node) |
1940 response = {'boot_device': None, 'persistent': None} |
2030 response = {'boot_device': None, 'persistent': None} |
1941 |
2031 |
1942 if arch == 'x86': |
2032 if cpu_arch == 'x86': |
1943 cmd = ["chassis", "bootparam", "get", "5"] |
2033 cmd = ["chassis", "bootparam", "get", "5"] |
1944 elif arch == 'SPARC': |
2034 elif cpu_arch == 'SPARC': |
1945 cmd = ['sunoem', 'getval', '/HOST/bootmode/script'] |
2035 cmd = ['sunoem', 'getval', '/HOST/bootmode/script'] |
1946 else: |
2036 else: |
1947 raise exception.InvalidParameterValue( |
2037 raise exception.InvalidParameterValue( |
1948 _("Invalid node architecture of '%s'.") % (arch)) |
2038 _("Invalid node architecture of '%s'.") % (cpu_arch)) |
1949 |
2039 |
1950 try: |
2040 try: |
1951 out, _err = _exec_ipmitool(driver_info, cmd) |
2041 out, _err = _exec_ipmitool(driver_info, cmd) |
1952 except (exception.PasswordFileFailedToCreate, |
2042 except (exception.PasswordFileFailedToCreate, |
1953 processutils.ProcessExecutionError) as err: |
2043 processutils.ProcessExecutionError) as err: |
1995 |
2085 |
1996 """ |
2086 """ |
1997 driver_info = _parse_driver_info(task.node) |
2087 driver_info = _parse_driver_info(task.node) |
1998 # with '-v' option, we can get the entire sensor data including the |
2088 # with '-v' option, we can get the entire sensor data including the |
1999 # extended sensor informations |
2089 # extended sensor informations |
2000 cmd = "-v sdr" |
2090 cmd = ['sdr', '-v'] |
2001 try: |
2091 try: |
2002 out, _err = _exec_ipmitool(driver_info, cmd) |
2092 out, _err = _exec_ipmitool(driver_info, cmd) |
2003 except (exception.PasswordFileFailedToCreate, |
2093 except (exception.PasswordFileFailedToCreate, |
2004 processutils.ProcessExecutionError) as err: |
2094 processutils.ProcessExecutionError) as err: |
2005 raise exception.FailedToGetSensorData(node=task.node.uuid, |
2095 raise exception.FailedToGetSensorData(node=task.node.uuid, |
2006 error=err) |
2096 error=err) |
2007 |
2097 |
2008 return ipmitool._parse_ipmi_sensors_data(task.node, out) |
2098 return ipmitool._parse_ipmi_sensors_data(task.node, out) |
|
2099 |
|
2100 |
|
2101 class SolarisInspect(base.InspectInterface): |
|
2102 """Inspect class for solaris nodes.""" |
|
2103 |
|
2104 def get_properties(self): |
|
2105 """Return Solaris driver properties""" |
|
2106 return COMMON_PROPERTIES |
|
2107 |
|
2108 def validate(self, task): |
|
2109 """Validate driver_info containts IPMI credentials. |
|
2110 |
|
2111 Ensure 'driver_info' containers the required IPMI |
|
2112 properties used to access a nodes properties. |
|
2113 |
|
2114 :param task: a TaskManager instance |
|
2115 :raises: InvalidParameterValue if required IPMI parameters |
|
2116 are missing. |
|
2117 :raises: MissingParameterValue if a required parameter is missing. |
|
2118 """ |
|
2119 _parse_driver_info(task.node) |
|
2120 |
|
2121 def inspect_hardware(self, task): |
|
2122 """Inspect hardware to get the hardware properties. |
|
2123 |
|
2124 Inspects hardware to get the defined IPMI_PROPERTIES. |
|
2125 Failure occures if any of the defined IPMI_PROPERTIES are not |
|
2126 determinable from the node. |
|
2127 |
|
2128 :param task: a TaskManager instance |
|
2129 :raises: HardwareInspectionFailure if properties could |
|
2130 not be retrieved successfully. |
|
2131 :returns: the resulting state of inspection. |
|
2132 """ |
|
2133 LOG.debug("SolarisInspect.inspect_hardware") |
|
2134 |
|
2135 ipmi_props = self._get_ipmi_properties(task) |
|
2136 |
|
2137 keys, _none = zip(*IPMI_PROPERTIES) |
|
2138 vallist = [line.split(': ')[1] |
|
2139 for line in ipmi_props.strip().splitlines()] |
|
2140 propdict = dict(zip(keys, vallist)) |
|
2141 |
|
2142 # Installed memory size is returned in GB, Nova assumes this is MB |
|
2143 # so convert if returned in GB |
|
2144 memsize, memtype = propdict['memory_mb'].split(' ') |
|
2145 if memtype == 'GB': |
|
2146 propdict['memory_mb'] = int(memsize) * 1024 |
|
2147 else: |
|
2148 propdict['memory_mb'] = int(memsize) |
|
2149 |
|
2150 cpu_props = self._get_cpu_cores(task, propdict['cpus']) |
|
2151 |
|
2152 vallist = [line.split(': ')[1] |
|
2153 for line in cpu_props.strip().splitlines()] |
|
2154 total_cores = sum(map(int, vallist)) |
|
2155 propdict['cores'] = total_cores |
|
2156 |
|
2157 node_properties = task.node.properties |
|
2158 node_properties.update(propdict) |
|
2159 task.node.properties = node_properties |
|
2160 task.node.save() |
|
2161 |
|
2162 self._create_port_if_not_exist(task.node, node_properties['mac']) |
|
2163 LOG.info(_LI("Node %s inspected."), task.node.uuid) |
|
2164 return states.MANAGEABLE |
|
2165 |
|
2166 def _get_ipmi_properties(self, task): |
|
2167 """Retrieve IPMI_PROPERTIES from node |
|
2168 :param task: a TaskManager instance. |
|
2169 :returns: ipmitool retrieved property values |
|
2170 """ |
|
2171 fh = tempfile.NamedTemporaryFile() |
|
2172 for _none, prop in IPMI_PROPERTIES: |
|
2173 fh.write('sunoem getval %s\n' % prop) |
|
2174 fh.seek(0) |
|
2175 cmd = ["exec", fh.name] |
|
2176 driver_info = _parse_driver_info(task.node) |
|
2177 |
|
2178 try: |
|
2179 out, _err = _exec_ipmitool(driver_info, cmd) |
|
2180 except (exception.PasswordFileFailedToCreate, |
|
2181 processutils.ProcessExecutionError) as err: |
|
2182 LOG.warning(_LW('IPMI inspect properties failed for node %(node)s ' |
|
2183 'when executing "ipmitool %(cmd)s". ' |
|
2184 'Error: %(error)s'), |
|
2185 {'node': task.node.uuid, |
|
2186 'cmd': cmd, 'error': err}) |
|
2187 raise exception.IPMIFailure(cmd=cmd) |
|
2188 fh.close() |
|
2189 |
|
2190 return out |
|
2191 |
|
2192 def _get_cpu_cores(self, task, cpus): |
|
2193 """Retrieve IPMI_PROPERTIES from node |
|
2194 :param task: a TaskManager instance. |
|
2195 :param cpus: CPU numbers to use. |
|
2196 :returns: ipmitool retrieved property values |
|
2197 """ |
|
2198 fh = tempfile.NamedTemporaryFile() |
|
2199 for i in range(int(cpus)): |
|
2200 fh.write('sunoem getval %s\n' % (CPU_LOCATION % i)) |
|
2201 fh.seek(0) |
|
2202 cmd = ["exec", fh.name] |
|
2203 driver_info = _parse_driver_info(task.node) |
|
2204 |
|
2205 try: |
|
2206 out, _err = _exec_ipmitool(driver_info, cmd) |
|
2207 except (exception.PasswordFileFailedToCreate, |
|
2208 processutils.ProcessExecutionError) as err: |
|
2209 LOG.warning(_LW('IPMI CPU inspection failed for node %(node)s ' |
|
2210 'when executing "ipmitool %(cmd)s". ' |
|
2211 'Error: %(error)s'), |
|
2212 {'node': task.node.uuid, |
|
2213 'cmd': cmd, 'error': err}) |
|
2214 raise exception.IPMIFailure(cmd=cmd) |
|
2215 fh.close() |
|
2216 return out |
|
2217 |
|
2218 def _create_port_if_not_exist(self, node, mac): |
|
2219 """Create ironic port if not existing for this MAC |
|
2220 :param task: Node to creaate port for. |
|
2221 :param mac: MAC address to use for port. |
|
2222 """ |
|
2223 node_id = node.id |
|
2224 port_dict = {'address': mac, 'node_id': node_id} |
|
2225 mydbapi = dbapi.get_instance() |
|
2226 try: |
|
2227 mydbapi.create_port(port_dict) |
|
2228 LOG.info(_LI("Port created for MAC address %(mac)s for node " |
|
2229 "%(node)s."), {'mac': mac, 'node': node.uuid}) |
|
2230 except exception.MACAlreadyExists: |
|
2231 LOG.warn(_LW("Port already exists for MAC address %(mac)s " |
|
2232 "for node %(node)s."), |
|
2233 {'mac': mac, 'node': node.uuid}) |
2009 |
2234 |
2010 |
2235 |
2011 class AIService(): |
2236 class AIService(): |
2012 """AI Service""" |
2237 """AI Service""" |
2013 |
2238 |
2137 self._profiles = [] |
2362 self._profiles = [] |
2138 |
2363 |
2139 except Exception as _err: |
2364 except Exception as _err: |
2140 self.delete_remote_file(remote_iso) |
2365 self.delete_remote_file(remote_iso) |
2141 if PLATFORM == "SunOS": |
2366 if PLATFORM == "SunOS": |
2142 _umount_archive(mount_dir, temp_uar) |
2367 _umount_archive(mount_dir) |
2143 else: |
2368 else: |
2144 _image_refcount_adjust(temp_uar, -1) |
2369 _image_refcount_adjust(temp_uar, -1) |
2145 raise AICreateServiceFail( |
2370 raise AICreateServiceFail( |
2146 _("Failed to create AI Service %s") % (uuid)) |
2371 _("Failed to create AI Service %s") % (uuid)) |
2147 |
2372 |
2148 # 4. Remove copy of AI ISO on AI Server |
2373 # 4. Remove copy of AI ISO on AI Server |
2149 self.delete_remote_file(remote_iso) |
2374 self.delete_remote_file(remote_iso) |
2150 |
2375 |
2151 if PLATFORM == "SunOS": |
2376 if PLATFORM == "SunOS": |
2152 # 5. Unmount UAR |
2377 # 5. Unmount UAR |
2153 _umount_archive(mount_dir, temp_uar) |
2378 _umount_archive(mount_dir) |
2154 |
2379 |
2155 # 6. Decrement reference count for image |
2380 # 6. Decrement reference count for image |
2156 if temp_uar is not None: |
2381 if temp_uar is not None: |
2157 _image_refcount_adjust(temp_uar, -1) |
2382 _image_refcount_adjust(temp_uar, -1) |
2158 |
2383 |
2166 _stdout, _rc = _ssh_execute(self.ssh_obj, ai_cmd) |
2391 _stdout, _rc = _ssh_execute(self.ssh_obj, ai_cmd) |
2167 except Exception as _err: |
2392 except Exception as _err: |
2168 raise AIDeleteServiceFail( |
2393 raise AIDeleteServiceFail( |
2169 _("Failed to delete AI Service %s") % (self.name)) |
2394 _("Failed to delete AI Service %s") % (self.name)) |
2170 |
2395 |
2171 def create_client(self, mac, arch, archive_uri, auth_token, |
2396 def create_client(self, mac, cpu_arch, archive_uri, auth_token, |
2172 publishers, fmri): |
2397 publishers, fmri): |
2173 """Create a client associated with this service |
2398 """Create a client associated with this service |
2174 |
2399 |
2175 :param mac: MAC Address of client to create |
2400 :param mac: MAC Address of client to create |
2176 :param arch: Machine architecture for this node |
2401 :param cpu_arch: Machine architecture for this node |
2177 :param archive_uri: URI of archive to install node from |
2402 :param archive_uri: URI of archive to install node from |
2178 :param auth_token: Authorization token for glance UAR retrieval |
2403 :param auth_token: Authorization token for glance UAR retrieval |
2179 :param publishers: IPS publishers list in name@origin format |
2404 :param publishers: IPS publishers list in name@origin format |
2180 :param fmri: IPS package FMRIs to install |
2405 :param fmri: IPS package FMRIs to install |
2181 :returns: Nothing exception raised if deletion fails |
2406 :returns: Nothing exception raised if deletion fails |