Пример #1
0
    def _validate_add_count(self, sess: Session, swp_name: str, count: int):
        """
        See validate_add_count.

        """
        swp_api = SoftwareProfilesDbHandler()
        swp = swp_api.getSoftwareProfile(sess, swp_name)

        if swp.maxNodes <= 0:
            return
        current_count = len(swp.nodes)
        request_count = self._count_current_node_requests(sess, swp)

        if current_count + request_count + count > swp.maxNodes:
            raise OperationFailed(
                'Request to add {} node(s) exceeds software profile'
                ' limit of {} nodes'.format(count, swp.maxNodes))
Пример #2
0
class SoftwareProfileDbApi(TagsDbApiMixin, TortugaDbApi):
    """
    SoftwareProfile DB API class.

    """
    tag_model = SoftwareProfileTag

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

        self._softwareProfilesDbHandler = SoftwareProfilesDbHandler()
        self._globalParametersDbHandler = GlobalParametersDbHandler()
        self._adminsDbHandler = AdminsDbHandler()
        self._osDbHandler = OperatingSystemsDbHandler()

    def getSoftwareProfile(
            self,
            session,
            name: str,
            optionDict: Optional[Dict[str, bool]] = None) -> SoftwareProfile:
        """
        Get softwareProfile from the db.

            Returns:
               softwareProfile
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        try:
            dbSoftwareProfile = \
                self._softwareProfilesDbHandler.getSoftwareProfile(
                    session, name)

            return self.__get_software_profile_obj(dbSoftwareProfile,
                                                   options=optionDict)
        except TortugaException:
            raise
        except Exception as ex:
            self._logger.exception(str(ex))
            raise

    def __get_software_profile_obj(
            self,
            software_profile: SoftwareProfileModel,
            options: Optional[dict] = None) -> SoftwareProfile:
        """
        Deserialize SQLAlchemy object to TortugaObject
        """
        self.loadRelations(software_profile, options)

        self.loadRelations(software_profile, dict(tags=True))

        # if 'components' is specified, ensure 'kit' relationship is
        # also serialized
        if options and 'components' in options and options['components']:
            for component in software_profile.components:
                self.loadRelation(component, 'kit')

        software_profile_obj = SoftwareProfile.getFromDbDict(
            software_profile.__dict__)

        return software_profile_obj

    def getSoftwareProfileById(
            self,
            session: Session,
            softwareProfileId: int,
            optionDict: Optional[Dict[str, bool]] = None) -> SoftwareProfile:
        """
        Get softwareProfile from the db.

            Returns:
               softwareProfile
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        try:
            dbSoftwareProfile = \
                self._softwareProfilesDbHandler.getSoftwareProfileById(
                    session, softwareProfileId)

            return self.__get_software_profile_obj(dbSoftwareProfile,
                                                   options=optionDict)
        except TortugaException:
            raise
        except Exception as ex:
            self._logger.exception(str(ex))
            raise

    def getSoftwareProfileList(self, session: Session, tags=None):
        """
        Get list of all available softwareProfiles from the db.

            Returns:
                [softwareProfile]
            Throws:
                DbError
        """

        try:
            dbSoftwareProfileList = \
                self._softwareProfilesDbHandler.getSoftwareProfileList(
                    session, tags=tags)

            softwareProfileList = TortugaObjectList()

            for dbSoftwareProfile in dbSoftwareProfileList:
                softwareProfileList.append(
                    self.__get_software_profile_obj(dbSoftwareProfile,
                                                    options={
                                                        'components': True,
                                                        'partitions': True,
                                                        'hardwareprofiles':
                                                        True,
                                                        'tags': True,
                                                    }))

            return softwareProfileList
        except TortugaException:
            raise
        except Exception as ex:
            self._logger.exception(str(ex))
            raise

    def addSoftwareProfile(
            self, session: Session,
            softwareProfile: SoftwareProfile) -> SoftwareProfileModel:
        """
        Insert software profile into the db.

        Raises:
            SoftwareProfileAlreadyExists
            DbError
        """

        try:
            try:
                dbSoftwareProfile = self._softwareProfilesDbHandler.\
                    getSoftwareProfile(
                        session, softwareProfile.getName())

                raise SoftwareProfileAlreadyExists(
                    'Software profile [%s] already exists' % (softwareProfile))
            except SoftwareProfileNotFound as ex:
                pass

            dbSoftwareProfile = self.__populateSoftwareProfile(
                session, softwareProfile)

            session.query(func.max(SoftwareProfileModel.id)).one()

            softwareProfile.setId(dbSoftwareProfile.id)

            self._logger.info('Added software profile [%s]' %
                              (dbSoftwareProfile.name))

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

    def deleteSoftwareProfile(self, session: Session, name: str) -> None:
        """
        Delete softwareProfile from the db.

            Returns:
                None
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        try:
            # This role of this lookup is twofold.  One, it validates
            # the existence of the software profile to be deleted and
            # second, gets the id for looking up any associated nodes
            dbSwProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, name)

            if dbSwProfile.nodes:
                # The software profile cannot be removed while
                # associated
                # nodes exist
                raise TortugaException('Unable to delete software profile with'
                                       ' associated nodes')

            # Proceed with software profile deletion
            self._logger.debug('Marking software profile [%s] for deletion' %
                               (name))

            session.delete(dbSwProfile)

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

    def getAllEnabledComponentList(self,
                                   session: Session) -> TortugaObjectList:
        """
        Get a list of all enabled components in the system

            Returns:
                [ components ]
            Throws:
                DbError
        """

        self._logger.debug('Retrieving enabled component list')

        try:
            dbComponents = \
                ComponentsDbHandler().getEnabledComponentList(session)

            return self.getTortugaObjectList(Component, dbComponents)
        except TortugaException:
            raise
        except Exception as ex:
            self._logger.exception(str(ex))
            raise

    def getEnabledComponentList(self, session: Session,
                                name: str) -> TortugaObjectList:
        """
        Get a list of enabled components from the db.

            Returns:
                node
            Throws:
                DbError
        """

        try:
            componentList = TortugaObjectList()

            for c in self._softwareProfilesDbHandler.getSoftwareProfile(
                    session, name).components:
                self.loadRelation(c, 'kit')

                componentList.append(Component.getFromDbDict(c.__dict__))

            return componentList
        except TortugaException:
            raise
        except Exception as ex:
            self._logger.exception(str(ex))
            raise

    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 getPartitionList(
            self, session: Session, softwareProfileName: str) \
            -> TortugaObjectList:
        """
        Get a list of software profile partitions from the db.

            Returns:
                [partition]
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        try:
            dbSoftwareProfile = \
                self._softwareProfilesDbHandler.getSoftwareProfile(
                    session, softwareProfileName)

            return self.getTortugaObjectList(Partition,
                                             dbSoftwareProfile.partitions)
        except TortugaException:
            raise
        except Exception as ex:
            self._logger.exception(str(ex))
            raise

    def addPartition(self, session: Session, partitionName: str,
                     softwareProfileName: str) -> None:
        """
        Add software profile partition.

            Returns:
                partitionId
            Throws:
                PartitionAlreadyExists
                SoftwareProfileNotFound
        """

        try:
            self._softwareProfilesDbHandler.addPartitionToSoftwareProfile(
                session, partitionName, softwareProfileName)

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

    def deletePartition(self, session: Session, partitionName: str,
                        softwareProfileName: str) -> None:
        """
        Delete node from the db.

            Returns:
                None
            Throws:
                PartitionNotFound
                SoftwareProfileNotFound
                DbError
        """

        try:
            self._softwareProfilesDbHandler.deletePartitionFromSoftwareProfile(
                session, partitionName, softwareProfileName)

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

    def addUsableHardwareProfileToSoftwareProfile(
            self, session: Session, hardwareProfileName: str,
            softwareProfileName: str) -> None:
        """
         Add hardwareProfile to softwareProfile

            Returns:
                SoftwareUsesHardwareId
            Throws:
                HardwareProfileNotFound
                SoftwareProfileNotFound
                SoftwareUsesHardwareAlreadyExists
                DbError
        """

        try:
            self._softwareProfilesDbHandler.addUsableHardwareProfileToSoftwareProfile(
                session, hardwareProfileName, softwareProfileName)

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

    def deleteUsableHardwareProfileFromSoftwareProfile(
            self, session: Session, hardwareProfileName: str,
            softwareProfileName: str) -> None:
        """
        Delete hardwareProfile from softwareProfile

            Returns:
                None
            Throws:
                HardwareProfileNotFound
                SoftwareProfileNotFound
                SoftwareUsesHardwareNotFound
                DbError
        """

        try:
            self._softwareProfilesDbHandler.\
                deleteUsableHardwareProfileFromSoftwareProfile(
                    session, hardwareProfileName, softwareProfileName)

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

    def addAdmin(self, session: Session, softwareProfileName: str,
                 adminUsername: str) -> None:
        """
        Add an admin to this software profile

        Raises:
            AdminAlreadyExists
        """

        try:
            dbAdmin = self._adminsDbHandler.getAdmin(session, adminUsername)

            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, softwareProfileName)

            if dbAdmin not in dbSoftwareProfile.admins:
                dbSoftwareProfile.admins.append(dbAdmin)
            else:
                raise AdminAlreadyExists(
                    'Admin [%s] already associated with %s' %
                    (adminUsername, softwareProfileName))

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

    def deleteAdmin(self, session: Session, softwareProfileName: str,
                    adminUsername: str) -> None:
        """
        Delete an admin from a software profile
        """

        try:
            dbAdmin = self._adminsDbHandler.getAdmin(session, adminUsername)

            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, softwareProfileName)

            if dbAdmin in dbSoftwareProfile.admins:
                dbSoftwareProfile.admins.remove(dbAdmin)
            else:
                raise AdminNotFound(
                    'Admin [%s] not associated with software profile'
                    ' [%s]' % (adminUsername, softwareProfileName))

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

    def updateSoftwareProfile(self, session: Session,
                              softwareProfileObject: SoftwareProfile) -> None:
        """
        Update a software profile
        """

        try:
            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfileById(
                    session, softwareProfileObject.getId())

            self.__populateSoftwareProfile(session, softwareProfileObject,
                                           dbSoftwareProfile)

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

    def __populateSoftwareProfile(
            self, session: Session, softwareProfile: SoftwareProfile,
            dbSoftwareProfile: Optional[SoftwareProfileModel] = None) \
            -> SoftwareProfileModel:
        """
        Helper function for creating/updating dbSoftwareProfile Object
        """

        # Validate object
        if softwareProfile.getName() is None:
            raise UpdateSoftwareProfileFailed('Software profile name required')

        if softwareProfile.getType() is None:
            raise UpdateSoftwareProfileFailed(
                'Software profile must have valid type')

        osInfo = softwareProfile.getOsInfo()
        if osInfo is None or osInfo.getName() is None:
            raise UpdateSoftwareProfileFailed(
                'Software profile must have valid operating system')

        if dbSoftwareProfile is None:
            dbSoftwareProfile = SoftwareProfileModel()

        dbOs = self._osDbHandler.addOsIfNotFound(session, osInfo)

        dbSoftwareProfile.name = softwareProfile.getName()
        dbSoftwareProfile.description = softwareProfile.getDescription()
        dbSoftwareProfile.kernel = softwareProfile.getKernel()
        dbSoftwareProfile.kernelParams = softwareProfile.getKernelParams()
        dbSoftwareProfile.initrd = softwareProfile.getInitrd()
        dbSoftwareProfile.os = dbOs
        dbSoftwareProfile.type = softwareProfile.getType()
        dbSoftwareProfile.minNodes = softwareProfile.getMinNodes()
        dbSoftwareProfile.maxNodes = softwareProfile.getMaxNodes()
        dbSoftwareProfile.lockedState = softwareProfile.getLockedState()
        dbSoftwareProfile.dataRoot = softwareProfile.getDataRoot()
        dbSoftwareProfile.dataRsync = softwareProfile.getDataRsync()

        # Add partitions
        partitions: Dict[Tuple[str, str], Partition] = {}
        for partition in softwareProfile.getPartitions():
            # This is a new partition
            dbPartition = PartitionModel()

            dbPartition.name = partition.getName()
            dbPartition.device = partition.getDevice()
            dbPartition.mountPoint = partition.getMountPoint()
            dbPartition.fsType = partition.getFsType()
            dbPartition.size = partition.getSize()
            dbPartition.options = partition.getOptions()
            dbPartition.preserve = partition.getPreserve()
            dbPartition.bootLoader = partition.getBootLoader()
            dbPartition.diskSize = partition.getDiskSize()
            dbPartition.directAttachment = partition.getDirectAttachment()
            dbPartition.indirectAttachment = partition.\
                getIndirectAttachment()
            dbPartition.sanVolume = partition.getSanVolume()

            if not dbPartition.name:
                raise InvalidPartitionScheme(
                    'Invalid partition in software profile:'
                    ' missing or empty name')

            if not dbPartition.device:
                raise InvalidPartitionScheme(
                    'Invalid partition in software profile:'
                    ' missing or empty device')

            if not dbPartition.fsType:
                raise InvalidPartitionScheme(
                    'Invalid partition [%s/%s] in software profile:'
                    ' missing or empty fsType' %
                    (dbPartition.name, dbPartition.device))

            if dbPartition.size is None:
                raise InvalidPartitionScheme(
                    'Invalid partition [%s/%s] in software profile:'
                    ' missing size' % (dbPartition.name, dbPartition.device))

            if partitions.get(
                (dbPartition.name, dbPartition.device)) is not None:
                # Duplicate partition ...error
                raise UpdateSoftwareProfileFailed(
                    'Duplicate partition [%s/%s] found' %
                    (dbPartition.name, dbPartition.device))

            try:
                int(dbPartition.size)
            except ValueError:
                raise InvalidPartitionScheme(
                    'Invalid partition [%s/%s] in software profile:'
                    ' non-integer size' %
                    (dbPartition.name, dbPartition.device))

            try:
                if dbPartition.diskSize is not None:
                    int(dbPartition.diskSize)
            except ValueError:
                raise InvalidPartitionScheme(
                    'Invalid partition [%s/%s] in software profile:'
                    ' non-integer disk size' %
                    (dbPartition.name, dbPartition.device))

            bGrow = partition.getGrow()
            if bGrow is not None:
                dbPartition.grow = bGrow

            maxSize = partition.getMaxSize()
            if maxSize is not None:
                dbPartition.maxSize = maxSize

            partitions[(dbPartition.name, dbPartition.device)] = \
                dbPartition

        # Delete out the old ones
        dbSoftwareProfile.partitions = []

        session.flush()

        dbSoftwareProfile.partitions = list(partitions.values())
        self._set_tags(dbSoftwareProfile, softwareProfile.getTags())

        session.add(dbSoftwareProfile)
        session.flush()

        return dbSoftwareProfile

    def copySoftwareProfile(self, session: Session,
                            srcSoftwareProfileName: str,
                            dstSoftwareProfileName: str) -> None:
        src_swprofile = self._softwareProfilesDbHandler.getSoftwareProfile(
            session, srcSoftwareProfileName)

        dst_swprofile = SoftwareProfileModel(
            name=dstSoftwareProfileName,
            description='Copy of %s' % (src_swprofile.description),
            kernel=src_swprofile.kernel,
            kernelParams=src_swprofile.kernelParams,
            initrd=src_swprofile.initrd,
            type=src_swprofile.type,
            minNodes=src_swprofile.minNodes,
            maxNodes=src_swprofile.maxNodes,
            lockedState=src_swprofile.lockedState,
            dataRoot=src_swprofile.dataRoot,
            dataRsync=src_swprofile.dataRsync)

        # os
        dst_swprofile.os = src_swprofile.os

        # admins
        for admin in src_swprofile.admins:
            dst_swprofile.admins.append(admin)

        # partitions
        for partition in src_swprofile.partitions:
            dst_swprofile.partitions.append(partition)

        # components
        for component in src_swprofile.components:
            dst_swprofile.components.append(component)

        # tags
        for tag in src_swprofile.tags:
            dst_swprofile.tags.append(tag)

        # kitsources
        for kitsource in src_swprofile.kitsources:
            dst_swprofile.kitsources.append(kitsource)

        # hardwareprofiles
        for hwprofile in src_swprofile.hardwareprofiles:
            dst_swprofile.hardwareprofiles.append(hwprofile)

        session.add(dst_swprofile)

        session.commit()

    def getUsableNodes(self, session: Session, name: str) \
            -> TortugaObjectList:
        """
        Return list of nodes with same software/hardware profile mapping
        as the specified software profile.
        """

        try:
            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, name)

            nodes = [
                dbNode
                for dbHardwareProfile in dbSoftwareProfile.hardwareprofiles
                for dbNode in dbHardwareProfile.nodes
            ]

            return self.getTortugaObjectList(Node, nodes)
        except TortugaException:
            raise
        except Exception as ex:
            self._logger.exception(str(ex))
            raise
Пример #3
0
class NodesDbHandler(TortugaDbObjectHandler):
    """
    This class handles nodes table.
    """
    def __init__(self):
        super().__init__()

        self._softwareProfilesDbHandler = SoftwareProfilesDbHandler()

    def getNode(self, session: Session, name: str) -> Node:
        """
        Return node.

        Raises:
            NodeNotFound
        """

        try:
            if '.' in name:
                # Attempt exact match on fully-qualfied name
                return session.query(Node).filter(
                    func.lower(Node.name) == name.lower()).one()

            # 'name' is short host name; attempt to match on either short
            # host name or any host starting with same host name
            return session.query(Node).filter(
                or_(
                    func.lower(Node.name) == name.lower(),
                    func.lower(Node.name).like(name.lower() + '.%'))).one()
        except NoResultFound:
            raise NodeNotFound("Node [%s] not found" % (name))

    def get_installer_node(self, session: Session) -> Node:
        """
        Return installer node derived from searching for all software
        profiles with type 'installer'.

        Raises:
            NodeNotFound
        """

        installer_swprofiles = \
            SoftwareProfilesDbHandler().getSoftwareProfileList(
                session,
                profile_type='installer'
            )

        if not installer_swprofiles:
            raise NodeNotFound('No installer software profiles found')

        installer_nodes = installer_swprofiles[0].nodes
        if not installer_nodes:
            raise NodeNotFound(
                'No installer node found in software profile {}'.format(
                    installer_swprofiles[0].name))

        return installer_nodes[0]

    def getNodesByTags(self, session: Session, tags: Optional[Tags] = None):
        """
        Gets nodes by tag(s). Tags is a dictionary of key/value pairs to
        match against.

        :param session: a SQLAlchemy database session
        :param tags:    a dictionary of key/value tag pairs

        :return: a list of nodes

        """
        searchspec = []

        # iterate over list of tag tuples making SQLAlchemy search
        # specification
        if tags:
            for name, value in tags.items():
                if value:
                    #
                    # Match both name and value
                    #
                    searchspec.append(
                        and_(Node.tags.any(name=name),
                             Node.tags.any(value=value)))
                else:
                    #
                    # Match name only
                    #
                    searchspec.append(Node.tags.any(name=name))

        return session.query(Node).filter(or_(*searchspec)).all()

    def getNodesByAddHostSession(self, session: Session, ahSession: str) \
            -> List[Node]:
        """
        Get nodes by add host session
        Returns a list of nodes
        """

        self._logger.debug('getNodesByAddHostSession(): ahSession [%s]' %
                           (ahSession))

        return session.query(Node).filter(
            Node.addHostSession == ahSession).order_by(Node.name).all()

    def getNodesByNameFilter(
            self,
            session: Session,
            filter_spec: Union[str, list],
            include_installer: Optional[bool] = True) -> List[Node]:
        """
        Filter follows SQL "LIKE" semantics (ie. "something%")

        Exclude installer node from node list by setting
        'include_installer' to False.

        Returns a list of Node
        """

        filter_spec_list = [filter_spec] \
            if not isinstance(filter_spec, list) else filter_spec

        node_filter = []

        for filter_spec_item in filter_spec_list:
            if '.' not in filter_spec_item:
                # Match exactly (ie. "hostname-01")
                node_filter.append(Node.name.like(filter_spec_item))

                # Match host name only (ie. "hostname-01.%")
                node_filter.append(Node.name.like(filter_spec_item + '.%'))

                continue

            # Match fully-qualified node names exactly
            # (ie. "hostname-01.domain")
            node_filter.append(Node.name.like(filter_spec_item))

        if not include_installer:
            installer_fqdn = getfqdn()

            return session.query(Node).filter(
                and_(Node.name != installer_fqdn, or_(*node_filter))).all()

        return session.query(Node).filter(or_(*node_filter)).all()

    def getNodeById(self, session: Session, _id: int) -> Node:
        """
        Return node.

        Raises:
            NodeNotFound
        """

        self._logger.debug('Retrieving node by ID [%s]' % (_id))

        dbNode = session.query(Node).get(_id)

        if not dbNode:
            raise NodeNotFound('Node ID [%s] not found.' % (_id))

        return dbNode

    def getNodeByIp(self, session: Session, ip: str) -> Node:
        """
        Raises:
            NodeNotFound
        """

        self._logger.debug('Retrieving node by IP [%s]' % (ip))

        try:
            return session.query(Node).join(Nic).filter(Nic.ip == ip).one()
        except NoResultFound:
            raise NodeNotFound('Node with IP address [%s] not found.' % (ip))

    def getNodeList(self,
                    session: Session,
                    softwareProfile: Optional[str] = None,
                    tags: Optional[Tags] = None) -> List[Node]:
        """
        Get sorted list of nodes from the db.

        Raises:
            SoftwareProfileNotFound
        """

        self._logger.debug('getNodeList()')

        if softwareProfile:
            dbSoftwareProfile = \
                self._softwareProfilesDbHandler.getSoftwareProfile(
                    session, softwareProfile)

            return dbSoftwareProfile.nodes

        searchspec = []

        if tags:
            for name, value in dict(tags).items():
                if value:
                    #
                    # Match both name and value
                    #
                    searchspec.append(
                        and_(Node.tags.any(name=name),
                             Node.tags.any(value=value)))
                else:
                    #
                    # Match name only
                    #
                    searchspec.append(Node.tags.any(name=name))

        return session.query(Node).filter(or_(*searchspec)).order_by(
            Node.name).all()

    def getNodeListByNodeStateAndSoftwareProfileName(
            self, session: Session, nodeState: str,
            softwareProfileName: str) -> List[Node]:
        """
        Get list of nodes from the db.
        """

        self._logger.debug('Retrieving nodes with state [%s] from software'
                           ' profile [%s]' % (nodeState, softwareProfileName))

        return session.query(Node).join(SoftwareProfile).filter(
            and_(SoftwareProfile.name == softwareProfileName,
                 Node.state == nodeState)).all()

    def getNodesByNodeState(self, session: Session, state: str) -> List[Node]:
        return session.query(Node).filter(Node.state == state).all()

    def getNodesByMac(self, session: Session, usedMacList: List[str]) \
            -> List[Node]:
        if not usedMacList:
            return []

        return session.query(Node).join(Nic).filter(
            Nic.mac.in_(usedMacList)).all()

    def build_node_filterspec(self, nodespec: str) -> List[str]:
        filter_spec = []

        for nodespec_token in nodespec.split(','):
            # Convert shell-style wildcards into SQL wildcards
            if '*' in nodespec_token or '?' in nodespec_token:
                filter_spec.append(
                    nodespec_token.replace('*', '%').replace('?', '_'))

                continue

            if '.' not in nodespec_token:
                filter_spec.append(nodespec_token)
                filter_spec.append(nodespec_token + '.%')

                continue

            # Add nodespec "AS IS"
            filter_spec.append(nodespec_token)

        return filter_spec

    def expand_nodespec(self, session: Session, nodespec: str,
                        include_installer: Optional[bool] = True) \
            -> List[Node]:
        """
        Expand command-line nodespec (ie. "compute*") to list of nodes
        """

        return self.getNodesByNameFilter(session,
                                         self.build_node_filterspec(nodespec),
                                         include_installer=include_installer)
Пример #4
0
class ComponentDbApi(TortugaDbApi):
    """
    Component DB API class.
    """
    def __init__(self):
        TortugaDbApi.__init__(self)

        self._softwareProfilesDbHandler = SoftwareProfilesDbHandler()
        self._componentsDbHandler = ComponentsDbHandler()

    def getComponent(self, session: Session, name: str, version: str,
                     osInfo: OsInfo,
                     optionDict: Optional[Union[dict, None]] = None) \
            -> Component:
        """
        Get component from the db.

            Returns:
                component
            Throws:
                ComponentNotFound
                DbError
        """
        try:
            dbComponent = self._componentsDbHandler.getComponentByOsInfo(
                session, name, version, osInfo)

            self.loadRelations(dbComponent, optionDict)

            return Component.getFromDbDict(dbComponent.__dict__)
        except TortugaException:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise

    def getBestMatchComponent(self, session: Session, name, version, osInfo,
                              kitId):
        """
        Get component from the db.

            Returns:
                component
            Throws:
                ComponentNotFound
                DbError
        """

        try:
            dbComponent = self._componentsDbHandler.getBestMatchComponent(
                session, name, version, osInfo, kitId)

            self.loadRelations(
                dbComponent, {
                    'os': True,
                    'family': True,
                    'kit': True,
                    'os_components': True,
                    'osfamily_components': True,
                })

            return Component.getFromDbDict(dbComponent.__dict__)
        except TortugaException:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise

    def addComponentToSoftwareProfile(self, session: Session, componentId,
                                      softwareProfileId):
        """
        Add component to softwareProfile.

            Returns:
                None
            Throws:
                SoftwareProfileNotFound
                ComponentNotFound
                SoftwareProfileComponentAlreadyExists
                DbError
        """

        try:
            self._softwareProfilesDbHandler.addComponentToSoftwareProfile(
                session, componentId, softwareProfileId)

            session.commit()
        except TortugaException:
            session.rollback()
            raise
        except Exception as ex:
            session.rollback()
            self.getLogger().exception('%s' % ex)
            raise

    def deleteComponentFromSoftwareProfile(self, session: Session, componentId,
                                           softwareProfileId):
        """
        Delete component to software profile.

            Returns:
                None
            Throws:
                SoftwareProfileNotFound
                ComponentNotFound
                SoftwareProfileComponentNotFound
                DbError
        """

        try:
            self._softwareProfilesDbHandler.\
                deleteComponentFromSoftwareProfile(
                    session, componentId, softwareProfileId)

            session.commit()
        except TortugaException:
            session.rollback()
            raise
        except Exception as ex:
            session.rollback()
            self.getLogger().exception('%s' % ex)
            raise

    def getComponentList(self, session: Session, softwareProfile=None):
        try:
            if softwareProfile:
                return self._softwareProfilesDbHandler.getSoftwareProfile(
                    session, softwareProfile).components

            # List all components
            self.getLogger().debug('Retrieving component list')

            dbComps = self._componentsDbHandler.getComponentList(session)

            return self.getTortugaObjectList(Component, dbComps)
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
Пример #5
0
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()
Пример #6
0
class SoftwareProfileDbApi(TortugaDbApi):
    """
    SoftwareProfile DB API class.
    """
    def __init__(self):
        TortugaDbApi.__init__(self)

        self._softwareProfilesDbHandler = SoftwareProfilesDbHandler()
        self._nodesDbHandler = NodesDbHandler()
        self._globalParametersDbHandler = GlobalParametersDbHandler()
        self._adminsDbHandler = AdminsDbHandler()
        self._osDbHandler = OperatingSystemsDbHandler()

    def getSoftwareProfile(self, name, optionDict=None):
        """
        Get softwareProfile from the db.

            Returns:
               softwareProfile
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, name)

            self.loadRelations(dbSoftwareProfile, optionDict or {})

            self.loadRelations(dbSoftwareProfile, dict(tags=True))

            return SoftwareProfile.getFromDbDict(dbSoftwareProfile.__dict__)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def getSoftwareProfileById(self, softwareProfileId, optionDict=None):
        """
        Get softwareProfile from the db.

            Returns:
               softwareProfile
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfileById(session, softwareProfileId)

            self.loadRelations(dbSoftwareProfile, optionDict or {})

            return SoftwareProfile.getFromDbDict(dbSoftwareProfile.__dict__)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def getSoftwareProfileList(self, tags=None):
        """
        Get list of all available softwareProfiles from the db.

            Returns:
                [softwareProfile]
            Throws:
                DbError
        """

        session = DbManager().openSession()

        try:
            dbSoftwareProfileList = self._softwareProfilesDbHandler.\
                getSoftwareProfileList(session, tags=tags)

            softwareProfileList = TortugaObjectList()

            for dbSoftwareProfile in dbSoftwareProfileList:
                self.loadRelations(
                    dbSoftwareProfile, {
                        'components': True,
                        'partitions': True,
                        'hardwareprofiles': True,
                        'tags': True,
                    })

                softwareProfileList.append(
                    SoftwareProfile.getFromDbDict(dbSoftwareProfile.__dict__))

            return softwareProfileList
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def getIdleSoftwareProfileList(self):
        """
        Get list of all available idle softwareProfiles from the db.

            Returns:
                [idle softwareProfile]
            Throws:
                DbError
        """

        session = DbManager().openSession()

        try:
            dbSoftwareProfileList = self._softwareProfilesDbHandler.\
                getIdleSoftwareProfileList(session)

            return self.getTortugaObjectList(SoftwareProfile,
                                             dbSoftwareProfileList)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def setIdleState(self, softwareProfileName, state):
        """
        Set idle state of a software profile

            Returns:
                -none-
            Throws:
                DbError
        """

        session = DbManager().openSession()

        try:
            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, softwareProfileName)

            self.getLogger().debug(
                'Setting idle state [%s] on software profile [%s]' %
                (state, dbSoftwareProfile.name))

            dbSoftwareProfile.isIdle = state

            session.commit()
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def addSoftwareProfile(self, softwareProfile, session=None):
        """
        Insert software profile into the db.

        Raises:
            SoftwareProfileAlreadyExists
            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:
                dbSoftwareProfile = self._softwareProfilesDbHandler.\
                    getSoftwareProfile(
                        _session, softwareProfile.getName())

                raise SoftwareProfileAlreadyExists(
                    'Software profile [%s] already exists' % (softwareProfile))
            except SoftwareProfileNotFound as ex:
                pass

            dbSoftwareProfile = self.__populateSoftwareProfile(
                _session, softwareProfile)

            _session.query(func.max(SoftwareProfiles.id)).one()

            softwareProfile.setId(dbSoftwareProfile.id)

            if session is None:
                _session.commit()

            self.getLogger().info('Added software profile [%s]' %
                                  (dbSoftwareProfile.name))

            return dbSoftwareProfile
        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 deleteSoftwareProfile(self, name):
        """
        Delete softwareProfile from the db.

            Returns:
                None
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            # This role of this lookup is twofold.  One, it validates
            # the existence of the software profile to be deleted and
            # second, gets the id for looking up any associated nodes
            dbSwProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, name)

            if dbSwProfile.nodes:
                # The software profile cannot be removed while
                # associated
                # nodes exist
                raise TortugaException('Unable to delete software profile with'
                                       ' associated nodes')

            if dbSwProfile.isIdle:
                # Ensure this software profile is not associated with
                # a hardware profile

                if dbSwProfile.hwprofileswithidle:
                    # This software profile is associated with one
                    # or more hardware profiles
                    raise TortugaException(
                        'Unable to delete software profile.'
                        '  This software profile is associated'
                        ' with one or more hardware profiles: [%s]' %
                        (' '.join([
                            hwprofile.name
                            for hwprofile in dbSwProfile.hwprofileswithidle
                        ])))

            # Proceed with software profile deletion
            self.getLogger().debug(
                'Marking software profile [%s] for deletion' % (name))

            session.delete(dbSwProfile)

            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 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 getAllEnabledComponentList(self):
        """
        Get a list of all enabled components in the system

            Returns:
                [ components ]
            Throws:
                DbError
        """

        session = DbManager().openSession()

        try:
            handler = ComponentsDbHandler()

            dbComponents = handler.getEnabledComponentList(session)

            return self.getTortugaObjectList(Component, dbComponents)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def getEnabledComponentList(self, name):
        """
        Get a list of enabled components from the db.

            Returns:
                node
            Throws:
                DbError
        """

        session = DbManager().openSession()

        try:
            componentList = TortugaObjectList()

            for c in self._softwareProfilesDbHandler.getSoftwareProfile(
                    session, name).components:
                self.loadRelation(c, 'kit')

                componentList.append(Component.getFromDbDict(c.__dict__))

            return componentList
        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 getNodeListByNodeStateAndSoftwareProfileName(self, nodeState,
                                                     softwareProfileName):
        """
        Return a list of Node objects based on the specified node state
        and software profile
        """

        session = DbManager().openSession()

        try:
            dbNodes = self._nodesDbHandler.\
                getNodeListByNodeStateAndSoftwareProfileName(
                    session, nodeState, softwareProfileName)

            return self.getTortugaObjectList(Node, dbNodes)
        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 getPackageList(self, softwareProfileName):
        """
        Get a list of packages from the db.

            Returns:
                [package]
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            dbPackages = self._softwareProfilesDbHandler.\
                getSoftwareProfile(
                    session, softwareProfileName).packages

            return self.getTortugaObjectList(Package, dbPackages)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def getPartitionList(self, softwareProfileName):
        """
        Get a list of software profile partitions from the db.

            Returns:
                [partition]
            Throws:
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, softwareProfileName)
            return self.getTortugaObjectList(Partition,
                                             dbSoftwareProfile.partitions)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def addPackage(self, packageName, softwareProfileName):
        """
        Add software profile package.

            Returns:
                packageId
            Throws:
                PackageAlreadyExists
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            self._softwareProfilesDbHandler.addPackageToSoftwareProfile(
                session, packageName, softwareProfileName)

            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 deletePackage(self, packageName, softwareProfileName):
        """
        Delete node from the db.

            Returns:
                None
            Throws:
                PackageNotFound
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            self._softwareProfilesDbHandler.\
                deletePackageFromSoftwareProfile(
                    session, packageName, softwareProfileName)
            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 addPartition(self, partitionName, softwareProfileName):
        """
        Add software profile partition.

            Returns:
                partitionId
            Throws:
                PartitionAlreadyExists
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            self._softwareProfilesDbHandler.\
                addPartitionToSoftwareProfile(
                    session, partitionName, softwareProfileName)

            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 deletePartition(self, partitionName, softwareProfileName):
        """
        Delete node from the db.

            Returns:
                None
            Throws:
                PartitionNotFound
                SoftwareProfileNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            self._softwareProfilesDbHandler.\
                deletePartitionFromSoftwareProfile(
                    session, partitionName, softwareProfileName)
            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 addUsableHardwareProfileToSoftwareProfile(self, hardwareProfileName,
                                                  softwareProfileName):
        """
         Add hardwareProfile to softwareProfile

            Returns:
                SoftwareUsesHardwareId
            Throws:
                HardwareProfileNotFound
                SoftwareProfileNotFound
                SoftwareUsesHardwareAlreadyExists
                DbError
        """

        session = DbManager().openSession()

        try:
            swUsesHwId = self._softwareProfilesDbHandler.\
                addUsableHardwareProfileToSoftwareProfile(
                    session, hardwareProfileName, softwareProfileName)
            session.commit()
            return swUsesHwId
        except TortugaException as ex:
            session.rollback()
            raise
        except Exception as ex:
            session.rollback()
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()

    def deleteUsableHardwareProfileFromSoftwareProfile(self,
                                                       hardwareProfileName,
                                                       softwareProfileName):
        """
        Delete hardwareProfile from softwareProfile

            Returns:
                None
            Throws:
                HardwareProfileNotFound
                SoftwareProfileNotFound
                SoftwareUsesHardwareNotFound
                DbError
        """

        session = DbManager().openSession()

        try:
            self._softwareProfilesDbHandler.\
                deleteUsableHardwareProfileFromSoftwareProfile(
                    session, hardwareProfileName, softwareProfileName)

            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, softwareProfileName, adminUsername):
        """ Add an admin to this software profile """
        session = DbManager().openSession()

        try:
            dbAdmin = self._adminsDbHandler.getAdmin(session, adminUsername)

            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, softwareProfileName)

            if dbAdmin not in dbSoftwareProfile.admins:
                dbSoftwareProfile.admins.append(dbAdmin)
            else:
                raise AdminAlreadyExists(
                    'Admin [%s] already associated with %s' %
                    (adminUsername, softwareProfileName))
            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, softwareProfileName, adminUsername):
        """ Delete an admin from a software profile """

        session = DbManager().openSession()
        try:
            dbAdmin = self._adminsDbHandler.getAdmin(session, adminUsername)

            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, softwareProfileName)

            if dbAdmin in dbSoftwareProfile.admins:
                dbSoftwareProfile.admins.remove(dbAdmin)
            else:
                raise AdminNotFound(
                    'Admin [%s] not associated with software profile'
                    ' [%s]' % (adminUsername, softwareProfileName))

            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 updateSoftwareProfile(self, softwareProfileObject):
        """ Update a software profile """

        session = DbManager().openSession()

        try:
            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfileById(
                    session, softwareProfileObject.getId())
            self.__populateSoftwareProfile(session, softwareProfileObject,
                                           dbSoftwareProfile)
            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 __populateSoftwareProfile(self,
                                  session,
                                  softwareProfile,
                                  dbSoftwareProfile=None):
        """
        Helper function for creating/updating dbSoftwareProfile Object
        """

        # Validate object
        if softwareProfile.getName() is None:
            raise UpdateSoftwareProfileFailed('Software profile name required')

        if softwareProfile.getType() is None:
            raise UpdateSoftwareProfileFailed(
                'Software profile must have valid type')

        osInfo = softwareProfile.getOsInfo()
        if osInfo is None or osInfo.getName() is None:
            raise UpdateSoftwareProfileFailed(
                'Software profile must have valid operating system')

        if dbSoftwareProfile is None:
            dbSoftwareProfile = SoftwareProfiles()

        dbOs = self._osDbHandler.addOsIfNotFound(session, osInfo)

        dbSoftwareProfile.name = softwareProfile.getName()
        dbSoftwareProfile.description = softwareProfile.getDescription()
        dbSoftwareProfile.kernel = softwareProfile.getKernel()
        dbSoftwareProfile.kernelParams = softwareProfile.getKernelParams()
        dbSoftwareProfile.initrd = softwareProfile.getInitrd()
        dbSoftwareProfile.os = dbOs
        dbSoftwareProfile.type = softwareProfile.getType()
        dbSoftwareProfile.minNodes = softwareProfile.getMinNodes()
        dbSoftwareProfile.isIdle = softwareProfile.getIsIdle()

        # Add packages
        packages = {}
        for package in softwareProfile.getPackages():
            # This is a new package
            dbPackage = Packages()

            dbPackage.name = package.getName()
            if packages.get(dbPackage.name) is not None:
                # Duplicate package ...error
                raise UpdateSoftwareProfileFailed(
                    'Duplicate package [%s] found' % (dbPackage.name))

            packages[dbPackage.name] = dbPackage

        # Add partitions
        partitions = {}
        for partition in softwareProfile.getPartitions():
            # This is a new partition
            dbPartition = Partitions()

            dbPartition.name = partition.getName()
            dbPartition.device = partition.getDevice()
            dbPartition.mountPoint = partition.getMountPoint()
            dbPartition.fsType = partition.getFsType()
            dbPartition.size = partition.getSize()
            dbPartition.options = partition.getOptions()
            dbPartition.preserve = partition.getPreserve()
            dbPartition.bootLoader = partition.getBootLoader()
            dbPartition.diskSize = partition.getDiskSize()
            dbPartition.directAttachment = partition.getDirectAttachment()
            dbPartition.indirectAttachment = partition.\
                getIndirectAttachment()
            dbPartition.sanVolume = partition.getSanVolume()

            if not dbPartition.name:
                raise InvalidPartitionScheme(
                    'Invalid partition in software profile:'
                    ' missing or empty name')

            if not dbPartition.device:
                raise InvalidPartitionScheme(
                    'Invalid partition in software profile:'
                    ' missing or empty device')

            if not dbPartition.fsType:
                raise InvalidPartitionScheme(
                    'Invalid partition [%s/%s] in software profile:'
                    ' missing or empty fsType' %
                    (dbPartition.name, dbPartition.device))

            if dbPartition.size is None:
                raise InvalidPartitionScheme(
                    'Invalid partition [%s/%s] in software profile:'
                    ' missing size' % (dbPartition.name, dbPartition.device))

            if partitions.get(
                (dbPartition.name, dbPartition.device)) is not None:
                # Duplicate partition ...error
                raise UpdateSoftwareProfileFailed(
                    'Duplicate partition [%s/%s] found' %
                    (dbPartition.name, dbPartition.device))

            try:
                int(dbPartition.size)
            except ValueError:
                raise InvalidPartitionScheme(
                    'Invalid partition [%s/%s] in software profile:'
                    ' non-integer size' %
                    (dbPartition.name, dbPartition.device))

            try:
                if dbPartition.diskSize is not None:
                    int(dbPartition.diskSize)
            except ValueError:
                raise InvalidPartitionScheme(
                    'Invalid partition [%s/%s] in software profile:'
                    ' non-integer disk size' %
                    (dbPartition.name, dbPartition.device))

            bGrow = partition.getGrow()
            if bGrow is not None:
                dbPartition.grow = bGrow

            maxSize = partition.getMaxSize()
            if maxSize is not None:
                dbPartition.maxSize = maxSize

            partitions[(dbPartition.name, dbPartition.device)] = \
                dbPartition

        # Delete out the old ones
        dbSoftwareProfile.partitions = []
        dbSoftwareProfile.packages = []

        session.flush()

        dbSoftwareProfile.partitions = list(partitions.values())
        dbSoftwareProfile.packages = list(packages.values())

        session.add(dbSoftwareProfile)

        session.flush()

        return dbSoftwareProfile

    def copySoftwareProfile(self, srcSoftwareProfileName,
                            dstSoftwareProfileName):
        session = DbManager().openSession()

        srcSoftwareProfile = self.getSoftwareProfile(srcSoftwareProfileName, {
            'partitions': True,
            'packages': True,
            'components': True,
        })

        dstSoftwareProfile = self.getSoftwareProfile(srcSoftwareProfileName)
        dstSoftwareProfile.setName(dstSoftwareProfileName)
        newDescription = 'Copy of %s' % (dstSoftwareProfile.getDescription())
        dstSoftwareProfile.setDescription(newDescription)

        # partitions
        dstSoftwareProfile.setPartitions(srcSoftwareProfile.getPartitions())

        # packages
        dstSoftwareProfile.setPackages(srcSoftwareProfile.getPackages())

        # Finally add the software profile
        dstSoftwareProfile = self.addSoftwareProfile(dstSoftwareProfile,
                                                     session)

        # Enable components separately
        srcCompList = self.getEnabledComponentList(srcSoftwareProfileName)

        for srcComp in srcCompList:
            if srcComp.getKit().getIsOs() or srcComp.getName() == 'core':
                self._softwareProfilesDbHandler.\
                    addComponentToSoftwareProfileEx(
                        session, srcComp.getId(), dstSoftwareProfile)

        session.commit()

    def getUsableNodes(self, name):
        """
        Return list of nodes with same software/hardware profile mapping
        as the specified software profile.
        """

        session = DbManager().openSession()

        try:
            dbSoftwareProfile = self._softwareProfilesDbHandler.\
                getSoftwareProfile(session, name)

            nodes = [
                dbNode
                for dbHardwareProfile in dbSoftwareProfile.hardwareprofiles
                for dbNode in dbHardwareProfile.nodes
            ]

            return self.getTortugaObjectList(Node, nodes)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise
        finally:
            DbManager().closeSession()
Пример #7
0
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)