def addHosts(self, session, addHostSession, addHostRequest): """ Raises: HardwareProfileNotFound """ self.getLogger().debug('addHosts()') softwareProfilesDbHandler = SoftwareProfilesDbHandler() hardwareProfilesDbHandler = HardwareProfilesDbHandler() dbHardwareProfile = hardwareProfilesDbHandler.getHardwareProfile( session, addHostRequest['hardwareProfile']) if not dbHardwareProfile.resourceadapter: errmsg = ('Resource adapter not defined for hardware' ' profile [%s]' % (dbHardwareProfile.name)) self.getLogger().error(errmsg) raise ResourceAdapterNotFound(errmsg) softwareProfileName = addHostRequest['softwareProfile'] \ if 'softwareProfile' in addHostRequest else None dbSoftwareProfile = softwareProfilesDbHandler.\ getSoftwareProfile(session, softwareProfileName) \ if softwareProfileName else None # Look up and/or create tags as necessary tags = get_tags(session, addHostRequest['tags']) \ if 'tags' in addHostRequest else [] ResourceAdapterClass = resourceAdapterFactory.getResourceAdapterClass( dbHardwareProfile.resourceadapter.name) resourceAdapter = ResourceAdapterClass(addHostSession=addHostSession) # Call the start() method of the resource adapter newNodes = resourceAdapter.start(addHostRequest, session, dbHardwareProfile, dbSoftwareProfile=dbSoftwareProfile) # Apply tags to new nodes for node in newNodes: node.tags = tags # Commit new node(s) to database session.commit() # Only perform post-add operations if we actually added a node if newNodes: if dbSoftwareProfile and not dbSoftwareProfile.isIdle: self.getLogger().info( 'Node(s) added to software profile [%s] and' ' hardware profile [%s]' % (dbSoftwareProfile.name if dbSoftwareProfile else 'None', dbHardwareProfile.name)) newNodeNames = [tmpNode.name for tmpNode in newNodes] resourceAdapter.hookAction('add', newNodeNames) self.postAddHost(dbHardwareProfile.name, softwareProfileName, addHostSession) resourceAdapter.hookAction('start', newNodeNames) self.getLogger().debug('Add host workflow complete')
class HardwareProfileDbApi(TortugaDbApi): """ HardwareProfile DB API class. """ def __init__(self): TortugaDbApi.__init__(self) self._hardwareProfilesDbHandler = HardwareProfilesDbHandler() self._nodesDbHandler = NodesDbHandler() self._globalParametersDbHandler = GlobalParametersDbHandler() self._adminsDbHandler = AdminsDbHandler() self._nicsDbHandler = NicsDbHandler() self._resourceAdaptersDbHandler = ResourceAdaptersDbHandler() self._networkDevicesDbHandler = NetworkDevicesDbHandler() self._networksDbHandler = NetworksDbHandler() def getHardwareProfile(self, name: str, optionDict: Optional[Union[dict, None]] = None): """ Get hardwareProfile from the db. Returns: hardwareProfile Throws: HardwareProfileNotFound DbError """ session = DbManager().openSession() try: dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, name) self.loadRelations(dbHardwareProfile, optionDict) self.loadRelations(dbHardwareProfile, dict(tags=True)) return HardwareProfile.getFromDbDict(dbHardwareProfile.__dict__) except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def getHardwareProfileById(self, hardwareProfileId: int, optionDict: Optional[Union[dict, None]] = None): """ Get hardwareProfile from the db. Returns: hardwareProfile Throws: HardwareProfileNotFound DbError """ session = DbManager().openSession() try: dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfileById(session, hardwareProfileId) self.loadRelations(dbHardwareProfile, optionDict) return HardwareProfile.getFromDbDict(dbHardwareProfile.__dict__) except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def getHardwareProfileList(self, optionDict: Optional[Union[dict, None]] = None, tags: Optional[Union[dict, None]] = None): """ Get list of all available hardwareProfiles from the db. Returns: [hardwareProfile] Throws: DbError """ session = DbManager().openSession() try: dbHardwareProfileList = self._hardwareProfilesDbHandler.\ getHardwareProfileList(session, tags=tags) hardwareProfileList = TortugaObjectList() for dbHardwareProfile in dbHardwareProfileList: # For now expand networks self.loadRelation(dbHardwareProfile, 'hardwareprofilenetworks') self.loadRelations(dbHardwareProfile, optionDict) self.loadRelations(dbHardwareProfile, dict(tags=True)) hardwareProfileList.append( HardwareProfile.getFromDbDict(dbHardwareProfile.__dict__)) return hardwareProfileList except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def setIdleSoftwareProfile(self, hardwareProfileName, softwareProfileName=None): """ Sets the idle software profile Returns: -none- Raises: SoftwareProfileNotFound SoftwareProfileNotIdle """ session = DbManager().openSession() try: dbSoftwareProfile = SoftwareProfilesDbHandler().\ getSoftwareProfile(session, softwareProfileName) \ if softwareProfileName else None dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, hardwareProfileName) self._hardwareProfilesDbHandler.setIdleSoftwareProfile( dbHardwareProfile, dbSoftwareProfile) session.commit() except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def addHardwareProfile(self, hardwareProfile, session=None): """ Insert hardwareProfile into the db. Returns: (none) Throws: HardwareProfileAlreadyExists DbError """ # Keep local 'session' instance. If 'session' is None, # ensure transaction is committed before returning to the # caller, otherwise the caller is responsible. On exceptions, # the rollback is performed regardless. _session = session if _session is None: _session = DbManager().openSession() try: try: self._hardwareProfilesDbHandler.getHardwareProfile( _session, hardwareProfile.getName()) raise HardwareProfileAlreadyExists( 'Hardware profile [%s] already exists' % (hardwareProfile)) except HardwareProfileNotFound as ex: pass dbHardwareProfile = self.__populateHardwareProfile( _session, hardwareProfile) _session.add(dbHardwareProfile) if session is None: _session.commit() self.getLogger().info('Added hardware profile [%s]' % (dbHardwareProfile.name)) except TortugaException as ex: _session.rollback() raise except Exception as ex: _session.rollback() self.getLogger().exception('%s' % ex) raise finally: if session is None: DbManager().closeSession() def deleteHardwareProfile(self, name): """ Delete hardwareProfile from the db. Returns: None Throws: HardwareProfileNotFound DbError TortugaException """ session = DbManager().openSession() try: hwProfile = self._hardwareProfilesDbHandler.getHardwareProfile( session, name) if hwProfile.nodes: raise TortugaException( 'Unable to remove hardware profile with associated' ' nodes') # First delete the mappings hwProfile.mappedsoftwareprofiles = [] self.getLogger().debug( 'Marking hardware profile [%s] for deletion' % (name)) session.delete(hwProfile) session.commit() except TortugaException as ex: session.rollback() raise except Exception as ex: session.rollback() self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def copyHardwareProfile(self, srcHardwareProfileName, dstHardwareProfileName): session = DbManager().openSession() try: srcHardwareProfile = self.getHardwareProfile( srcHardwareProfileName, { 'admins': True, 'hardwareprofilenetworks': True, 'nics': True, 'resourceadapter': True, }) dstHardwareProfile = \ self.getHardwareProfile(srcHardwareProfileName) dstHardwareProfile.setName(dstHardwareProfileName) newDescription = 'Copy of %s' % ( dstHardwareProfile.getDescription()) dstHardwareProfile.setDescription(newDescription) dstHardwareProfile.setNetworks(srcHardwareProfile.getNetworks()) dstHardwareProfile.setProvisioningNics( srcHardwareProfile.getProvisioningNics()) dstHardwareProfile.setResourceAdapter( srcHardwareProfile.getResourceAdapter()) self.addHardwareProfile(dstHardwareProfile, session) session.commit() finally: DbManager().closeSession() def getNode(self, name): """ Get node from the db. Returns: node Throws: NodeNotFound DbError """ session = DbManager().openSession() try: return self._nodesDbHandler.getNode(session, name) except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def deleteNode(self, name): """ Delete node from the db. Returns: None Throws: NodeNotFound DbError """ session = DbManager().openSession() try: self._nodesDbHandler.deleteNode(session, name) session.commit() except TortugaException as ex: session.rollback() raise except Exception as ex: session.rollback() self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def addAdmin(self, hardwareProfileName, adminUsername): """ Add an admin to this hardware profile Raises: AdminAlreadyExists """ session = DbManager().openSession() try: dbAdmin = self._adminsDbHandler.getAdmin(session, adminUsername) dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, hardwareProfileName) if dbAdmin in dbHardwareProfile.admins: raise AdminAlreadyExists( 'The admin %s is already associated with %s.' % (adminUsername, hardwareProfileName)) dbHardwareProfile.admins.append(dbAdmin) session.commit() except TortugaException as ex: session.rollback() raise except Exception as ex: session.rollback() self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def deleteAdmin(self, hardwareProfileName, adminUsername): """ Delete an admin from a hardware profile Raises: AdminNotFound """ session = DbManager().openSession() try: dbAdmin = self._adminsDbHandler.getAdmin(session, adminUsername) dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, hardwareProfileName) if dbAdmin not in dbHardwareProfile.admins: raise AdminNotFound('Admin user [%s] not associated with %s.' % (adminUsername, hardwareProfileName)) dbHardwareProfile.admins.remove(dbAdmin) session.commit() except TortugaException as ex: session.rollback() raise except Exception as ex: session.rollback() self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def updateHardwareProfile(self, hardwareProfileObject): """ Update Hardware Profile Object """ session = DbManager().openSession() try: dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfileById(session, hardwareProfileObject.getId()) self.__populateHardwareProfile(session, hardwareProfileObject, dbHardwareProfile) session.commit() except TortugaException as ex: session.rollback() raise except Exception as ex: session.rollback() self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def __getInstallerNode(self, session): return self._nodesDbHandler.getNode(session, ConfigManager().getInstaller()) def __get_provisioning_nics(self, session): return self.__getInstallerNode(session).nics def __get_all_networks(self, session): return self._networksDbHandler.getNetworkList(session) def __get_network_devices(self, session): \ # pylint: disable=no-self-use return session.query(NetworkDevices).all() def __populateHardwareProfile(self, session, hardwareProfile, dbHardwareProfile=None): """ Helper function for creating / updating HardwareProfiles. If 'dbHardwareProfile' is specified, this is an update (vs. add) operation Raises: NicNotFound """ # Preload provisioning nics and networks prov_nics = self.__get_provisioning_nics(session) all_networks = self.__get_all_networks(session) networkdevices = self.__get_network_devices(session) # Validate hw profile if hardwareProfile.getName() is None: raise ConfigurationError('Hardware profile requires name.') if hardwareProfile.getNameFormat() is None: raise ConfigurationError( 'Hardware profile requires name format field.') # Handle the special case of a hardware profile not having an # associated idle software profile (ie. Installer hardware # profile) idleSoftwareProfileId = hardwareProfile.getIdleSoftwareProfileId() \ if hardwareProfile.getIdleSoftwareProfileId else None if dbHardwareProfile is None: dbHardwareProfile = HardwareProfiles() dbHardwareProfile.name = hardwareProfile.getName() dbHardwareProfile.description = hardwareProfile.getDescription() dbHardwareProfile.nameFormat = hardwareProfile.getNameFormat() if hardwareProfile.getInstallType() is None: if hardwareProfile.getLocation() == 'remote': dbHardwareProfile.installType = 'bootstrap' else: raise ConfigurationError( 'Hardware profile must have valid install type.') else: dbHardwareProfile.installType = hardwareProfile.\ getInstallType() if hardwareProfile.getLocation() != 'remote': dbHardwareProfile.kernel = hardwareProfile.getKernel() dbHardwareProfile.kernelParams = hardwareProfile.\ getKernelParams() dbHardwareProfile.initrd = hardwareProfile.getInitrd() dbHardwareProfile.localBootParams = hardwareProfile.\ getLocalBootParams() dbHardwareProfile.softwareOverrideAllowed = hardwareProfile.\ getSoftwareOverrideAllowed() dbHardwareProfile.idleSoftwareProfileId = idleSoftwareProfileId dbHardwareProfile.location = hardwareProfile.getLocation() dbHardwareProfile.hypervisorSoftwareProfileId = hardwareProfile.\ getHypervisorSoftwareProfileId() dbHardwareProfile.maxUnits = hardwareProfile.getMaxUnits() dbHardwareProfile.bcastEnabled = hardwareProfile.getBcastEnabled() dbHardwareProfile.mcastEnabled = hardwareProfile.getMcastEnabled() dbHardwareProfile.cost = hardwareProfile.getCost() # Add resource adapter resourceAdapter = hardwareProfile.getResourceAdapter() if resourceAdapter: dbHardwareProfile.resourceAdapter = self.\ _resourceAdaptersDbHandler.getResourceAdapter( session, resourceAdapter.getName()) dbHardwareProfile.resourceAdapterId = dbHardwareProfile.\ resourceAdapter.id # Add networks networks = [] for network in hardwareProfile.getNetworks(): for prov_network in all_networks: if prov_network.address == network.getAddress(): dbNetwork = prov_network break else: raise NetworkNotFound('Network [%s] does not exist' % (network.getAddress())) # Lookup network device for network_device in networkdevices: if network.getNetworkDevice().getName() == network_device.name: dbNetworkDevice = network_device break else: dbNetworkDevice = NetworkDevices() dbNetworkDevice.name = network.getNetworkDevice().getName() # Now check if we have this one already... for dbHardwareProfileNetwork in dbHardwareProfile.\ hardwareprofilenetworks: if dbHardwareProfileNetwork.\ networkDeviceId == dbNetworkDevice.id and \ dbHardwareProfileNetwork.networkId == dbNetwork.id: break else: dbHardwareProfileNetwork = HardwareProfileNetworks() if dbNetwork.id is not None: dbHardwareProfileNetwork.networkId = dbNetwork.id else: dbHardwareProfileNetwork.network = dbNetwork dbHardwareProfileNetwork.hardwareProfileId = \ dbHardwareProfile.id if dbNetworkDevice.id is not None: dbHardwareProfileNetwork.networkDeviceId = \ dbNetworkDevice.id else: dbHardwareProfileNetwork.networkdevice = dbNetworkDevice dbHardwareProfile.hardwareprofilenetworks.append( dbHardwareProfileNetwork) networks.append(dbHardwareProfileNetwork) # Now remove all old networks for dbNetwork in dbHardwareProfile.hardwareprofilenetworks: for network in networks: if network.networkDeviceId == dbNetwork.networkDeviceId \ and network.networkId == dbNetwork.networkId: # Its a keeper break else: # No match...delete time session.delete(dbNetwork) # Add provisioning Nics if hardwareProfile.getProvisioningNics(): # Only one provisioning nic is possible nic = hardwareProfile.getProvisioningNics()[0] for prov_nic in prov_nics: if nic.getIp() == prov_nic.ip: dbNic = prov_nic break else: raise NicNotFound('Provisioning NIC with IP [%s] not found' % (nic.getIp())) if dbNic not in dbHardwareProfile.nics: dbHardwareProfile.nics.append(dbNic) return dbHardwareProfile def getHypervisorNodes(self, hardwareProfileName): """ Get list of nodes that belong to hypervisorSoftwareProfileId assigned to the given hardware profile name. """ session = DbManager().openSession() try: dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, hardwareProfileName) if not dbHardwareProfile.hypervisor: return TortugaObjectList() return self.getTortugaObjectList( Node, dbHardwareProfile.hypervisor.nodes) except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def setProvisioningNic(self, hardwareProfileName, nicId): session = DbManager().openSession() try: dbNic = self._nicsDbHandler.getNicById(session, nicId) dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, hardwareProfileName) dbHardwareProfile.nics.append(dbNic) session.commit() except sqlalchemy.exc.IntegrityError as ex: # Entry for this hwProfile/nicId already exists, ignore self.getLogger().debug( 'setProvisioningNic(): entry already exists for' ' hwProfile=%s, nicId=%d' % (hardwareProfileName, nicId)) except TortugaException as ex: raise except Exception as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession() def getProvisioningNicForNetwork(self, network, netmask): """ Raises: NicNotFound """ session = DbManager().openSession() try: installer_node = self.__getInstallerNode(session) nics = [ dbNic for dbNic in installer_node.hardwareprofile.nics if dbNic.network.address == network and dbNic.network.netmask == netmask ] if not nics: raise NicNotFound( 'Unable to find provisioning NIC for network [%s]' ' netmask [%s]' % (network, netmask)) return tortuga.objects.nic.Nic.getFromDbDict(nics[0].__dict__) except TortugaException as ex: self.getLogger().exception('%s' % ex) raise finally: DbManager().closeSession()
class HardwareProfileDbApi(TagsDbApiMixin, TortugaDbApi): """ HardwareProfile DB API class. """ tag_model = HardwareProfileTag def __init__(self): super().__init__() self._hardwareProfilesDbHandler = HardwareProfilesDbHandler() self._nodesDbHandler = NodesDbHandler() self._globalParametersDbHandler = GlobalParametersDbHandler() self._adminsDbHandler = AdminsDbHandler() self._nicsDbHandler = NicsDbHandler() self._resourceAdaptersDbHandler = ResourceAdaptersDbHandler() self._networkDevicesDbHandler = NetworkDevicesDbHandler() self._networksDbHandler = NetworksDbHandler() def getHardwareProfile(self, session: Session, name: str, optionDict: Optional[OptionDict] = None) \ -> HardwareProfile: """ Get hardwareProfile from the db. Returns: hardwareProfile Throws: HardwareProfileNotFound DbError """ try: dbHardwareProfile = \ self._hardwareProfilesDbHandler.getHardwareProfile( session, name) self.loadRelations( dbHardwareProfile, get_default_relations(optionDict)) return HardwareProfile.getFromDbDict( dbHardwareProfile.__dict__) except TortugaException: raise except Exception as ex: self._logger.exception(str(ex)) raise def getHardwareProfileById( self, session: Session, hardwareProfileId: int, optionDict: Optional[OptionDict] = None) -> HardwareProfile: """ Get hardwareProfile from the db. Returns: hardwareProfile Throws: HardwareProfileNotFound DbError """ try: dbHardwareProfile = \ self._hardwareProfilesDbHandler.getHardwareProfileById( session, hardwareProfileId) self.loadRelations( dbHardwareProfile, get_default_relations(optionDict)) return HardwareProfile.getFromDbDict(dbHardwareProfile.__dict__) except TortugaException: raise except Exception as ex: self._logger.exception(str(ex)) raise def getHardwareProfileList( self, session: Session, optionDict: Optional[OptionDict] = None, tags: Optional[Tags] = None) -> TortugaObjectList: """ Get list of all available hardwareProfiles from the db. Returns: [hardwareProfile] Throws: DbError """ try: dbHardwareProfileList = \ self._hardwareProfilesDbHandler.getHardwareProfileList( session, tags=tags) hardwareProfileList = TortugaObjectList() for dbHardwareProfile in dbHardwareProfileList: options = dict.copy(optionDict or {}) options['hardwareprofilenetworks'] = True self.loadRelations( dbHardwareProfile, get_default_relations(options)) hardwareProfileList.append( HardwareProfile.getFromDbDict( dbHardwareProfile.__dict__)) return hardwareProfileList except TortugaException: raise except Exception as ex: self._logger.exception(str(ex)) raise def addHardwareProfile( self, session: Session, hardwareProfile: HardwareProfile) -> None: """ Insert hardwareProfile into the db. Returns: (none) Throws: HardwareProfileAlreadyExists DbError """ try: try: self._hardwareProfilesDbHandler.getHardwareProfile( session, hardwareProfile.getName()) raise HardwareProfileAlreadyExists( 'Hardware profile [%s] already exists' % ( hardwareProfile)) except HardwareProfileNotFound as ex: pass dbHardwareProfile = self.__populateHardwareProfile( session, hardwareProfile) session.add(dbHardwareProfile) session.flush() self._set_tags(dbHardwareProfile, hardwareProfile.getTags()) session.commit() self._logger.info( 'Added hardware profile [%s]' % (dbHardwareProfile.name)) except TortugaException: session.rollback() raise except Exception as ex: session.rollback() self._logger.exception(str(ex)) raise def deleteHardwareProfile(self, session: Session, name: str) -> None: """ Delete hardwareProfile from the db. Returns: None Throws: HardwareProfileNotFound DbError TortugaException """ try: hwProfile = self._hardwareProfilesDbHandler.getHardwareProfile( session, name) if hwProfile.nodes: raise TortugaException( 'Unable to delete hardware profile with associated nodes' ) # First delete the mappings hwProfile.mappedsoftwareprofiles = [] self._logger.debug( 'Marking hardware profile [%s] for deletion' % (name)) session.delete(hwProfile) session.commit() except TortugaException: session.rollback() raise except Exception as ex: session.rollback() self._logger.exception(str(ex)) raise def copyHardwareProfile(self, session: Session, srcHardwareProfileName: str, dstHardwareProfileName: str): # # Ensure the destination hardware profile doesn't already exist # try: self.getHardwareProfile(session, dstHardwareProfileName) raise TortugaException( 'Destination hardware profile already exists: {}'.format( dstHardwareProfileName) ) except HardwareProfileNotFound: pass srcHardwareProfile = self.getHardwareProfile( session, srcHardwareProfileName, { 'admins': True, 'hardwareprofilenetworks': True, 'nics': True, 'resourceadapter': True, }) dstHardwareProfile = \ self.getHardwareProfile(session, srcHardwareProfileName) dstHardwareProfile.setName(dstHardwareProfileName) newDescription = 'Copy of %s' % ( dstHardwareProfile.getDescription()) dstHardwareProfile.setDescription(newDescription) dstHardwareProfile.setNetworks(srcHardwareProfile.getNetworks()) dstHardwareProfile.setProvisioningNics( srcHardwareProfile.getProvisioningNics()) dstHardwareProfile.setResourceAdapter( srcHardwareProfile.getResourceAdapter()) self.addHardwareProfile(session, dstHardwareProfile) def addAdmin( self, session: Session, hardwareProfileName, adminUsername: str) -> None: """ Add an admin to this hardware profile Raises: AdminAlreadyExists """ try: dbAdmin = self._adminsDbHandler.getAdmin( session, adminUsername) dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, hardwareProfileName) if dbAdmin in dbHardwareProfile.admins: raise AdminAlreadyExists( 'The admin %s is already associated with %s.' % ( adminUsername, hardwareProfileName)) dbHardwareProfile.admins.append(dbAdmin) session.commit() except TortugaException: session.rollback() raise except Exception as ex: session.rollback() self._logger.exception(str(ex)) raise def deleteAdmin( self, session: Session, hardwareProfileName: str, adminUsername: str) -> None: """ Delete an admin from a hardware profile Raises: AdminNotFound """ try: dbAdmin = self._adminsDbHandler.getAdmin(session, adminUsername) dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, hardwareProfileName) if dbAdmin not in dbHardwareProfile.admins: raise AdminNotFound( 'Admin user [%s] not associated with %s.' % ( adminUsername, hardwareProfileName)) dbHardwareProfile.admins.remove(dbAdmin) session.commit() except TortugaException: session.rollback() raise except Exception as ex: session.rollback() self._logger.exception(str(ex)) raise def updateHardwareProfile( self, session: Session, hardwareProfileObject: HardwareProfile) -> None: """ Update Hardware Profile Object """ try: dbHardwareProfile = \ self._hardwareProfilesDbHandler.getHardwareProfileById( session, hardwareProfileObject.getId()) self.__populateHardwareProfile( session, hardwareProfileObject, dbHardwareProfile) self._set_tags(dbHardwareProfile, hardwareProfileObject.getTags()) session.commit() except TortugaException: session.rollback() raise except Exception as ex: session.rollback() self._logger.exception(str(ex)) raise def __getInstallerNode(self, session: Session) -> Node: return self._nodesDbHandler.getNode( session, ConfigManager().getInstaller()) def __get_provisioning_nics(self, session: Session) -> List[Nic]: return self.__getInstallerNode(session).nics def __get_all_networks(self, session: Session) -> List[Network]: return self._networksDbHandler.getNetworkList(session) def __populateHardwareProfile( self, session: Session, hardwareProfile: HardwareProfile, dbHardwareProfile: Optional[HardwareProfileModel] = None) \ -> HardwareProfileModel: """ Helper function for creating / updating hardware profiles. If 'dbHardwareProfile' is specified, this is an update (vs. add) operation Raises: NicNotFound ResourceAdapterNotFound InvalidArgument ConfigurationError """ # Preload provisioning nics and networks prov_nics = self.__get_provisioning_nics(session) all_networks = self.__get_all_networks(session) # Validate hw profile if hardwareProfile.getName() is None: raise ConfigurationError('Hardware profile requires name.') if hardwareProfile.getNameFormat() is None: raise ConfigurationError( 'Hardware profile requires name format field.') if dbHardwareProfile is None: dbHardwareProfile = HardwareProfileModel() dbHardwareProfile.name = hardwareProfile.getName() dbHardwareProfile.description = hardwareProfile.getDescription() dbHardwareProfile.nameFormat = hardwareProfile.getNameFormat() if hardwareProfile.getInstallType() is None: if hardwareProfile.getLocation() == 'remote': dbHardwareProfile.installType = 'bootstrap' else: dbHardwareProfile.installType = 'package' else: dbHardwareProfile.installType = hardwareProfile.\ getInstallType() if hardwareProfile.getLocation() != 'remote': dbHardwareProfile.kernel = hardwareProfile.getKernel() dbHardwareProfile.kernelParams = \ hardwareProfile.getKernelParams() dbHardwareProfile.initrd = hardwareProfile.getInitrd() dbHardwareProfile.localBootParams = \ hardwareProfile.getLocalBootParams() dbHardwareProfile.softwareOverrideAllowed = hardwareProfile.\ getSoftwareOverrideAllowed() dbHardwareProfile.location = hardwareProfile.getLocation() dbHardwareProfile.cost = hardwareProfile.getCost() # Add resource adapter resource_adapter_name = \ hardwareProfile.getResourceAdapter().getName() \ if hardwareProfile.getResourceAdapter() else 'default' dbHardwareProfile.resourceadapter = \ self._resourceAdaptersDbHandler.getResourceAdapter( session, resource_adapter_name) if hardwareProfile.getDefaultResourceAdapterConfig(): adapter_cfg = None self._logger.debug( 'Setting default resource adapter config: {}'.format( hardwareProfile.getDefaultResourceAdapterConfig()) ) for adapter_cfg in \ dbHardwareProfile.resourceadapter.resource_adapter_config: if adapter_cfg.name == \ hardwareProfile.getDefaultResourceAdapterConfig(): break else: raise InvalidArgument( 'Resource adapter configuration profile [{}] is' ' invalid'.format( hardwareProfile.getDefaultResourceAdapterConfig()) ) dbHardwareProfile.default_resource_adapter_config = adapter_cfg else: dbHardwareProfile.default_resource_adapter_config = None # Add networks networks = [] for network in hardwareProfile.getNetworks(): for prov_network in all_networks: if prov_network.address == network.getAddress(): dbNetwork = prov_network break else: raise NetworkNotFound( 'Network [%s] does not exist' % (network.getAddress())) dbNetworkDevice = \ self._networkDevicesDbHandler.createNetworkDeviceIfNotExists( session, network.getNetworkDevice().getName()) # Now check if we have this one already... for dbHardwareProfileNetwork in \ dbHardwareProfile.hardwareprofilenetworks: if dbHardwareProfileNetwork.networkDeviceId == \ dbNetworkDevice.id and \ dbHardwareProfileNetwork.networkId == dbNetwork.id: break else: dbHardwareProfileNetwork = HardwareProfileNetwork() dbHardwareProfileNetwork.hardwareprofile = dbHardwareProfile if dbNetwork.id is not None: dbHardwareProfileNetwork.networkId = dbNetwork.id else: dbHardwareProfileNetwork.network = dbNetwork dbHardwareProfileNetwork.hardwareProfileId = \ dbHardwareProfile.id if dbNetworkDevice.id is not None: dbHardwareProfileNetwork.networkDeviceId = \ dbNetworkDevice.id else: dbHardwareProfileNetwork.networkdevice = dbNetworkDevice dbHardwareProfile.hardwareprofilenetworks.append( dbHardwareProfileNetwork) networks.append(dbHardwareProfileNetwork) # Now remove all old networks for dbNetwork in dbHardwareProfile.hardwareprofilenetworks: for network in networks: if network.networkDeviceId == dbNetwork.networkDeviceId \ and network.networkId == dbNetwork.networkId: # Its a keeper break else: # No match...delete time session.delete(dbNetwork) # Add provisioning Nics if hardwareProfile.getProvisioningNics(): # Only one provisioning nic is possible nic = hardwareProfile.getProvisioningNics()[0] for prov_nic in prov_nics: if nic.getIp() == prov_nic.ip: dbNic = prov_nic break else: raise NicNotFound( 'Provisioning NIC with IP [%s] not found' % nic.getIp()) if dbNic not in dbHardwareProfile.nics: dbHardwareProfile.nics.append(dbNic) return dbHardwareProfile def setProvisioningNic( self, session: Session, hardwareProfileName: str, nicId: int) -> None: try: dbNic = self._nicsDbHandler.getNicById(session, nicId) dbHardwareProfile = self._hardwareProfilesDbHandler.\ getHardwareProfile(session, hardwareProfileName) dbHardwareProfile.nics.append(dbNic) session.commit() except sqlalchemy.exc.IntegrityError as ex: # Entry for this hwProfile/nicId already exists, ignore self._logger.debug( 'setProvisioningNic(): entry already exists for' ' hwProfile=%s, nicId=%d' % (hardwareProfileName, nicId)) except TortugaException: raise except Exception as ex: self._logger.exception(str(ex)) raise def getProvisioningNicForNetwork( self, session: Session, network: str, netmask: str) -> Nic: """ Raises: NicNotFound """ try: installer_node = self.__getInstallerNode(session) nics = [ dbNic for dbNic in installer_node.hardwareprofile.nics if dbNic.network.address == network and dbNic.network.netmask == netmask] if not nics: raise NicNotFound( 'Unable to find provisioning NIC for network [%s]' ' netmask [%s]' % (network, netmask)) return tortuga.objects.nic.Nic.getFromDbDict(nics[0].__dict__) except TortugaException as ex: self._logger.exception(str(ex)) raise
def validate_addnodes_request(addNodesRequest): """ Raises: HardwareProfileNotFound SoftwareProfileNotFound ProfileMappingNotAllowed InvalidArgument """ if 'hardwareProfile' not in addNodesRequest and \ 'softwareProfile' not in addNodesRequest: raise InvalidArgument( 'Hardware and/or software profile must be specified') hpapi = HardwareProfilesDbHandler() spapi = SoftwareProfilesDbHandler() hardwareProfileName = addNodesRequest['hardwareProfile'] \ if 'hardwareProfile' in addNodesRequest else None nodeDetails = addNodesRequest.get('nodeDetails', []) softwareProfileName = addNodesRequest['softwareProfile'] \ if 'softwareProfile' in addNodesRequest else None nodeCount = int(addNodesRequest.get('count', 0)) rackNumber = addNodesRequest.get('rack') session = DbManager().openSession() try: # Look up hardware profile hp = hpapi.getHardwareProfile(session, hardwareProfileName) \ if hardwareProfileName else None # Look up software profile sp = spapi.getSoftwareProfile( session, softwareProfileName) if softwareProfileName else None if sp and not sp.isIdle and 'isIdle' in addNodesRequest and \ addNodesRequest['isIdle']: raise InvalidArgument( 'Software profile [%s] is not idle software profile' % (softwareProfileName)) # Make sure that if a software profile is given that it is allowed # to be used with the given hardware profile if sp is not None and hp is not None: checkProfilesMapped(sp, hp) elif sp is not None and hp is None: if not sp.hardwareprofiles: raise InvalidArgument( 'Software profile [{0}] is not mapped to any hardware' ' profiles'.format(softwareProfileName)) if len(sp.hardwareprofiles) > 1: raise InvalidArgument( 'Ambiguous request: multiple hardware profiles are' ' mapped to software profile [{0}]'.format( softwareProfileName)) hp = sp.hardwareprofiles[0] elif hp is not None and sp is None and not addNodesRequest['isIdle']: if not hp.mappedsoftwareprofiles: raise InvalidArgument( 'Hardware profile [{0}] is not mapped to any software' ' profiles'.format(hardwareProfileName)) if len(hp.mappedsoftwareprofiles) > 1: raise InvalidArgument( 'Ambiguous request: multiple software profiles are' ' mapped to hardware profile [{0}]'.format( hardwareProfileName)) sp = hp.mappedsoftwareprofiles[0] # Ensure user does not make a request for DHCP discovery mode. # Currently, this is determined by the presence of the item # 'nodeDetails' in addNodesRequest. Ultimately, this should be # shared code between here and the default resource adapter. if hp.resourceadapter and \ hp.resourceadapter.name == 'default' and not nodeDetails: raise InvalidArgument( 'DHCP discovery is not available through WS API.') if sp and 'softwareProfile' not in addNodesRequest: addNodesRequest['softwareProfile'] = sp.name if 'hardwareProfile' not in addNodesRequest: addNodesRequest['hardwareProfile'] = hp.name # Validate 'nodeDetails' if nodeDetails: # Reconcile nodeDetails that contain hostnames with hwp name # format bWildcardNameFormat = hp.nameFormat == '*' hostname = nodeDetails[0]['name'] \ if 'name' in nodeDetails[0] else None if hostname and not bWildcardNameFormat: # Host name specified, but hardware profile does not # allow setting the host name raise InvalidArgument('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 InvalidArgument('Hardware profile requires imported node' ' name to be set') if nodeCount > 0 and nodeCount != len(nodeDetails): raise InvalidArgument('Node count must be equal to number' ' of MAC/IP/node names provided') if hostname: # Ensure host does not already exist existing_node = session.query(Nodes).filter( Nodes.name == hostname).first() if existing_node: raise NodeAlreadyExists('Node [%s] already exists' % (hostname)) # Prohibit running add-host against installer validate_hwprofile(hp) # If the given hardwareProfile's nameFormat contains "#R', # then the rackNumber is required. nameFormat = hp.nameFormat if nameFormat.find('#R') != -1 and rackNumber is None: raise InvalidArgument( 'Missing "rackNumber" for name format [%s] of' ' hardware profile [%s]' % (nameFormat, hp)) adapter = resourceAdapterFactory.getApi(hp.resourceadapter.name) adapter.validate_start_arguments(addNodesRequest, hp, dbSoftwareProfile=sp) finally: DbManager().closeSession()
def validate_addnodes_request(session: Session, addNodesRequest: Dict[str, Any]): """ Raises: HardwareProfileNotFound SoftwareProfileNotFound ProfileMappingNotAllowed InvalidArgument OperationFailed """ if 'hardwareProfile' not in addNodesRequest and \ 'softwareProfile' not in addNodesRequest: raise InvalidArgument( 'Hardware and/or software profile must be specified') hpapi = HardwareProfilesDbHandler() spapi = SoftwareProfilesDbHandler() hardwareProfileName = addNodesRequest['hardwareProfile'] \ if 'hardwareProfile' in addNodesRequest else None nodeDetails = addNodesRequest.get('nodeDetails', []) softwareProfileName = addNodesRequest['softwareProfile'] \ if 'softwareProfile' in addNodesRequest else None nodeCount = int(addNodesRequest.get('count', 0)) rackNumber = addNodesRequest.get('rack') # Look up hardware profile hp = hpapi.getHardwareProfile(session, hardwareProfileName) \ if hardwareProfileName else None # Look up software profile sp = spapi.getSoftwareProfile( session, softwareProfileName) if softwareProfileName else None # Make sure that if a software profile is given that it is allowed # to be used with the given hardware profile if sp is not None and hp is not None: checkProfilesMapped(sp, hp) elif sp is not None and hp is None: if not sp.hardwareprofiles: raise InvalidArgument( 'Software profile [{0}] is not mapped to any hardware' ' profiles'.format(softwareProfileName)) if len(sp.hardwareprofiles) > 1: raise InvalidArgument( 'Ambiguous request: multiple hardware profiles are' ' mapped to software profile [{0}]'.format( softwareProfileName)) hp = sp.hardwareprofiles[0] elif hp is not None and sp is None: if not hp.mappedsoftwareprofiles: raise InvalidArgument( 'Hardware profile [{0}] is not mapped to any software' ' profiles'.format(hardwareProfileName)) if len(hp.mappedsoftwareprofiles) > 1: raise InvalidArgument( 'Ambiguous request: multiple software profiles are' ' mapped to hardware profile [{0}]'.format( hardwareProfileName)) sp = hp.mappedsoftwareprofiles[0] if sp and 'softwareProfile' not in addNodesRequest: addNodesRequest['softwareProfile'] = sp.name if 'hardwareProfile' not in addNodesRequest: addNodesRequest['hardwareProfile'] = hp.name swprofile_node_count = len(sp.nodes) # Validate 'nodeDetails' if nodeDetails: # Reconcile nodeDetails that contain hostnames with hwp name # format bWildcardNameFormat = hp.nameFormat == '*' hostname = nodeDetails[0]['name'] \ if 'name' in nodeDetails[0] else None if hostname and not bWildcardNameFormat: # Host name specified, but hardware profile does not # allow setting the host name raise InvalidArgument('Hardware profile does not allow setting' ' host names of imported nodes') if nodeCount > 0 and nodeCount != len(nodeDetails): raise InvalidArgument('Node count must be equal to number' ' of MAC/IP/node names provided') # check if software profile is locked if sp.lockedState: if sp.lockedState == 'HardLocked': raise OperationFailed( 'Nodes cannot be added to hard locked software' ' profile [{}]'.format(sp.name)) elif sp.lockedState == 'SoftLocked': if 'force' not in addNodesRequest or \ not addNodesRequest['force']: raise OperationFailed( 'Use --force argument to add nodes to soft locked' f' software profile [{sp.name}]') # ensure adding nodes does not exceed imposed limits if sp.maxNodes > 0 and \ (swprofile_node_count + nodeCount) > sp.maxNodes: raise OperationFailed( 'Request to add {} node(s) exceeds software profile' ' limit of {} nodes'.format(nodeCount, sp.maxNodes)) # Prohibit running add-host against installer validate_hwprofile(hp) # If the given hardwareProfile's nameFormat contains "#R', # then the rackNumber is required. nameFormat = hp.nameFormat if nameFormat.find('#R') != -1 and rackNumber is None: raise InvalidArgument('Missing "rackNumber" for name format [%s] of' ' hardware profile [%s]' % (nameFormat, hp)) adapter = resourceAdapterFactory.get_api(hp.resourceadapter.name) adapter.session = session adapter.validate_start_arguments(addNodesRequest, hp, dbSoftwareProfile=sp)