components/openstack/ironic/files/drivers/modules/solaris_ipmitool.py
branchs11u3-sru
changeset 6035 c9748fcc32de
parent 4508 d8924d870370
equal deleted inserted replaced
6016:a477397bba8b 6035:c9748fcc32de
     3 # Copyright 2012 Hewlett-Packard Development Company, L.P.
     3 # Copyright 2012 Hewlett-Packard Development Company, L.P.
     4 # Copyright (c) 2012 NTT DOCOMO, INC.
     4 # Copyright (c) 2012 NTT DOCOMO, INC.
     5 # Copyright 2014 International Business Machines Corporation
     5 # Copyright 2014 International Business Machines Corporation
     6 # All Rights Reserved.
     6 # All Rights Reserved.
     7 #
     7 #
     8 # Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
     8 # Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
     9 #
     9 #
    10 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    10 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    11 #    not use this file except in compliance with the License. You may obtain
    11 #    not use this file except in compliance with the License. You may obtain
    12 #    a copy of the License at
    12 #    a copy of the License at
    13 #
    13 #
    20 #    under the License.
    20 #    under the License.
    21 """
    21 """
    22 Solaris Driver and supporting meta-classes.
    22 Solaris Driver and supporting meta-classes.
    23 """
    23 """
    24 
    24 
       
    25 import errno
    25 import os
    26 import os
    26 import platform
    27 import platform
    27 import re
    28 import re
    28 import select
    29 import select
    29 import shutil
    30 import shutil
    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:
    59     from pkg.misc import valid_pub_prefix, valid_pub_url
    62     from pkg.misc import valid_pub_prefix, valid_pub_url
    60 
    63 
    61 
    64 
    62 AI_OPTS = [
    65 AI_OPTS = [
    63     cfg.StrOpt('server',
    66     cfg.StrOpt('server',
    64                default='None',
       
    65                help='Host name for AI Server.'),
    67                help='Host name for AI Server.'),
    66     cfg.StrOpt('username',
    68     cfg.StrOpt('username',
    67                default='None',
       
    68                help='Username to ssh to AI Server.'),
    69                help='Username to ssh to AI Server.'),
    69     cfg.StrOpt('password',
    70     cfg.StrOpt('password',
    70                default='None',
    71                help='Password for user to ssh to AI Server. If ssh_key_file '
    71                help='Password for user to ssh to AI Server.'),
    72                     'or ssh_key_contents are set, this config setting is used '
       
    73                     'to provide the passphrase if required. If an encrypted '
       
    74                     'key is used, set this to the passphrase.'),
    72     cfg.StrOpt('port',
    75     cfg.StrOpt('port',
    73                default='22',
    76                default='22',
    74                help='SSH port to use.'),
    77                help='SSH port to use.'),
    75     cfg.StrOpt('timeout',
    78     cfg.StrOpt('timeout',
    76                default='10',
    79                default='10',
    80                help='Interval in seconds to check AI deployment status.'),
    83                help='Interval in seconds to check AI deployment status.'),
    81     cfg.StrOpt('derived_manifest',
    84     cfg.StrOpt('derived_manifest',
    82                default='file:///usr/lib/ironic/ironic-manifest.ksh',
    85                default='file:///usr/lib/ironic/ironic-manifest.ksh',
    83                help='Derived Manifest used for deployment.'),
    86                help='Derived Manifest used for deployment.'),
    84     cfg.StrOpt('ssh_key_file',
    87     cfg.StrOpt('ssh_key_file',
    85                default='None',
       
    86                help='SSH Filename to use.'),
    88                help='SSH Filename to use.'),
    87     cfg.StrOpt('ssh_key_contents',
    89     cfg.StrOpt('ssh_key_contents',
    88                default='None',
       
    89                help='Actual SSH Key contents to use.')
    90                help='Actual SSH Key contents to use.')
    90     ]
    91     ]
    91 
    92 
    92 AUTH_OPTS = [
    93 AUTH_OPTS = [
    93     cfg.StrOpt('auth_strategy',
    94     cfg.StrOpt('auth_strategy',
   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 
   187     :raises: SSHCommandFailed on an error from ssh, if specified to raise.
   202     :raises: SSHCommandFailed on an error from ssh, if specified to raise.
   188     """
   203     """
   189     LOG.debug("_ssh_execute():ssh_cmd: %s" % (ssh_cmd))
   204     LOG.debug("_ssh_execute():ssh_cmd: %s" % (ssh_cmd))
   190 
   205 
   191     returncode = 0
   206     returncode = 0
       
   207     stdout = None
   192     try:
   208     try:
   193         stdout = processutils.ssh_execute(ssh_obj, ssh_cmd)[0]
   209         stdout = processutils.ssh_execute(ssh_obj, ssh_cmd)[0]
   194     except Exception as err:
   210     except Exception as err:
   195         LOG.debug(_("Cannot execute SSH cmd %(cmd)s. Reason: %(err)s.") %
   211         LOG.debug(_("Cannot execute SSH cmd %(cmd)s. Reason: %(err)s.") %
   196                   {'cmd': ssh_cmd, 'err': err})
   212                   {'cmd': ssh_cmd, 'err': err})
   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 
   486         LOG.debug("_check_deploy_state().deploying: %s" %
   555         LOG.debug("_check_deploy_state().deploying: %s" %
   487                   (deploy_thread.state))
   556                   (deploy_thread.state))
   488         cur_node.provision_state = states.DEPLOYING
   557         cur_node.provision_state = states.DEPLOYING
   489         cur_node.save()
   558         cur_node.save()
   490 
   559 
   491     elif cur_node.target_provision_state == states.NOSTATE:
   560     elif cur_node.target_provision_state == states.AVAILABLE or \
       
   561             cur_node.target_provision_state == states.NOSTATE:
   492         # Node was most likely deleted so end deployment completion checking
   562         # Node was most likely deleted so end deployment completion checking
   493         LOG.debug("_check_deploy_state().deleted: %s" %
   563         LOG.debug("_check_deploy_state().deleted: %s" %
   494                   (cur_node.target_provision_state))
   564                   (cur_node.target_provision_state))
       
   565         deploy_thread.stop()
       
   566         raise loopingcall.LoopingCallDone()
       
   567 
       
   568     elif cur_node.provision_state == states.DEPLOYFAIL:
       
   569         # Node deployment as for some reason failed already, exist thread
       
   570         LOG.debug("_check_deploy_state().deploy_failed: %s" %
       
   571                   (cur_node.provision_state))
   495         deploy_thread.stop()
   572         deploy_thread.stop()
   496         raise loopingcall.LoopingCallDone()
   573         raise loopingcall.LoopingCallDone()
   497 
   574 
   498 
   575 
   499 def _url_exists(url):
   576 def _url_exists(url):
   594 
   671 
   595         # Check if reference count is zero if so remove
   672         # Check if reference count is zero if so remove
   596         # refcount file and image file
   673         # refcount file and image file
   597         if int(ref_count) <= 0:
   674         if int(ref_count) <= 0:
   598             lock.release()
   675             lock.release()
   599             os.remove(ref_filename)
   676             try:
   600             os.remove(image_path)
   677                 os.remove(ref_filename)
       
   678             except OSError as err:
       
   679                 if err.errno != errno.ENOENT:
       
   680                     raise
       
   681             try:
       
   682                 os.remove(image_path)
       
   683             except OSError as err:
       
   684                 if err.errno != errno.ENOENT:
       
   685                     raise
       
   686 
   601         else:
   687         else:
   602             fp.seek(0)
   688             fp.seek(0)
   603             fp.write(ref_count)
   689             fp.write(ref_count)
   604             if release:
   690             if release:
   605                 lock.release()
   691                 lock.release()
   668                         cmd = ["/usr/bin/curl", "-sS", "-o", temp_uri, uri]
   754                         cmd = ["/usr/bin/curl", "-sS", "-o", temp_uri, uri]
   669                         pc = Popen(cmd, stdout=PIPE, stderr=PIPE)
   755                         pc = Popen(cmd, stdout=PIPE, stderr=PIPE)
   670                         _stdout, err = pc.communicate()
   756                         _stdout, err = pc.communicate()
   671                         if pc.returncode != 0:
   757                         if pc.returncode != 0:
   672                             err_msg = _("Failed to retrieve image: %s") % err
   758                             err_msg = _("Failed to retrieve image: %s") % err
       
   759                             _image_refcount_adjust(temp_uri, -1)
   673                             raise SolarisIPMIError(msg=err_msg)
   760                             raise SolarisIPMIError(msg=err_msg)
   674 
   761 
   675                         # Release acquired lock now that file is retrieved
   762                         # Release acquired lock now that file is retrieved
   676                         lock.release()
   763                         lock.release()
   677 
   764 
   687         # as noted above Caller is responsible for its removal
   774         # as noted above Caller is responsible for its removal
   688         LOG.error(_("Unable to fetch image: uri %s: %s") % (uri, err))
   775         LOG.error(_("Unable to fetch image: uri %s: %s") % (uri, err))
   689         if url.scheme == "glance":
   776         if url.scheme == "glance":
   690             _image_refcount_adjust(temp_uri, -1)
   777             _image_refcount_adjust(temp_uri, -1)
   691         else:
   778         else:
   692             os.remove(temp_uri)
   779             try:
       
   780                 os.remove(temp_uri)
       
   781             except OSError as err:
       
   782                 if err.errno != errno.ENOENT:
       
   783                     raise
   693         raise
   784         raise
   694 
   785 
   695     return temp_uri
   786     return temp_uri
   696 
   787 
   697 
   788 
   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:
   822     if PLATFORM == "SunOS":
   912     if PLATFORM == "SunOS":
   823         mount_dir, temp_uar = _mount_archive(task, archive_uri)
   913         mount_dir, temp_uar = _mount_archive(task, archive_uri)
   824         try:
   914         try:
   825             _iso, uuid = _get_archive_iso_and_uuid(mount_dir)
   915             _iso, uuid = _get_archive_iso_and_uuid(mount_dir)
   826         except:
   916         except:
   827             _umount_archive(mount_dir, temp_uar)
   917             _umount_archive(mount_dir)
   828             raise
   918             raise
   829         _umount_archive(mount_dir, temp_uar)
   919         _umount_archive(mount_dir)
   830     else:
   920     else:
   831         temp_uar = _fetch_uri(task, archive_uri)
   921         temp_uar = _fetch_uri(task, archive_uri)
   832         try:
   922         try:
   833             _iso, uuid = _get_archive_iso_and_uuid(temp_uar)
   923             _iso, uuid = _get_archive_iso_and_uuid(temp_uar)
   834         except:
   924         except:
  1335         LOG.debug("SolarisDeploy.validate()")
  1425         LOG.debug("SolarisDeploy.validate()")
  1336         LOG.debug(task.context.auth_token)
  1426         LOG.debug(task.context.auth_token)
  1337 
  1427 
  1338         # Validate IPMI credentials by getting node architecture
  1428         # Validate IPMI credentials by getting node architecture
  1339         try:
  1429         try:
  1340             _arch = _get_node_architecture(task.node)
  1430             _cpu_arch = _get_node_architecture(task.node)
  1341         except Exception as err:
  1431         except Exception as err:
  1342             raise exception.InvalidParameterValue(_(err))
  1432             raise exception.InvalidParameterValue(_(err))
  1343 
  1433 
  1344         if not driver_utils.get_node_mac_addresses(task):
  1434         if not driver_utils.get_node_mac_addresses(task):
  1345             raise exception.InvalidParameterValue(
  1435             raise exception.InvalidParameterValue(
  1423             _validate_ai_manifest(task)
  1513             _validate_ai_manifest(task)
  1424 
  1514 
  1425         # Try to get the URL of the Ironic API
  1515         # Try to get the URL of the Ironic API
  1426         try:
  1516         try:
  1427             CONF.conductor.api_url or keystone.get_service_url()
  1517             CONF.conductor.api_url or keystone.get_service_url()
  1428         except (exception.CatalogFailure,
  1518         except (exception.KeystoneFailure,
  1429                 exception.CatalogNotFound,
  1519                 exception.KeystoneUnauthorized,
  1430                 exception.CatalogUnauthorized):
  1520                 exception.CatalogNotFound):
  1431             raise exception.InvalidParameterValue(_(
  1521             raise exception.InvalidParameterValue(_(
  1432                 "Couldn't get the URL of the Ironic API service from the "
  1522                 "Couldn't get the URL of the Ironic API service from the "
  1433                 "configuration file or Keystone catalog."))
  1523                 "configuration file or Keystone catalog."))
  1434 
  1524 
  1435         # Validate driver_info by parsing contents
  1525         # Validate driver_info by parsing contents
  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
  1616                 # Client exists remove it
  1706                 # Client exists remove it
  1617                 aiservice.delete_client(mac)
  1707                 aiservice.delete_client(mac)
  1618 
  1708 
  1619             # Recreate new ai client for this mac address
  1709             # Recreate new ai client for this mac address
  1620             new_uri, auth_token = _format_archive_uri(task, archive_uri)
  1710             new_uri, auth_token = _format_archive_uri(task, archive_uri)
  1621             aiservice.create_client(mac, arch, new_uri, auth_token,
  1711             aiservice.create_client(mac, cpu_arch, new_uri, auth_token,
  1622                                     publishers, fmri)
  1712                                     publishers, fmri)
  1623 
  1713 
  1624             # 3. (Re)Create AI Manifest for each port/Mac specified for this
  1714             # 3. (Re)Create AI Manifest for each port/Mac specified for this
  1625             #    Node. Manifest name will be MAC address stripped of colons
  1715             #    Node. Manifest name will be MAC address stripped of colons
  1626             manifest_name = mac.replace(':', '')
  1716             manifest_name = mac.replace(':', '')
  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:
  1956                             'Error: %(error)s'),
  2046                             'Error: %(error)s'),
  1957                         {'node': driver_info['uuid'],
  2047                         {'node': driver_info['uuid'],
  1958                          'cmd': cmd, 'error': err})
  2048                          'cmd': cmd, 'error': err})
  1959             raise exception.IPMIFailure(cmd=cmd)
  2049             raise exception.IPMIFailure(cmd=cmd)
  1960 
  2050 
  1961         if arch == 'x86':
  2051         if cpu_arch == 'x86':
  1962             re_obj = re.search('Boot Device Selector : (.+)?\n', out)
  2052             re_obj = re.search('Boot Device Selector : (.+)?\n', out)
  1963             if re_obj:
  2053             if re_obj:
  1964                 boot_selector = re_obj.groups('')[0]
  2054                 boot_selector = re_obj.groups('')[0]
  1965                 if 'PXE' in boot_selector:
  2055                 if 'PXE' in boot_selector:
  1966                     response['boot_device'] = boot_devices.PXE
  2056                     response['boot_device'] = boot_devices.PXE
  1973                     response['boot_device'] = boot_devices.BIOS
  2063                     response['boot_device'] = boot_devices.BIOS
  1974                 elif 'CD/DVD' in boot_selector:
  2064                 elif 'CD/DVD' in boot_selector:
  1975                     response['boot_device'] = boot_devices.CDROM
  2065                     response['boot_device'] = boot_devices.CDROM
  1976 
  2066 
  1977             response['persistent'] = 'Options apply to all future boots' in out
  2067             response['persistent'] = 'Options apply to all future boots' in out
  1978         elif arch == 'SPARC':
  2068         elif cpu_arch == 'SPARC':
  1979             if "net:dhcp" in out:
  2069             if "net:dhcp" in out:
  1980                 response['boot_device'] = 'wanboot'
  2070                 response['boot_device'] = 'wanboot'
  1981             else:
  2071             else:
  1982                 response['boot_device'] = 'disk'
  2072                 response['boot_device'] = boot_devices.DISK
  1983         LOG.debug(response)
  2073         LOG.debug(response)
  1984         return response
  2074         return response
  1985 
  2075 
  1986     def get_sensors_data(self, task):
  2076     def get_sensors_data(self, task):
  1987         """Get sensors data.
  2077         """Get sensors data.
  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 
  2111         remote_iso = os.path.join("/tmp", uuid) + ".iso"
  2336         remote_iso = os.path.join("/tmp", uuid) + ".iso"
  2112         try:
  2337         try:
  2113             self.copy_remote_file(iso, remote_iso)
  2338             self.copy_remote_file(iso, remote_iso)
  2114         except:
  2339         except:
  2115             if PLATFORM == "SunOS":
  2340             if PLATFORM == "SunOS":
  2116                 _umount_archive(mount_dir, temp_uar)
  2341                 _umount_archive(mount_dir)
  2117                 if urlparse(archive_uri).scheme == "glance":
  2342                 if urlparse(archive_uri).scheme == "glance":
  2118                     _image_refcount_adjust(temp_uar, -1)
  2343                     _image_refcount_adjust(temp_uar, -1)
  2119             else:
  2344             else:
  2120                 shutil.rmtree(os.path.dirname(iso))
  2345                 shutil.rmtree(os.path.dirname(iso))
  2121                 _image_refcount_adjust(temp_uar, -1)
  2346                 _image_refcount_adjust(temp_uar, -1)
  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
  2183         LOG.debug("AIService.create_client():mac: %s" % (mac))
  2408         LOG.debug("AIService.create_client():mac: %s" % (mac))
  2184         ai_cmd = "/usr/bin/pfexec /usr/sbin/installadm create-client -e " + \
  2409         ai_cmd = "/usr/bin/pfexec /usr/sbin/installadm create-client -e " + \
  2185             mac + " -n " + self.name
  2410             mac + " -n " + self.name
  2186 
  2411 
  2187         # Add specific boot arguments for 'x86' clients only
  2412         # Add specific boot arguments for 'x86' clients only
  2188         if arch == 'x86':
  2413         if cpu_arch == 'x86':
  2189             ai_cmd += " -b install=true,console=ttya"
  2414             ai_cmd += " -b install=true,console=ttya"
  2190 
  2415 
  2191             if archive_uri:
  2416             if archive_uri:
  2192                 ai_cmd += ",archive_uri=%s" % (archive_uri)
  2417                 ai_cmd += ",archive_uri=%s" % (archive_uri)
  2193 
  2418 
  2208             _stdout, _rc = _ssh_execute(self.ssh_obj, ai_cmd)
  2433             _stdout, _rc = _ssh_execute(self.ssh_obj, ai_cmd)
  2209         except Exception as _err:
  2434         except Exception as _err:
  2210             raise AICreateClientFail(_("Failed to create AI Client %s") %
  2435             raise AICreateClientFail(_("Failed to create AI Client %s") %
  2211                                      (mac))
  2436                                      (mac))
  2212 
  2437 
  2213         # If arch x86 customize grub reducing grub menu timeout to 0
  2438         # If cpu_arch x86 customize grub reducing grub menu timeout to 0
  2214         if arch == 'x86':
  2439         if cpu_arch == 'x86':
  2215             custom_grub = "/tmp/%s.grub" % (mac)
  2440             custom_grub = "/tmp/%s.grub" % (mac)
  2216             ai_cmd = "/usr/bin/pfexec /usr/sbin/installadm export -e " + \
  2441             ai_cmd = "/usr/bin/pfexec /usr/sbin/installadm export -e " + \
  2217                 mac + " -G | /usr/bin/sed -e 's/timeout=30/timeout=0/'" + \
  2442                 mac + " -G | /usr/bin/sed -e 's/timeout=30/timeout=0/'" + \
  2218                 " > %s" % (custom_grub)
  2443                 " > %s" % (custom_grub)
  2219             try:
  2444             try:
  2440         """Generate SSH Dictionary for SSH Connection via paramiko
  2665         """Generate SSH Dictionary for SSH Connection via paramiko
  2441 
  2666 
  2442         :returns: dictionary for paramiko connection
  2667         :returns: dictionary for paramiko connection
  2443         """
  2668         """
  2444         LOG.debug("AIService._get_ssh_dict()")
  2669         LOG.debug("AIService._get_ssh_dict()")
  2445         if not CONF.ai.server or not CONF.ai.username:
  2670         if not CONF.ai.server or CONF.ai.server == "None" or \
       
  2671                 not CONF.ai.username or CONF.ai.username == "None":
  2446             raise exception.InvalidParameterValue(_(
  2672             raise exception.InvalidParameterValue(_(
  2447                 "SSH server and username must be set."))
  2673                 "SSH server and username must be set."))
  2448 
  2674 
  2449         ssh_dict = {
  2675         ssh_dict = {
  2450             'host': CONF.ai.server,
  2676             'host': CONF.ai.server,
  2530         lines = list_out.splitlines()
  2756         lines = list_out.splitlines()
  2531 
  2757 
  2532         # Get index into string for client/manifest/profile names
  2758         # Get index into string for client/manifest/profile names
  2533         # client/manifest/profile names are all in 2nd column of output
  2759         # client/manifest/profile names are all in 2nd column of output
  2534         if len(lines) > 1:
  2760         if len(lines) > 1:
  2535             col_start = lines[1].index(" --")
  2761             col_start = lines[1].index(" --") + 1
       
  2762             col_end = lines[1][col_start:].index(" --") + 1 + col_start
  2536 
  2763 
  2537             for line in range(2, len(lines)):
  2764             for line in range(2, len(lines)):
  2538                 names.append(lines[line][col_start:].split()[0])
  2765                 if lines[line][col_start:col_end].strip():
       
  2766                     names.append(lines[line][col_start:col_end].strip())
  2539 
  2767 
  2540         LOG.debug("AIService._parse_names():names: %s" % (names))
  2768         LOG.debug("AIService._parse_names():names: %s" % (names))
  2541         return names
  2769         return names
  2542 
  2770 
  2543 
  2771