def getNode(self, name: str, optionDict: Optional[Union[dict, None]] = None): """ Get node from the db. Returns: node Throws: NodeNotFound DbError """ session = DbManager().openSession() try: dbNode = self._nodesDbHandler.getNode(session, name) self.loadRelations(dbNode, optionDict) self.loadRelations(dbNode, { 'softwareprofile': True, 'hardwareprofile': True, 'tags': True, }) return Node.getFromDbDict(dbNode.__dict__) except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession()
def getNodeList(self, softwareProfile): """ Get list of nodes in 'softwareProfile' Returns: [node] Throws: DbError """ session = DbManager().openSession() try: dbSoftwareProfile = self._softwareProfilesDbHandler.\ getSoftwareProfile(session, softwareProfile) nodeList = TortugaObjectList() for dbNode in dbSoftwareProfile.nodes: self.loadRelation(dbNode, 'hardwareprofile') nodeList.append(Node.getFromDbDict(dbNode.__dict__)) return nodeList except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession()
def getNodeList(self, session: Session, softwareProfile: SoftwareProfile) -> TortugaObjectList: """ Get list of nodes in 'softwareProfile' Returns: [node] Throws: DbError """ try: dbSoftwareProfile = \ self._softwareProfilesDbHandler.getSoftwareProfile( session, softwareProfile) nodeList = TortugaObjectList() for dbNode in dbSoftwareProfile.nodes: self.loadRelation(dbNode, 'hardwareprofile') nodeList.append(Node.getFromDbDict(dbNode.__dict__)) return nodeList except TortugaException: raise except Exception as ex: self._logger.exception(str(ex)) raise
def __convert_nodes_to_TortugaObjectList( self, nodes: List[NodeModel], optionDict: Optional[OptionsDict] = None) -> TortugaObjectList: """ Return TortugaObjectList of nodes with relations populated :param nodes: list of Node objects :param optionDict: :param deleting: whether or not to include nodes in the deleting state :return: TortugaObjectList """ nodeList = TortugaObjectList() for node in nodes: self.loadRelations(node, optionDict) # ensure 'resourceadapter' relation is always loaded. This one # is special since it's a relationship inside of a relationship. # It needs to be explicitly defined. self.loadRelation(node.hardwareprofile, 'resourceadapter') nodeList.append(Node.getFromDbDict(node.__dict__)) return nodeList
def test_getFromDbDict(): nodeDbDict = { 'id': 1235, 'name': 'mike', } tmpnode = Node.getFromDbDict(nodeDbDict) assert tmpnode.getName() == 'mike'
def fire_state_change_event(self, db_node: Node, previous_state: str): """ Fires a node state changed event. This is a "fake" operation allowing resource adapters to fire events without having to actually take the node through the actual state change. The node is assumed to have it's current state set to the new state. :param Node db_node: a database node instance :param str previous_state: the previous state for the node """ node_dict = TortugaNode.getFromDbDict(db_node.__dict__).getCleanDict() NodeStateChanged.fire(node=node_dict, previous_state=previous_state)
def getNodeByIp(self, ip): session = DbManager().openSession() try: node = self._nodesDbHandler.getNodeByIp(session, ip) return Node.getFromDbDict(node.__dict__) except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession()
def getNodeById(self, nodeId: int, optionDict: Optional[Union[dict, None]] = None): session = DbManager().openSession() try: dbNode = self._nodesDbHandler.getNodeById(session, nodeId) self.loadRelations(dbNode, optionDict) return Node.getFromDbDict(dbNode.__dict__) except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession()
def __convert_nodes_to_TortugaObjectList( self, nodes, relations: Optional[Union[dict, None]] = None) -> TortugaObjectList: nodeList = TortugaObjectList() relations = relations or dict(softwareprofile=True, hardwareprofile=True) for t in nodes: self.loadRelations(t, relations) # Always load 'tags' relation self.loadRelations(t, {'tags': True}) node = Node.getFromDbDict(t.__dict__) nodeList.append(node) return nodeList
def getProvisioningInfo(self, nodeName): """ Get the provisioing information for a given provisioned address Returns: [provisioningInformation structure] Throws: NodeNotFound DbError """ session = DbManager().openSession() try: provisioningInfo = ProvisioningInfo() dbNode = self._nodesDbHandler.getNode(session, nodeName) if dbNode.softwareprofile: self.loadRelations(dbNode.softwareprofile, { 'partitions': True, 'packages': True, }) for component in dbNode.softwareprofile.components: self.loadRelations( component, { 'kit': True, 'os': True, 'family': True, 'os_components': True, 'osfamily_components': True, }) self.loadRelation(dbNode, 'hardwareprofile') provisioningInfo.setNode(Node.getFromDbDict(dbNode.__dict__)) globalParameters = self._globalParameterDbApi.getParameterList() # TODO: this is a terrible hack until something better comes # along. p = Parameter() p.setName('Installer') hostName = socket.gethostname().split('.', 1)[0] if '.' in dbNode.name: nodeDomain = dbNode.name.split('.', 1)[1] priInstaller = hostName + '.%s' % (nodeDomain) else: priInstaller = hostName p.setValue(priInstaller) globalParameters.append(p) provisioningInfo.setGlobalParameters(globalParameters) return provisioningInfo except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession()
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 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 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 getProvisioningInfo(self, session: Session, nodeName: str) \ -> ProvisioningInfo: """ Get the provisioing information for a given provisioned address Returns: [provisioningInformation structure] Throws: NodeNotFound DbError """ try: provisioningInfo = ProvisioningInfo() dbNode = self._nodesDbHandler.getNode(session, nodeName) if dbNode.softwareprofile: self.loadRelations(dbNode.softwareprofile, { 'partitions': True, }) for component in dbNode.softwareprofile.components: self.loadRelations(component, { 'kit': True, 'os': True, 'family': True, 'os_components': True, 'osfamily_components': True, }) self.loadRelation(dbNode, 'hardwareprofile') provisioningInfo.setNode( Node.getFromDbDict(dbNode.__dict__)) globalParameters = \ self._globalParameterDbApi.getParameterList(session) # manually inject value for 'installer' p = Parameter(name='Installer') hostName = getfqdn().split('.', 1)[0] if '.' in dbNode.name: nodeDomain = dbNode.name.split('.', 1)[1] priInstaller = hostName + '.%s' % (nodeDomain) else: priInstaller = hostName p.setValue(priInstaller) globalParameters.append(p) provisioningInfo.setGlobalParameters(globalParameters) return provisioningInfo except TortugaException: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise
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