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()
Esempio n. 2
0
    def _get_resource_adapter(self, sess: Session,
                              node_id: str) -> ResourceAdapter:
        node_store = NodeStoreManager.get()
        node = node_store.get(node_id)
        #
        # Lookup the hardware profile for the node
        #
        hwp_store = HardwareProfileStoreManager.get()
        hwp = hwp_store.get(node.hardwareprofile_id)
        #
        # Lookup the resource adapter for the hardware profile
        #
        ra_handler = ResourceAdaptersDbHandler()
        for db_ra in ra_handler.getResourceAdapterList(sess):
            if db_ra.id == int(hwp.resourceadapter_id):
                #
                # Get a instantiated ResourceAdapter instance
                #
                return get_api(db_ra.name)

        raise Exception('Resource adapter not found with ID: %s',
                        hwp.rsourceadapter_id)
Esempio n. 3
0
    def __init__(self):
        self._resourceAdapterConfigDbHandler = \
            ResourceAdapterConfigDbHandler()

        self._resourceAdaptersDbHandler = ResourceAdaptersDbHandler()
Esempio n. 4
0
class ResourceAdapterConfigurationManager:
    def __init__(self):
        self._resourceAdapterConfigDbHandler = \
            ResourceAdapterConfigDbHandler()

        self._resourceAdaptersDbHandler = ResourceAdaptersDbHandler()

    def create(self,
               session: Session,
               resadapter_name: str,
               name: str,
               configuration: Union[List[Dict[str, str]], None] = None,
               force: bool = False) -> ResourceAdapterConfig:
        """
        Creates a new resource adapter profile.

        :param Session session:                    the current database
                                                   session
        :param str resadapter_name:                the name of the resource
                                                   adapter
        :param str name:                           the name of the resource
                                                   adapter profile
        :param List[Dict[str, str]] configuration: the list of configuration
                                                   settings
        :param bool force:                         when True, will not
                                                   validate the configuration
                                                   settings

        :raises ResourceAlreadyExists:
        :raises ResourceAdapterNotFound:
        :raises ValidationError:

        """
        #
        # Check for duplicates
        #
        adapter = self._resourceAdaptersDbHandler.getResourceAdapter(
            session, resadapter_name)

        try:
            self._resourceAdapterConfigDbHandler.get(session, resadapter_name,
                                                     name)
            raise ResourceAlreadyExists(
                'Resource adapter configuration [{}] already exists'.format(
                    name))

        except ResourceNotFound:
            pass

        #
        # Basic validation of the settings
        #
        cfg = ResourceAdapterConfig(name=name)
        validator = ConfigurationValidator(adapter.settings)

        for entry in configuration or []:
            cfg.configuration.append(
                ResourceAdapterSetting(key=entry['key'], value=entry['value']))
            validator[entry['key']] = entry['value']

        if not force:
            validator.validate(full=False)

        #
        # Commit resource adapter changes to database
        #
        adapter.resource_adapter_config.append(cfg)
        session.commit()

        return cfg

    def get(self, session: Session, resadapter_name: str, name: str) \
            -> ResourceAdapterConfig:
        """
        Raises:
            ResourceNotFound
            ResourceAdapterNotFound
        """

        # first check if resource adapter exists
        self._resourceAdaptersDbHandler.getResourceAdapter(
            session, resadapter_name)

        # then attempt to retrieve specified configuration
        return self._resourceAdapterConfigDbHandler.get(
            session, resadapter_name, name)

    def get_profile_names(self, session: Session, resadapter_name: str) \
            -> List[str]:
        """
        Raises:
            ResourceAdapterNotFound
        """

        adapter = self._resourceAdaptersDbHandler.getResourceAdapter(
            session, resadapter_name)

        return [cfg.name for cfg in adapter.resource_adapter_config]

    def delete(self, session: Session, resadapter_name: str, name: str) \
            -> None:
        """
        Delete resource adapter configuration

        Raises:
            ResourceAdapterNotFound
            ResourceNotFound
        """

        self._resourceAdaptersDbHandler.getResourceAdapter(
            session, resadapter_name)

        cfg = self.get(session, resadapter_name, name)

        session.delete(cfg)

    def update(self,
               session: Session,
               resadapter_name: str,
               name: str,
               configuration: List[Dict[str, str]],
               force: bool = False) -> None:
        """
        Updates an existing resource adapter profile.

        :param Session session:                    the current database
                                                   session
        :param str resadapter_name:                the name of the resource
                                                   adapter
        :param str name:                           the name of the resource
                                                   adapter profile
        :param List[Dict[str, str]] configuration: the list of configuration
                                                   settings
        :param bool force:                         when True, will not
                                                   validate the configuration
                                                   settings

        :raises ResourceAlreadyExists:
        :raises ResourceAdapterNotFound:
        :raises ValidationError:

        """
        #
        # Ensure resource adapter is valid
        #
        adapter = self._resourceAdaptersDbHandler.getResourceAdapter(
            session, resadapter_name)

        #
        # Basic validation of the settings
        #
        if not force:
            validator = ConfigurationValidator(adapter.settings)

            for entry in configuration or []:
                validator[entry['key']] = entry['value']

            validator.validate(full=False)

        #
        # Update the database
        #
        cfg = self._resourceAdapterConfigDbHandler.get(session,
                                                       resadapter_name, name)
        self.__update_settings(session, configuration, cfg.configuration)
        session.commit()

    def __update_settings(self, session: Session,
                          configuration: List[Dict[str, str]],
                          existing_settings: List[ResourceAdapterSetting]) \
            -> None:
        new_settings: List[Tuple[str, str]] = []
        delete_settings: List[ResourceAdapterSetting] = []

        for entry in configuration:
            if 'key' not in entry or 'value' not in entry:
                raise InvalidArgument(
                    'Malformed resource adapter configuration data')

            setting = setting_exists(existing_settings, entry['key'])

            if entry['value'] is None:
                if setting:
                    # setting is marked for deletion
                    delete_settings.append(setting)

                continue

            if setting is None:
                if entry['value'] is not None:
                    # create new setting
                    new_settings.append((entry['key'], entry['value']))

                continue

            # update existing settings
            setting.value = entry['value']

        # add new setting(s)
        for key, value in new_settings:
            existing_settings.append(
                ResourceAdapterSetting(key=key, value=value))

        # delete setting(s) marked for deletion
        for delete_setting in delete_settings:
            session.delete(delete_setting)
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