Example #1
0
    def getStatus(self, session, **kwargs):
        '''
        Call the addHost manager directly
        '''

        startMessage = int(kwargs['startMessage']) \
            if 'startMessage' in kwargs else 0

        getNodes = kwargs['getNodes'].lower().startswith('t') \
            if 'getNodes' in kwargs else False

        try:
            status = AddHostManager().getStatus(cherrypy.request.db, session,
                                                int(startMessage), getNodes)

            response = {'addhoststatus': status.getCleanDict()}
        except NotFound as ex:
            self.handleException(ex)
            code = self.getTortugaStatusCode(ex)
            response = self.notFoundErrorResponse(str(ex), code)
        except Exception as ex:  # pylint: disable=broad-except
            self._logger.error('Exception retrieving addhost status')
            self.handleException(ex)
            response = self.errorResponse(str(ex))

        return self.formatResponse(response)
Example #2
0
    def __init__(self):
        super(NodeManager, self).__init__()

        self._nodeDbApi = NodeDbApi()
        self._cm = ConfigManager()
        self._bhm = osUtility.getOsObjectFactory().getOsBootHostManager(
            self._cm)
        self._nodesDbHandler = NodesDbHandler()
        self._addHostManager = AddHostManager()
        self._logger = logging.getLogger(NODE_NAMESPACE)
Example #3
0
class AddHostSessionContextManager(object):
    def __init__(self, addHostSession):
        self.addHostSession = addHostSession
        self.ahm = None

    def __enter__(self):
        self.ahm = AddHostManager()

        self.ahm.update_session(self.addHostSession, running=True)

        return self.ahm

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.ahm.update_session(self.addHostSession, running=False)
Example #4
0
def init_node_request_record(nodespec):
    request = NodeRequests(nodespec)
    request.timestamp = datetime.datetime.utcnow()
    request.addHostSession = AddHostManager().createNewSession()
    request.action = 'DELETE'

    return request
Example #5
0
    def __process_activateNode_results(self, tmp_results, dstswprofilename):
        results = {}

        for key, values in tmp_results.items():
            # With the exception of the "ProfileMappingNotAllowed" dict
            # item, all items in the dict are lists of nodes.
            if key != 'ProfileMappingNotAllowed':
                results[key] = [dbNode.name for dbNode in values]
            else:
                results[key] = \
                    [(value[0].name, value[1], value[2])
                     for value in values]

        if tmp_results['success']:
            # Iterate over activated nodes, creating dict keyed on
            # 'addHostSession'
            addHostSessions = {}

            for node in tmp_results['success']:
                if node.addHostSession not in addHostSessions:
                    addHostSessions[node.addHostSession] = []

                addHostSessions[node.addHostSession] = \
                    node.hardwareprofile.name

            # For each 'addHostSession', call postAddHost()
            for addHostSession, hwprofile in addHostSessions.items():
                AddHostManager().postAddHost(hwprofile, dstswprofilename,
                                             addHostSession)

        return results
Example #6
0
 def statusMessage(self, msg: str) -> None:
     if self._addHostSession:
         AddHostManager().updateStatus(self._addHostSession, msg)
     else:
         # Just print out the message...this is a stop gap for resource
         # adapters running outside of the addHostManager framework
         sys.stdout.write(msg + '\n')
         sys.stdout.flush()
Example #7
0
def init_node_request_record(addNodesRequest):
    request = NodeRequests(json.dumps(addNodesRequest['addNodesRequest']))
    request.timestamp = datetime.datetime.utcnow()
    request.addHostSession = AddHostManager().createNewSession()
    request.action = 'ADD'

    if 'metadata' in addNodesRequest and \
            'admin_id' in addNodesRequest['metadata']:
        request.admin_id = addNodesRequest['metadata']['admin_id']

    return request
Example #8
0
def init_async_node_request(action: str,
                            data: Any,
                            *,
                            admin_id: Optional[int] = None):
    """
    Serialize async node request to NodeRequest (db) object
    """

    request = NodeRequest(
        request=json.dumps(data),
        timestamp=datetime.datetime.utcnow(),
        action=action,
        addHostSession=AddHostManager().createNewSession(),
        admin_id=admin_id,
    )

    return request
Example #9
0
import datetime
import logging

from sqlalchemy.orm.session import Session
from tortuga.addhost.addHostManager import AddHostManager
from tortuga.db.nodeRequestsDbHandler import NodeRequestsDbHandler
from tortuga.events.types import DeleteNodeRequestComplete
from tortuga.exceptions.nodeNotFound import NodeNotFound
from tortuga.exceptions.operationFailed import OperationFailed
from tortuga.exceptions.tortugaException import TortugaException
from tortuga.node.nodeApi import NodeApi

logger = logging.getLogger(__name__)

ahm = AddHostManager()


def process_delete_host_request(session: Session,
                                transaction_id: str,
                                nodespec: str,
                                force: bool = False):
    try:
        req = NodeRequestsDbHandler().get_by_addHostSession(
            session, transaction_id)
        if req is None:
            # Session was deleted prior to being processed. Nothing to do...

            logger.warning(
                'Delete host request [%s] not found; nothing to do...',
                transaction_id)
Example #10
0
class NodeManager(TortugaObjectManager):     \
        # pylint: disable=too-many-public-methods

    def __init__(self):
        super(NodeManager, self).__init__()

        self._nodeDbApi = NodeDbApi()
        self._cm = ConfigManager()
        self._bhm = osUtility.getOsObjectFactory().getOsBootHostManager(
            self._cm)
        self._syncApi = SyncApi()
        self._nodesDbHandler = NodesDbHandler()
        self._addHostManager = AddHostManager()
        self._logger = logging.getLogger(NODE_NAMESPACE)

    def __validateHostName(self, hostname: str, name_format: str) -> None:
        """
        Raises:
            ConfigurationError
        """

        bWildcardNameFormat = (name_format == '*')

        if hostname and not bWildcardNameFormat:
            # Host name specified, but hardware profile does not
            # allow setting the host name
            raise ConfigurationError(
                'Hardware profile does not allow setting host names'
                ' of imported nodes')
        elif not hostname and bWildcardNameFormat:
            # Host name not specified but hardware profile expects it
            raise ConfigurationError(
                'Hardware profile requires host names to be set')

    def createNewNode(self,
                      session: Session,
                      addNodeRequest: dict,
                      dbHardwareProfile: HardwareProfileModel,
                      dbSoftwareProfile: Optional[SoftwareProfileModel] = None,
                      validateIp: bool = True,
                      bGenerateIp: bool = True,
                      dns_zone: Optional[str] = None) -> NodeModel:
        """
        Convert the addNodeRequest into a Nodes object

        Raises:
            NicNotFound
        """

        self._logger.debug(
            'createNewNode(): session=[%s], addNodeRequest=[%s],'
            ' dbHardwareProfile=[%s], dbSoftwareProfile=[%s],'
            ' validateIp=[%s], bGenerateIp=[%s]' %
            (id(session), addNodeRequest, dbHardwareProfile.name,
             dbSoftwareProfile.name if dbSoftwareProfile else '(none)',
             validateIp, bGenerateIp))

        hostname = addNodeRequest['name'] \
            if 'name' in addNodeRequest else None

        # Ensure no conflicting options (ie. specifying host name for
        # hardware profile in which host names are generated)
        self.__validateHostName(hostname, dbHardwareProfile.nameFormat)

        node = NodeModel(name=hostname)

        if 'rack' in addNodeRequest:
            node.rack = addNodeRequest['rack']

        node.addHostSession = addNodeRequest['addHostSession']

        # Complete initialization of new node record
        nic_defs = addNodeRequest['nics'] \
            if 'nics' in addNodeRequest else []

        AddHostServerLocal().initializeNode(session,
                                            node,
                                            dbHardwareProfile,
                                            dbSoftwareProfile,
                                            nic_defs,
                                            bValidateIp=validateIp,
                                            bGenerateIp=bGenerateIp,
                                            dns_zone=dns_zone)

        # Set hardware profile of new node
        node.hardwareprofile = dbHardwareProfile

        node.softwareprofile = dbSoftwareProfile

        # Return the new node
        return node

    def getNode(self, session: Session, name, optionDict: OptionDict = None) \
            -> Node:
        """
        Get node by name

        Raises:
            NodeNotFound
        """

        return self.__populate_nodes(session, [
            self._nodeDbApi.getNode(
                session, name, optionDict=get_default_relations(optionDict))
        ])[0]

    def getNodeById(self,
                    session: Session,
                    nodeId: int,
                    optionDict: OptionDict = None) -> Node:
        """
        Get node by node id

        Raises:
            NodeNotFound
        """

        return self.__populate_nodes(session, [
            self._nodeDbApi.getNodeById(
                session,
                int(nodeId),
                optionDict=get_default_relations(optionDict))
        ])[0]

    def getNodeByIp(self,
                    session: Session,
                    ip: str,
                    optionDict: Dict[str, bool] = None) -> Node:
        """
        Get node by IP address

        Raises:
            NodeNotFound
        """

        return self.__populate_nodes(session, [
            self._nodeDbApi.getNodeByIp(
                session, ip, optionDict=get_default_relations(optionDict))
        ])[0]

    def getNodeList(self,
                    session,
                    tags=None,
                    optionDict: Optional[OptionDict] = None) -> List[Node]:
        """
        Return all nodes

        """
        return self.__populate_nodes(
            session,
            self._nodeDbApi.getNodeList(
                session,
                tags=tags,
                optionDict=get_default_relations(optionDict)))

    def __populate_nodes(self, session: Session,
                         nodes: List[Node]) -> List[Node]:
        """
        Expand non-database fields in Node objects

        """
        class SoftwareProfileMetadataCache(defaultdict):
            def __missing__(self, key):
                metadata = \
                    SoftwareProfileManager().get_software_profile_metadata(
                        session, key
                    )

                self[key] = metadata

                return metadata

        swprofile_map = SoftwareProfileMetadataCache()

        for node in nodes:
            if not node.getSoftwareProfile():
                continue

            node.getSoftwareProfile().setMetadata(
                swprofile_map[node.getSoftwareProfile().getName()])

        return nodes

    def updateNode(self, session: Session, nodeName: str,
                   updateNodeRequest: dict) -> None:
        """
        Calls updateNode() method of resource adapter
        """

        self._logger.debug('updateNode(): name=[{0}]'.format(nodeName))

        try:
            node = self._nodesDbHandler.getNode(session, nodeName)

            if 'nics' in updateNodeRequest:
                nic = updateNodeRequest['nics'][0]

                if 'ip' in nic:
                    node.nics[0].ip = nic['ip']
                    node.nics[0].boot = True

            # Call resource adapter
            # self._nodesDbHandler.updateNode(session, node, updateNodeRequest)

            adapter = self.__getResourceAdapter(node.hardwareprofile)

            adapter.updateNode(session, node, updateNodeRequest)

            run_post_install = False

            #
            # Capture previous state and node data as dict for firing the
            # event later on
            #
            previous_state = node.state
            node_dict = Node.getFromDbDict(node.__dict__).getCleanDict()

            if 'state' in updateNodeRequest:
                run_post_install = \
                    node.state == state.NODE_STATE_ALLOCATED and \
                    updateNodeRequest['state'] == state.NODE_STATE_PROVISIONED

                node.state = updateNodeRequest['state']
                node_dict['state'] = updateNodeRequest['state']

            session.commit()

            #
            # If the node state has changed, then fire the node state changed
            # event
            #
            if node_dict['state'] != previous_state:
                NodeStateChanged.fire(node=node_dict,
                                      previous_state=previous_state)

            if run_post_install:
                self._logger.debug(
                    'updateNode(): run-post-install for node [{0}]'.format(
                        node.name))

                self.__scheduleUpdate()
        except Exception:
            session.rollback()

            raise

    def updateNodeStatus(self,
                         session: Session,
                         nodeName: str,
                         node_state: Optional[str] = None,
                         bootFrom: int = None):
        """Update node status

        If neither 'state' nor 'bootFrom' are not None, this operation will
        update only the 'lastUpdated' timestamp.

        Returns:
            bool indicating whether state and/or bootFrom differed from
            current value
        """

        value = 'None' if bootFrom is None else \
            '1 (disk)' if int(bootFrom) == 1 else '0 (network)'

        self._logger.debug(
            'updateNodeStatus(): node=[%s], node_state=[{%s}],'
            ' bootFrom=[{%s}]', nodeName, node_state, value)

        dbNode = self._nodesDbHandler.getNode(session, nodeName)

        #
        # Capture previous state and node data in dict form for the
        # event later on
        #
        previous_state = dbNode.state
        node_dict = Node.getFromDbDict(dbNode.__dict__).getCleanDict()

        # Bitfield representing node changes (0 = state change,
        # 1 = bootFrom # change)
        changed = 0

        if node_state is not None and node_state != dbNode.state:
            # 'state' changed
            changed |= 1

        if bootFrom is not None and bootFrom != dbNode.bootFrom:
            # 'bootFrom' changed
            changed |= 2

        if changed:
            # Create custom log message
            msg = 'Node [%s] state change:' % (dbNode.name)

            if changed & 1:
                msg += ' state: [%s] -> [%s]' % (dbNode.state, node_state)

                dbNode.state = node_state
                node_dict['state'] = node_state

            if changed & 2:
                msg += ' bootFrom: [%d] -> [%d]' % (dbNode.bootFrom, bootFrom)

                dbNode.bootFrom = bootFrom

            self._logger.info(msg)
        else:
            self._logger.info('Updated timestamp for node [%s]' %
                              (dbNode.name))

        dbNode.lastUpdate = time.strftime('%Y-%m-%d %H:%M:%S',
                                          time.localtime(time.time()))

        result = bool(changed)

        # Only change local boot configuration if the hardware profile is
        # not marked as 'remote' and we're not acting on the installer
        # node.
        if dbNode.softwareprofile and \
                dbNode.softwareprofile.type != 'installer' and \
                dbNode.hardwareprofile.location != 'remote':
            # update local boot configuration for on-premise nodes
            self._bhm.writePXEFile(session, dbNode, localboot=bootFrom)

        session.commit()

        #
        # If the node state has changed, fire the node state changed
        # event
        #
        if state and (previous_state != state):
            NodeStateChanged.fire(node=node_dict,
                                  previous_state=previous_state)

        return result

    def __process_nodeErrorDict(self, nodeErrorDict):
        result = {}
        nodes_deleted = []

        for key, nodeList in nodeErrorDict.items():
            result[key] = [dbNode.name for dbNode in nodeList]

            if key == 'NodesDeleted':
                for node in nodeList:
                    node_deleted = {
                        'name': node.name,
                        'hardwareprofile': node.hardwareprofile.name,
                        'addHostSession': node.addHostSession,
                    }

                    if node.softwareprofile:
                        node_deleted['softwareprofile'] = \
                            node.softwareprofile.name

                    nodes_deleted.append(node_deleted)

        return result, nodes_deleted

    def deleteNode(self, session, nodespec: str, force: bool = False):
        """
        Delete node by nodespec

        Raises:
            NodeNotFound
        """

        kitmgr = KitActionsManager()
        kitmgr.session = session

        try:
            nodes = self._nodesDbHandler.expand_nodespec(
                session, nodespec, include_installer=False)
            if not nodes:
                raise NodeNotFound('No nodes matching nodespec [%s]' %
                                   (nodespec))

            self.__validate_delete_nodes_request(nodes, force)

            self.__preDeleteHost(kitmgr, nodes)

            nodeErrorDict = self.__delete_node(session, nodes)

            # REALLY!?!? Convert a list of Nodes objects into a list of
            # node names so we can report the list back to the end-user.
            # This needs to be FIXED!

            result, nodes_deleted = self.__process_nodeErrorDict(nodeErrorDict)

            session.commit()

            # ============================================================
            # Perform actions *after* node deletion(s) have been committed
            # to database.
            # ============================================================

            self.__postDeleteHost(kitmgr, nodes_deleted)

            addHostSessions = set(
                [tmpnode['addHostSession'] for tmpnode in nodes_deleted])

            if addHostSessions:
                self._addHostManager.delete_sessions(addHostSessions)

            for nodeName in result['NodesDeleted']:
                # Remove the Puppet cert
                self._bhm.deletePuppetNodeCert(nodeName)

                self._bhm.nodeCleanup(nodeName)

                self._logger.info('Node [%s] deleted' % (nodeName))

            # Schedule a cluster update
            self.__scheduleUpdate()

            return result
        except Exception:
            session.rollback()

            raise

    def __validate_delete_nodes_request(self, nodes: List[NodeModel],
                                        force: bool):
        """
        Raises:
            DeleteNodeFailed
        """

        swprofile_distribution: Dict[SoftwareProfileModel, int] = {}

        for node in nodes:
            if node.softwareprofile not in swprofile_distribution:
                swprofile_distribution[node.softwareprofile] = 0

            swprofile_distribution[node.softwareprofile] += 1

        errors: List[str] = []

        for software_profile, num_nodes_deleted in \
                swprofile_distribution.items():
            if software_profile.lockedState == 'HardLocked':
                errors.append(
                    f'Nodes cannot be deleted from hard locked software'
                    ' profile [{software_profile.name}]')

                continue

            if software_profile.minNodes and \
                    len(software_profile.nodes) - num_nodes_deleted < \
                        software_profile.minNodes:
                if force and software_profile.lockedState == 'SoftLocked':
                    # allow deletion of nodes when force is set and profile
                    # is soft locked
                    continue

                # do not allow number of software profile nodes to drop
                # below configured minimum
                errors.append(
                    'Software profile [{}] requires minimum of {} nodes;'
                    ' denied request to delete {} node(s)'.format(
                        software_profile.name, software_profile.minNodes,
                        num_nodes_deleted))

                continue

            if software_profile.lockedState == 'SoftLocked' and not force:
                errors.append(
                    'Nodes cannot be deleted from soft locked software'
                    f' profile [{software_profile.name}]')

        if errors:
            raise OperationFailed('\n'.join(errors))

    def __delete_node(self, session: Session, dbNodes: List[NodeModel]) \
            -> Dict[str, List[NodeModel]]:
        """
        Raises:
            DeleteNodeFailed
        """

        result: Dict[str, list] = {
            'NodesDeleted': [],
            'DeleteNodeFailed': [],
            'SoftwareProfileLocked': [],
            'SoftwareProfileHardLocked': [],
        }

        nodes: Dict[HardwareProfileModel, List[NodeModel]] = {}
        events_to_fire: List[dict] = []

        #
        # Mark node states as deleted in the database
        #
        for dbNode in dbNodes:
            #
            # Capture previous state and node data as a dict for firing
            # the event later on
            #
            event_data = {
                'previous_state': dbNode.state,
                'node': Node.getFromDbDict(dbNode.__dict__).getCleanDict()
            }

            dbNode.state = state.NODE_STATE_DELETED
            event_data['node']['state'] = 'Deleted'

            if dbNode.hardwareprofile not in nodes:
                nodes[dbNode.hardwareprofile] = [dbNode]
            else:
                nodes[dbNode.hardwareprofile].append(dbNode)

        session.commit()

        #
        # Fire node state change events
        #
        for event in events_to_fire:
            NodeStateChanged.fire(node=event['node'],
                                  previous_state=event['previous_state'])

        #
        # Call resource adapter with batch(es) of node lists keyed on
        # hardware profile.
        #
        for hwprofile, hwprofile_nodes in nodes.items():
            # Get the ResourceAdapter
            adapter = self.__get_resource_adapter(session, hwprofile)

            # Call the resource adapter
            adapter.deleteNode(hwprofile_nodes)

            # Iterate over all nodes in hardware profile, completing the
            # delete operation.
            for dbNode in hwprofile_nodes:
                for tag in dbNode.tags:
                    if len(tag.nodes) == 1 and \
                            not tag.softwareprofiles and \
                            not tag.hardwareprofiles:
                        session.delete(tag)

                # Delete the Node
                self._logger.debug('Deleting node [%s]' % (dbNode.name))

                session.delete(dbNode)

                result['NodesDeleted'].append(dbNode)

        return result

    def __get_resource_adapter(self, session: Session,
                               hardwareProfile: HardwareProfileModel):
        """
        Raises:
            OperationFailed
        """

        if not hardwareProfile.resourceadapter:
            raise OperationFailed(
                'Hardware profile [%s] does not have an associated'
                ' resource adapter' % (hardwareProfile.name))

        adapter = resourceAdapterFactory.get_api(
            hardwareProfile.resourceadapter.name)

        adapter.session = session

        return adapter

    def __process_delete_node_result(self, nodeErrorDict):
        # REALLY!?!? Convert a list of Nodes objects into a list of
        # node names so we can report the list back to the end-user.
        # This needs to be FIXED!

        result = {}
        nodes_deleted = []

        for key, nodeList in nodeErrorDict.items():
            result[key] = [dbNode.name for dbNode in nodeList]

            if key == 'NodesDeleted':
                for node in nodeList:
                    node_deleted = {
                        'name': node.name,
                        'hardwareprofile': node.hardwareprofile.name,
                    }

                    if node.softwareprofile:
                        node_deleted['softwareprofile'] = \
                            node.softwareprofile.name

                    nodes_deleted.append(node_deleted)

        return result, nodes_deleted

    def __preDeleteHost(self, kitmgr: KitActionsManager, nodes):
        self._logger.debug('__preDeleteHost(): nodes=[%s]' %
                           (' '.join([node.name for node in nodes])))

        for node in nodes:
            kitmgr.pre_delete_host(
                node.hardwareprofile.name,
                node.softwareprofile.name if node.softwareprofile else None,
                nodes=[node.name])

    def __postDeleteHost(self, kitmgr, nodes_deleted):
        # 'nodes_deleted' is a list of dicts of the following format:
        #
        # {
        #     'name': 'compute-01',
        #     'softwareprofile': 'Compute',
        #     'hardwareprofile': 'LocalIron',
        # }
        #
        # if the node does not have an associated software profile, the
        # dict does not contain the key 'softwareprofile'.

        self._logger.debug('__postDeleteHost(): nodes_deleted=[%s]' %
                           (nodes_deleted))

        if not nodes_deleted:
            self._logger.debug('No nodes deleted in this operation')

            return

        for node_dict in nodes_deleted:
            kitmgr.post_delete_host(node_dict['hardwareprofile'],
                                    node_dict['softwareprofile'] if
                                    'softwareprofile' in node_dict else None,
                                    nodes=[node_dict['name']])

    def __scheduleUpdate(self):
        self._syncApi.scheduleClusterUpdate()

    def getInstallerNode(self,
                         session,
                         optionDict: Optional[OptionDict] = None):
        return self._nodeDbApi.getNode(
            session,
            self._cm.getInstaller(),
            optionDict=get_default_relations(optionDict))

    def getProvisioningInfo(self, session: Session, nodeName):
        return self._nodeDbApi.getProvisioningInfo(session, nodeName)

    def startupNode(self,
                    session,
                    nodespec: str,
                    remainingNodeList: List[NodeModel] = None,
                    bootMethod: str = 'n') -> None:
        """
        Raises:
            NodeNotFound
        """

        try:
            nodes = self._nodesDbHandler.expand_nodespec(session, nodespec)

            if not nodes:
                raise NodeNotFound('No matching nodes for nodespec [%s]' %
                                   (nodespec))

            # Break list of nodes into dict keyed on hardware profile
            nodes_dict = self.__processNodeList(nodes)

            for dbHardwareProfile, detailsDict in nodes_dict.items():
                # Get the ResourceAdapter
                adapter = self.__getResourceAdapter(dbHardwareProfile)

                # Call startup action extension
                adapter.startupNode(detailsDict['nodes'],
                                    remainingNodeList=remainingNodeList or [],
                                    tmpBootMethod=bootMethod)

            session.commit()
        except TortugaException:
            session.rollback()
            raise
        except Exception as ex:
            session.rollback()
            self._logger.exception(str(ex))
            raise

    def shutdownNode(self, session, nodespec: str, bSoftShutdown: bool = False) \
            -> None:
        """
        Raises:
            NodeNotFound
        """

        try:
            nodes = self._nodesDbHandler.expand_nodespec(session, nodespec)

            if not nodes:
                raise NodeNotFound('No matching nodes for nodespec [%s]' %
                                   (nodespec))

            d = self.__processNodeList(nodes)

            for dbHardwareProfile, detailsDict in d.items():
                # Get the ResourceAdapter
                adapter = self.__getResourceAdapter(dbHardwareProfile)

                # Call shutdown action extension
                adapter.shutdownNode(detailsDict['nodes'], bSoftShutdown)

            session.commit()
        except TortugaException:
            session.rollback()
            raise
        except Exception as ex:
            session.rollback()
            self._logger.exception(str(ex))
            raise

    def rebootNode(self,
                   session,
                   nodespec: str,
                   bSoftReset: bool = False,
                   bReinstall: bool = False) -> None:
        """
        Raises:
            NodeNotFound
        """

        nodes = self._nodesDbHandler.expand_nodespec(session, nodespec)
        if not nodes:
            raise NodeNotFound('No nodes matching nodespec [%s]' % (nodespec))

        if bReinstall:
            for dbNode in nodes:
                self._bhm.setNodeForNetworkBoot(session, dbNode)

        for dbHardwareProfile, detailsDict in \
                self.__processNodeList(nodes).items():
            # iterate over hardware profile/nodes dict to reboot each
            # node
            adapter = self.__getResourceAdapter(dbHardwareProfile)

            # Call reboot action extension
            adapter.rebootNode(detailsDict['nodes'], bSoftReset)

        session.commit()

    def getNodesByNodeState(self, session, node_state: str,
                            optionDict: Optional[OptionDict] = None) \
            -> TortugaObjectList:
        """
        Get nodes by state
        """

        return self.__populate_nodes(
            session,
            self._nodeDbApi.getNodesByNodeState(
                session,
                node_state,
                optionDict=get_default_relations(optionDict)))

    def getNodesByNameFilter(self, session, nodespec: str,
                             optionDict: OptionDict = None,
                             include_installer: Optional[bool] = True) \
            -> TortugaObjectList:
        """
        Return TortugaObjectList of Node objects matching nodespec
        """

        return self.__populate_nodes(
            session,
            self._nodeDbApi.getNodesByNameFilter(
                session,
                nodespec,
                optionDict=get_default_relations(optionDict),
                include_installer=include_installer))

    def getNodesByAddHostSession(self, session, addHostSession: str,
                                 optionDict: OptionDict = None) \
            -> TortugaObjectList:
        """
        Return TortugaObjectList of Node objects matching add host session
        """

        return self.__populate_nodes(
            session,
            self._nodeDbApi.getNodesByAddHostSession(
                session,
                addHostSession,
                optionDict=get_default_relations(optionDict)))

    def __processNodeList(self, dbNodes: List[NodeModel]) \
            -> Dict[HardwareProfileModel, Dict[str, list]]:
        """
        Returns dict indexed by hardware profile, each with a list of
        nodes in the hardware profile
        """

        d: Dict[HardwareProfileModel, Dict[str, list]] = {}

        for dbNode in dbNodes:
            if dbNode.hardwareprofile not in d:
                d[dbNode.hardwareprofile] = {
                    'nodes': [],
                }

            d[dbNode.hardwareprofile]['nodes'].append(dbNode)

        return d

    def __getResourceAdapter(self, hardwareProfile: HardwareProfileModel):
        """
        Raises:
            OperationFailed
        """

        if not hardwareProfile.resourceadapter:
            raise OperationFailed(
                'Hardware profile [%s] does not have an associated'
                ' resource adapter' % (hardwareProfile.name))

        return resourceAdapterFactory.get_api(
            hardwareProfile.resourceadapter.name) \
            if hardwareProfile.resourceadapter else None
Example #11
0
    def deleteNode(self, nodespec):
        """
        Delete node by nodespec

        Raises:
            NodeNotFound
        """

        installer_hostname = socket.getfqdn().split('.', 1)[0]

        session = DbManager().openSession()

        try:
            nodes = []

            for node in self.__expand_nodespec(session, nodespec):
                if node.name.split('.', 1)[0] == installer_hostname:
                    self.getLogger().info(
                        'Ignoring request to delete installer node'
                        ' ([{0}])'.format(node.name))

                    continue

                nodes.append(node)

            if not nodes:
                raise NodeNotFound('No nodes matching nodespec [%s]' %
                                   (nodespec))

            self.__preDeleteHost(nodes)

            nodeErrorDict = NodesDbHandler().deleteNode(session, nodes)

            # REALLY!?!? Convert a list of Nodes objects into a list of
            # node names so we can report the list back to the end-user.
            # This needs to be FIXED!

            result, nodes_deleted = self.__process_nodeErrorDict(nodeErrorDict)

            session.commit()

            # ============================================================
            # Perform actions *after* node deletion(s) have been committed
            # to database.
            # ============================================================

            self.__postDeleteHost(nodes_deleted)

            addHostSessions = set(
                [tmpnode['addHostSession'] for tmpnode in nodes_deleted])

            if addHostSessions:
                AddHostManager().delete_sessions(addHostSessions)

            bhm = osUtility.getOsObjectFactory().getOsBootHostManager()

            for nodeName in result['NodesDeleted']:
                # Remove the Puppet cert
                bhm.deletePuppetNodeCert(nodeName)

                bhm.nodeCleanup(nodeName)

                self.getLogger().info('Node [%s] deleted' % (nodeName))

            # Schedule a cluster update
            self.__scheduleUpdate()

            return result
        except TortugaException:
            session.rollback()

            raise
        except Exception:
            session.rollback()

            self.getLogger().exception('Exception in NodeManager.deleteNode()')

            raise
        finally:
            DbManager().closeSession()
Example #12
0
class NodeManager(TortugaObjectManager):     \
        # pylint: disable=too-many-public-methods

    def __init__(self):
        super(NodeManager, self).__init__()

        self._nodeDbApi = NodeDbApi()
        self._cm = ConfigManager()
        self._bhm = osUtility.getOsObjectFactory().getOsBootHostManager(
            self._cm)
        self._syncApi = SyncApi()
        self._nodesDbHandler = NodesDbHandler()
        self._addHostManager = AddHostManager()
        self._logger = logging.getLogger(NODE_NAMESPACE)

    def __validateHostName(self, hostname: str, name_format: str) -> None:
        """
        Raises:
            ConfigurationError
        """

        bWildcardNameFormat = (name_format == '*')

        if hostname and not bWildcardNameFormat:
            # Host name specified, but hardware profile does not
            # allow setting the host name
            raise ConfigurationError(
                'Hardware profile does not allow setting host names'
                ' of imported nodes')
        elif not hostname and bWildcardNameFormat:
            # Host name not specified but hardware profile expects it
            raise ConfigurationError(
                'Hardware profile requires host names to be set')

    def createNewNode(self,
                      session: Session,
                      addNodeRequest: dict,
                      dbHardwareProfile: HardwareProfileModel,
                      dbSoftwareProfile: Optional[SoftwareProfileModel] = None,
                      validateIp: bool = True,
                      bGenerateIp: bool = True,
                      dns_zone: Optional[str] = None) -> NodeModel:
        """
        Convert the addNodeRequest into a Nodes object

        Raises:
            NicNotFound
        """

        self._logger.debug(
            'createNewNode(): session=[%s], addNodeRequest=[%s],'
            ' dbHardwareProfile=[%s], dbSoftwareProfile=[%s],'
            ' validateIp=[%s], bGenerateIp=[%s]' %
            (id(session), addNodeRequest, dbHardwareProfile.name,
             dbSoftwareProfile.name if dbSoftwareProfile else '(none)',
             validateIp, bGenerateIp))

        hostname = addNodeRequest['name'] \
            if 'name' in addNodeRequest else None

        # Ensure no conflicting options (ie. specifying host name for
        # hardware profile in which host names are generated)
        self.__validateHostName(hostname, dbHardwareProfile.nameFormat)

        node: Node = NodeModel(name=hostname)

        if 'rack' in addNodeRequest:
            node.rack = addNodeRequest['rack']

        node.addHostSession = addNodeRequest['addHostSession']

        # Complete initialization of new node record
        nic_defs = addNodeRequest['nics'] \
            if 'nics' in addNodeRequest else []

        AddHostServerLocal().initializeNode(session,
                                            node,
                                            dbHardwareProfile,
                                            dbSoftwareProfile,
                                            nic_defs,
                                            bValidateIp=validateIp,
                                            bGenerateIp=bGenerateIp,
                                            dns_zone=dns_zone)

        node.hardwareprofile = dbHardwareProfile
        node.softwareprofile = dbSoftwareProfile

        #
        # Fire the tags changed event for all creates that have tags...
        # we have to convert this to a node object because... our API
        # is inconsistent!
        #
        n = Node.getFromDbDict(node.__dict__)
        if n.getTags():
            NodeTagsChanged.fire(node=n.getCleanDict(), previous_tags={})

        # Return the new node
        return node

    def getNode(self, session: Session, name, optionDict: OptionDict = None) \
            -> Node:
        """
        Get node by name

        Raises:
            NodeNotFound
        """

        return self.__populate_nodes(session, [
            self._nodeDbApi.getNode(
                session, name, optionDict=get_default_relations(optionDict))
        ])[0]

    def getNodeById(self,
                    session: Session,
                    nodeId: int,
                    optionDict: OptionDict = None) -> Node:
        """
        Get node by node id

        Raises:
            NodeNotFound
        """

        return self.__populate_nodes(session, [
            self._nodeDbApi.getNodeById(
                session,
                int(nodeId),
                optionDict=get_default_relations(optionDict))
        ])[0]

    def getNodeByIp(self,
                    session: Session,
                    ip: str,
                    optionDict: Dict[str, bool] = None) -> Node:
        """
        Get node by IP address

        Raises:
            NodeNotFound
        """

        return self.__populate_nodes(session, [
            self._nodeDbApi.getNodeByIp(
                session, ip, optionDict=get_default_relations(optionDict))
        ])[0]

    def getNodeList(self,
                    session,
                    tags=None,
                    optionDict: Optional[OptionDict] = None) -> List[Node]:
        """
        Return all nodes

        """
        return self.__populate_nodes(
            session,
            self._nodeDbApi.getNodeList(
                session,
                tags=tags,
                optionDict=get_default_relations(optionDict)))

    def __populate_nodes(self, session: Session, nodes: List[Node]) \
            -> List[Node]:
        """
        Expand non-database fields in Node objects

        """
        class SoftwareProfileMetadataCache(defaultdict):
            def __missing__(self, key):
                metadata = \
                    SoftwareProfileManager().get_software_profile_metadata(
                        session, key
                    )

                self[key] = metadata

                return metadata

        swprofile_map = SoftwareProfileMetadataCache()

        for node in nodes:
            if not node.getSoftwareProfile():
                continue

            node.getSoftwareProfile().setMetadata(
                swprofile_map[node.getSoftwareProfile().getName()])

        return nodes

    def updateNode(self, session: Session, nodeName: str,
                   updateNodeRequest: dict) -> None:
        """
        Calls updateNode() method of resource adapter
        """

        self._logger.debug('updateNode(): name=[{0}]'.format(nodeName))

        try:
            #
            # Get the old version for comparison later
            #
            node_old: Node = self.getNode(session, nodeName)

            db_node = self._nodesDbHandler.getNode(session, nodeName)
            if 'nics' in updateNodeRequest:
                nic = updateNodeRequest['nics'][0]
                if 'ip' in nic:
                    db_node.nics[0].ip = nic['ip']
                    db_node.nics[0].boot = True

            adapter = self.__getResourceAdapter(session,
                                                db_node.hardwareprofile)
            adapter.updateNode(session, db_node, updateNodeRequest)
            run_post_install = False

            if 'state' in updateNodeRequest:
                run_post_install = \
                    db_node.state == state.NODE_STATE_ALLOCATED and \
                    updateNodeRequest['state'] == state.NODE_STATE_PROVISIONED
                db_node.state = updateNodeRequest['state']

            session.commit()

            #
            # Fire events as required
            #
            # Get the current/new state of the node from the DB
            #
            node: Node = self.getNode(session, nodeName)
            if node.getState() != node_old.getState():
                NodeStateChanged.fire(node=node.getCleanDict(),
                                      previous_state=node_old.getState())
            if node.getTags() != node_old.getTags():
                NodeTagsChanged.fire(node=node.getCleanDict(),
                                     previous_tags=node_old.getTags())

            if run_post_install:
                self._logger.debug(
                    'updateNode(): run-post-install for node [{0}]'.format(
                        db_node.name))
                self.__scheduleUpdate()

        except Exception:
            session.rollback()
            raise

    def updateNodeStatus(self,
                         session: Session,
                         nodeName: str,
                         node_state: Optional[str] = None,
                         bootFrom: int = None):
        """Update node status

        If neither 'state' nor 'bootFrom' are not None, this operation will
        update only the 'lastUpdated' timestamp.

        Returns:
            bool indicating whether state and/or bootFrom differed from
            current value
        """

        value = 'None' if bootFrom is None else \
            '1 (disk)' if int(bootFrom) == 1 else '0 (network)'

        self._logger.debug(
            'updateNodeStatus(): node=[%s], node_state=[{%s}],'
            ' bootFrom=[{%s}]', nodeName, node_state, value)

        dbNode = self._nodesDbHandler.getNode(session, nodeName)

        #
        # Capture previous state and node data in dict form for the
        # event later on
        #
        previous_state = dbNode.state
        node_dict = Node.getFromDbDict(dbNode.__dict__).getCleanDict()

        # Bitfield representing node changes (0 = state change,
        # 1 = bootFrom # change)
        changed = 0

        if node_state is not None and node_state != dbNode.state:
            # 'state' changed
            changed |= 1

        if bootFrom is not None and bootFrom != dbNode.bootFrom:
            # 'bootFrom' changed
            changed |= 2

        if changed:
            # Create custom log message
            msg = 'Node [%s] state change:' % (dbNode.name)

            if changed & 1:
                msg += ' state: [%s] -> [%s]' % (dbNode.state, node_state)

                dbNode.state = node_state
                node_dict['state'] = node_state

            if changed & 2:
                msg += ' bootFrom: [%d] -> [%d]' % (dbNode.bootFrom, bootFrom)

                dbNode.bootFrom = bootFrom

            self._logger.info(msg)
        else:
            self._logger.info('Updated timestamp for node [%s]' %
                              (dbNode.name))

        dbNode.lastUpdate = time.strftime('%Y-%m-%d %H:%M:%S',
                                          time.gmtime(time.time()))

        result = bool(changed)

        # Only change local boot configuration if the hardware profile is
        # not marked as 'remote' and we're not acting on the installer
        # node.
        if dbNode.softwareprofile and \
                dbNode.softwareprofile.type != 'installer' and \
                dbNode.hardwareprofile.location != 'remote':
            # update local boot configuration for on-premise nodes
            self._bhm.writePXEFile(session, dbNode, localboot=bootFrom)

        session.commit()

        #
        # If the node state has changed, fire the node state changed
        # event
        #
        if state and (previous_state != state):
            NodeStateChanged.fire(node=node_dict,
                                  previous_state=previous_state)

        return result

    def deleteNode(self, session: Session, nodespec: str, force: bool = False):
        """
        Delete nodes by node spec

        :param Session session: a database session
        :param str nodespec:    a node spec
        :param bool force:      whether or not this is a force operation

        """
        try:
            nodes = self.__get_nodes_for_deletion(session, nodespec)

            kitmgr = KitActionsManager()
            kitmgr.session = session
            self.__delete_nodes(session, kitmgr, nodes)

        except Exception:
            session.rollback()
            raise

    def __get_nodes_for_deletion(self, session: Session,
                                 nodespec: str) -> List[NodeModel]:
        """
        Gets a list of nodes from a node spec.

        :param Session session: a database session
        :param str nodespec:    a node spec

        :raise NodeNotFound:

        """
        nodes = self._nodesDbHandler.expand_nodespec(session,
                                                     nodespec,
                                                     include_installer=False)
        if not nodes:
            raise NodeNotFound(
                'No nodes matching nodespec [{}]'.format(nodespec))

        return nodes

    def __delete_nodes(self, session: Session, kitmgr: KitActionsManager,
                       nodes: List[NodeModel]) -> None:
        """
        :raises DeleteNodeFailed:
        """

        hwprofile_nodes = self.__pre_delete_nodes(kitmgr, nodes)

        # commit node state changes to database
        session.commit()

        for hwprofile, node_data_dicts in hwprofile_nodes.items():
            # build list of NodeModels
            node_objs: List[NodeModel] = [
                node_data_dict['node'] for node_data_dict in node_data_dicts
            ]

            # Call resource adapter deleteNode() entry point
            self.__get_resource_adapter(session,
                                        hwprofile).deleteNode(node_objs)

            # Perform delete node action for each node in hwprofile
            for node_data_dict in node_data_dicts:
                # get JSON object for node record
                node_dict = NodeSchema(
                    only=('hardwareprofile', 'softwareprofile', 'name',
                          'state'),
                    exclude=('softwareprofile.metadata', )).dump(
                        node_data_dict['node']).data

                # Delete the Node
                self._logger.debug('Deleting node [%s]', node_dict['name'])

                #
                # Fire node state change events
                #
                NodeStateChanged.fire(
                    node=node_dict,
                    previous_state=node_data_dict['previous_state'])

                session.delete(node_data_dict['node'])

                # Commit the actual deletion of this node to the DB.  This is required
                # as the post_delete hooks may use a different DB session and we have
                # already commited some changes for this node.
                session.commit()

                self.__post_delete(kitmgr, node_dict)

                self._logger.info('Node [%s] deleted', node_dict['name'])

            # clean up add host session cache
            self._addHostManager.delete_sessions(
                set([
                    node.addHostSession for node in node_objs
                    if node.addHostSession
                ]))

        self.__scheduleUpdate()

    def __pre_delete_nodes(self, kitmgr: KitActionsManager,
                           nodes: List[NodeModel]) \
            -> DefaultDict[HardwareProfileModel, List[NodeModel]]:
        """Collect nodes being deleted, call pre-delete kit action,
        mark them for deletion, and return dict containing nodes
        keyed by hardware profile.
        """

        hwprofile_nodes = defaultdict(list)

        #
        # Mark node states as deleted in the database
        #
        for node in nodes:
            # call pre-delete host kit action
            kitmgr.pre_delete_host(node.hardwareprofile.name,
                                   get_node_swprofile_name(node),
                                   nodes=[node.name])

            #
            # Capture previous state and node data as a dict for firing
            # the event later on
            #
            hwprofile_nodes[node.hardwareprofile].append({
                'node':
                node,
                'previous_state':
                node.state
            })

            # mark node deleted
            node.state = state.NODE_STATE_DELETED

        return hwprofile_nodes

    def __get_resource_adapter(self, session: Session,
                               hardwareProfile: HardwareProfileModel):
        """
        Raises:
            OperationFailed
        """

        if not hardwareProfile.resourceadapter:
            raise OperationFailed(
                'Hardware profile [%s] does not have an associated'
                ' resource adapter' % (hardwareProfile.name))

        adapter = resourceAdapterFactory.get_api(
            hardwareProfile.resourceadapter.name)

        adapter.session = session

        return adapter

    def __process_delete_node_result(self, nodeErrorDict):
        # REALLY!?!? Convert a list of Nodes objects into a list of
        # node names so we can report the list back to the end-user.
        # This needs to be FIXED!

        result = {}
        nodes_deleted = []

        for key, nodeList in nodeErrorDict.items():
            result[key] = [dbNode.name for dbNode in nodeList]

            if key == 'NodesDeleted':
                for node in nodeList:
                    node_deleted = {
                        'name': node.name,
                        'hardwareprofile': node.hardwareprofile.name,
                    }

                    if node.softwareprofile:
                        node_deleted['softwareprofile'] = \
                            node.softwareprofile.name

                    nodes_deleted.append(node_deleted)

        return result, nodes_deleted

    def __post_delete(self, kitmgr: KitActionsManager, node: dict):
        """Call post-delete kit action for deleted node and clean up node
        state files (ie. Puppet certificate, etc.).

        'node' is a JSON object representing the deleted node.
        """

        kitmgr.post_delete_host(node['hardwareprofile']['name'],
                                node['softwareprofile']['name']
                                if node['softwareprofile'] else None,
                                nodes=[node['name']])

        # remove Puppet cert, etc.
        self.__cleanup_node_state_files(node)

    def __cleanup_node_state_files(self, node_dict: dict):
        # Remove the Puppet cert
        self._bhm.deletePuppetNodeCert(node_dict['name'])

        self._bhm.nodeCleanup(node_dict['name'])

    def __scheduleUpdate(self):
        self._syncApi.scheduleClusterUpdate()

    def getInstallerNode(self,
                         session,
                         optionDict: Optional[OptionDict] = None):
        return self._nodeDbApi.getNode(
            session,
            self._cm.getInstaller(),
            optionDict=get_default_relations(optionDict))

    def getProvisioningInfo(self, session: Session, nodeName):
        return self._nodeDbApi.getProvisioningInfo(session, nodeName)

    def startupNode(self,
                    session,
                    nodespec: str,
                    remainingNodeList: List[NodeModel] = None,
                    bootMethod: str = 'n') -> None:
        """
        Raises:
            NodeNotFound
        """

        try:
            nodes = self._nodesDbHandler.expand_nodespec(session, nodespec)

            if not nodes:
                raise NodeNotFound('No matching nodes for nodespec [%s]' %
                                   (nodespec))

            # Break list of nodes into dict keyed on hardware profile
            nodes_dict = self.__processNodeList(nodes)

            for dbHardwareProfile, detailsDict in nodes_dict.items():
                # Get the ResourceAdapter
                adapter = self.__getResourceAdapter(session, dbHardwareProfile)

                # Call startup action extension
                adapter.startupNode(detailsDict['nodes'],
                                    remainingNodeList=remainingNodeList or [],
                                    tmpBootMethod=bootMethod)

            session.commit()
        except TortugaException:
            session.rollback()
            raise
        except Exception as ex:
            session.rollback()
            self._logger.exception(str(ex))
            raise

    def shutdownNode(self,
                     session,
                     nodespec: str,
                     bSoftShutdown: bool = False) -> None:
        """
        Raises:
            NodeNotFound
        """

        try:
            nodes = self._nodesDbHandler.expand_nodespec(session, nodespec)

            if not nodes:
                raise NodeNotFound('No matching nodes for nodespec [%s]' %
                                   (nodespec))

            d = self.__processNodeList(nodes)

            for dbHardwareProfile, detailsDict in d.items():
                # Get the ResourceAdapter
                adapter = self.__getResourceAdapter(session, dbHardwareProfile)

                # Call shutdown action extension
                adapter.shutdownNode(detailsDict['nodes'], bSoftShutdown)

            session.commit()
        except TortugaException:
            session.rollback()
            raise
        except Exception as ex:
            session.rollback()
            self._logger.exception(str(ex))
            raise

    def rebootNode(self,
                   session,
                   nodespec: str,
                   bSoftReset: bool = False,
                   bReinstall: bool = False) -> None:
        """
        Raises:
            NodeNotFound
        """

        nodes = self._nodesDbHandler.expand_nodespec(session, nodespec)
        if not nodes:
            raise NodeNotFound('No nodes matching nodespec [%s]' % (nodespec))

        if bReinstall:
            for dbNode in nodes:
                self._bhm.setNodeForNetworkBoot(session, dbNode)

        for dbHardwareProfile, detailsDict in \
                self.__processNodeList(nodes).items():
            # iterate over hardware profile/nodes dict to reboot each
            # node
            adapter = self.__getResourceAdapter(session, dbHardwareProfile)

            # Call reboot action extension
            adapter.rebootNode(detailsDict['nodes'], bSoftReset)

        session.commit()

    def getNodesByNodeState(self, session, node_state: str,
                            optionDict: Optional[OptionDict] = None) \
            -> TortugaObjectList:
        """
        Get nodes by state
        """

        return self.__populate_nodes(
            session,
            self._nodeDbApi.getNodesByNodeState(
                session,
                node_state,
                optionDict=get_default_relations(optionDict)))

    def getNodesByNameFilter(self, session, nodespec: str,
                             optionDict: OptionDict = None,
                             include_installer: Optional[bool] = True) \
            -> TortugaObjectList:
        """
        Return TortugaObjectList of Node objects matching nodespec
        """

        return self.__populate_nodes(
            session,
            self._nodeDbApi.getNodesByNameFilter(
                session,
                nodespec,
                optionDict=get_default_relations(optionDict),
                include_installer=include_installer))

    def getNodesByAddHostSession(self, session, addHostSession: str,
                                 optionDict: OptionDict = None) \
            -> TortugaObjectList:
        """
        Return TortugaObjectList of Node objects matching add host session
        """

        return self.__populate_nodes(
            session,
            self._nodeDbApi.getNodesByAddHostSession(
                session,
                addHostSession,
                optionDict=get_default_relations(optionDict)))

    def __processNodeList(self, dbNodes: List[NodeModel]) \
            -> Dict[HardwareProfileModel, Dict[str, list]]:
        """
        Returns dict indexed by hardware profile, each with a list of
        nodes in the hardware profile
        """

        d: Dict[HardwareProfileModel, Dict[str, list]] = {}

        for dbNode in dbNodes:
            if dbNode.hardwareprofile not in d:
                d[dbNode.hardwareprofile] = {
                    'nodes': [],
                }

            d[dbNode.hardwareprofile]['nodes'].append(dbNode)

        return d

    def __getResourceAdapter(self, session: Session,
                             hardwareProfile: HardwareProfileModel) \
            -> Optional[ResourceAdapter]:
        """
        Raises:
            OperationFailed
        """

        if not hardwareProfile.resourceadapter:
            raise OperationFailed(
                'Hardware profile [%s] does not have an associated'
                ' resource adapter' % (hardwareProfile.name))

        adapter = resourceAdapterFactory.get_api(
            hardwareProfile.resourceadapter.name) \
            if hardwareProfile.resourceadapter else None

        if not adapter:
            return None

        adapter.session = session

        return adapter
Example #13
0
    def __enter__(self):
        self.ahm = AddHostManager()

        self.ahm.update_session(self.addHostSession, running=True)

        return self.ahm