class SoftwareProfileController(TortugaController):
    actions = [
        {
            'name': 'getSoftwareProfiles',
            'path': '/v1/softwareProfiles',
            'action': 'getSoftwareProfiles',
            'method': ['GET'],
        },
        {
            'name': 'deleteSoftwareProfile',
            'path': '/v1/softwareProfiles/:(softwareProfileName)',
            'action': 'deleteSoftwareProfile',
            'method': ['DELETE'],
        },
        {
            'name': 'createSoftwareProfile',
            'path': '/v1/softwareProfiles',
            'action': 'createSoftwareProfile',
            'method': ['POST'],
        },
        {
            'name': 'copySoftwareProfile',
            'path': '/v1/softwareProfiles/:(srcSoftwareProfileName)/copy',
            'action': 'copySoftwareProfile',
            'method': ['POST'],
        },
        {
            'name': 'getUsableNodes',
            'path': '/v1/softwareProfiles/:(softwareProfileName)/usable',
            'action': 'getUsableNodes',
            'method': ['GET'],
        },
        {
            'name': 'getIdleSoftwareProfiles',
            'path': '/v1/idleSoftwareProfiles',
            'action': 'getIdleSoftwareProfiles',
            'method': ['GET'],
        },
        {
            'name': 'updateSoftwareProfile',
            'path': '/v1/softwareProfiles/:(softwareProfileId)',
            'action': 'updateSoftwareProfile',
            'method': ['PUT'],
        },
        {
            'name': 'getSoftwareProfile',
            'path': '/v1/softwareProfiles/:(softwareProfileName)',
            'action': 'getSoftwareProfile',
            'method': ['POST'],
        },
        {
            'name': 'getSoftwareProfileById',
            'path': '/v1/softwareProfiles/id/:(id)',
            'action': 'getSoftwareProfileById',
            'method': ['GET'],
        },
        {
            'name': 'getSoftwareProfileProvisioningInfo',
            'path': '/v1/softwareProfiles/:(softwareProfileName)'
                    '/provisioningInfo',
            'action': 'getProvisioningInfo',
            'method': ['GET'],
        },
        {
            'name': 'getSoftwareProfileAdmins',
            'path': '/v1/softwareProfiles/:(softwareProfileName)/admins',
            'action': 'getAdmins',
            'method': ['GET'],
        },
        {
            'name': 'getEnabledComponents',
            'path': '/v1/softwareProfiles/:(softwareProfileName)/components',
            'action': 'getEnabledComponents',
            'method': ['GET'],
        },
        {
            'name': 'addSwAdmin',
            'path': '/v1/softwareProfiles/:(softwareProfileName)'
                    '/admin/:(adminUsername)',
            'action': 'addAdmin',
            'method': ['POST'],
        },
        {
            'name': 'deleteSwAdmin',
            'path': '/v1/softwareProfiles/:(softwareProfileName)'
                    '/admin/:(adminUsername)',
            'action': 'deleteAdmin',
            'method': ['DELETE'],
        },
        {
            'name': 'enableComponent',
            'path': '/v1/softwareProfiles/:(softwareProfileName)'
                    '/enable_components',
            'action': 'enableComponent',
            'method': ['PUT'],
        },
        {
            'name': 'disableComponent',
            'path': '/v1/softwareProfiles/:(softwareProfileName)'
                    '/disable_components',
            'action': 'disableComponent',
            'method': ['PUT'],
        },
        {
            'name': 'addUsableHardwareProfileToSoftwareProfile',
            'path': '/v1/softwareProfiles/:(softwareProfileName)'
                    '/mappings/:(hardwareProfileName)',
            'action': 'addUsableHardwareProfileToSoftwareProfile',
            'method': ['POST'],
        },
        {
            'name': 'deleteUsableHardwareProfileFromSoftwareProfile',
            'path': '/v1/softwareProfiles/:(softwareProfileName)'
                    '/mappings/:(hardwareProfileName)',
            'action': 'deleteUsableHardwareProfileFromSoftwareProfile',
            'method': ['DELETE'],
        },
        {
            'name': 'softwareProfileNodes',
            'path': '/v1/softwareProfiles/:(softwareProfileName)/nodes',
            'action': 'getNodes',
            'method': ['GET'],
        },
    ]

    def __init__(self):
        TortugaController.__init__(self)

        self._softwareProfileManager = SoftwareProfileManager()

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getSoftwareProfiles(self, **kwargs):
        tagspec = []

        if 'tag' in kwargs and kwargs['tag']:
            tagspec.extend(parse_tag_query_string(kwargs['tag']))

        softwareProfiles = self._softwareProfileManager.\
            getSoftwareProfileList(tags=tagspec)

        response = {
            'softwareprofiles': softwareProfiles.getCleanDict(),
        }

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getIdleSoftwareProfiles(self):
        idleSoftwareProfiles = self._softwareProfileManager.\
            getIdleSoftwareProfileList()

        response = {
            'softwareprofiles': idleSoftwareProfiles.getCleanDict(),
        }

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getSoftwareProfileById(self, id_):
        """Get software profile by id"""

        # self.getLogger().debug('getSoftwareProfileById(id=[%s])' % (id))

        try:
            sp = self._softwareProfileManager.getSoftwareProfileById(
                id_, {
                    'admins': True,
                    'components': True,
                    'nodes': True,
                    'os': True,
                    'packages': True,
                    'partitions': True,
                })

            response = {'softwareprofile': sp.getCleanDict()}
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API getSoftwareProfileById() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def createSoftwareProfile(self):
        """Create software profile"""

        response = None

        postdata = cherrypy.request.json

        if 'softwareProfile' not in postdata:
            raise Exception('Malformed request')

        settingsDict = postdata['settingsDict'] \
            if 'settingsDict' in postdata else {}

        self.getLogger().debug(
            '[%s] createSoftwareProfile(): softwareProfile=[%s]' % (
                self.__module__, postdata['softwareProfile']))

        swProfileSpec = SoftwareProfile.getFromDict(
            postdata['softwareProfile'])

        try:
            SoftwareProfileApi().createSoftwareProfile(
                swProfileSpec, settingsDict=settingsDict)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API createSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def deleteSoftwareProfile(self, softwareProfileName):
        """Delete software profile"""

        response = None

        # self.getLogger().debug('deleteSoftwareProfile()')

        try:
            SoftwareProfileApi().deleteSoftwareProfile(softwareProfileName)
        except SoftwareProfileNotFound as ex:
            self.handleException(ex)
            code = self.getTortugaStatusCode(ex)
            response = self.notFoundErrorResponse(str(ex), code)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API deleteSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getSoftwareProfile(self, softwareProfileName):
        """Get software profile by name"""

        postdata = cherrypy.request.json

        optionDict = postdata['optionDict'] \
            if 'optionDict' in postdata else {}

        try:
            sp = self._softwareProfileManager.getSoftwareProfile(
                softwareProfileName, optionDict)

            response = {
                'softwareprofile': sp.getCleanDict(),
            }
        except SoftwareProfileNotFound as ex:
            self.handleException(ex)
            code = self.getTortugaStatusCode(ex)
            response = self.notFoundErrorResponse(str(ex), code)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API getSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def updateSoftwareProfile(self, softwareProfileId):
        '''
        Handle put to softwareprofiles/:(softwareProfileId)
        '''

        response = None

        try:
            postdata = cherrypy.request.json

            swProfile = SoftwareProfile.getFromDict(postdata)

            # Make sure the id is synced
            swProfile.setId(softwareProfileId)

            self._softwareProfileManager.updateSoftwareProfile(swProfile)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API updateSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getEnabledComponents(self, softwareProfileName):
        """ Return list of all enabled components. """

        # self.getLogger().debug(
        #     'Retrieving enabled component list for [%s]' % (
        #         softwareProfileName))

        try:
            componentList = self._softwareProfileManager.\
                getEnabledComponentList(softwareProfileName)

            response = {'components': componentList.getCleanDict()}
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API getEnabledComponents() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def addUsableHardwareProfileToSoftwareProfile(self,
                                                  softwareProfileName,
                                                  hardwareProfileName):
        """ Add hardware profile to software profile. """

        # self.getLogger().debug(
        #     'Adding hardware profile [%s] to software profile [%s]' % (
        #         hardwareProfileName, softwareProfileName))

        response = None

        try:
            self._softwareProfileManager.\
                addUsableHardwareProfileToSoftwareProfile(
                    hardwareProfileName, softwareProfileName)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API'
                ' addUsableHardwareProfileToSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def deleteUsableHardwareProfileFromSoftwareProfile(self,
                                                       softwareProfileName,
                                                       hardwareProfileName):
        """ Delete hardware profile from software profile. """

        response = None

        try:
            self._softwareProfileManager.\
                deleteUsableHardwareProfileFromSoftwareProfile(
                    hardwareProfileName, softwareProfileName)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API'
                ' deleteUsableHardwareProfileFromSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def addAdmin(self, softwareProfileName, adminUsername):
        response = None

        try:
            self._softwareProfileManager.addAdmin(
                softwareProfileName, adminUsername)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API addAdmin() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def deleteAdmin(self, softwareProfileName, adminUsername):
        try:
            self._softwareProfileManager.deleteAdmin(
                softwareProfileName, adminUsername)

            response = None
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API deleteAdmin() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def enableComponent(self, softwareProfileName):
        response = None

        try:
            postdata = cherrypy.request.json

            if 'components' not in postdata or not postdata['components']:
                raise InvalidArgument('Malformed enable component request')

            # Reserved for possible future use where it will be possible to
            # enable multiple components in one request.
            component = postdata['components'][0]

            kitName = component['kitName']
            kitVersion = component['kitVersion']
            kitIteration = component['kitIteration']
            componentName = component['componentName']
            componentVersion = component['componentVersion']

            self._softwareProfileManager.enableComponent(
                softwareProfileName, kitName, kitVersion, kitIteration,
                componentName, comp_version=componentVersion)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API enableComponent() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def disableComponent(self, softwareProfileName):
        response = None

        try:
            postdata = cherrypy.request.json

            if 'components' not in postdata or not postdata['components']:
                raise InvalidArgument('Malformed disable component request')

            # Reserved for possible future use where it will be possible to
            # disable multiple components in one request.
            component = postdata['components'][0]

            kitName = component['kitName']
            kitVersion = component['kitVersion']
            kitIteration = component['kitIteration']
            componentName = component['componentName']
            componentVersion = component['componentVersion']

            self._softwareProfileManager.disableComponent(
                softwareProfileName, kitName, kitVersion, kitIteration,
                componentName, componentVersion)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API disableComponent() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def copySoftwareProfile(self, srcSoftwareProfileName,
                            dstSoftwareProfileName):
        response = None

        try:
            self._softwareProfileManager.copySoftwareProfile(
                srcSoftwareProfileName, dstSoftwareProfileName)
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API copySoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getUsableNodes(self, softwareProfileName):
        try:
            nodeList = self._softwareProfileManager.getUsableNodes(
                softwareProfileName)

            response = {'nodes': nodeList.getCleanDict()}
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API getUsableNodes() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @require()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getNodes(self, softwareProfileName):
        try:
            nodeList = self._softwareProfileManager.getNodeList(
                softwareProfileName)

            response = {
                'nodes': nodeList,
            }
        except Exception as ex:
            self.getLogger().exception(
                'software profile WS API getNodes() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)
示例#2
0
class SoftwareProfileApi(TortugaApi): \
        # pylint: disable=too-many-public-methods
    """
    SoftwareProfile API class.
    """

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

        self._softwareProfileManager = SoftwareProfileManager()

    def getSoftwareProfile(self, softwareProfileName, optionDict=None):
        """
        Get software profile information

            Returns:
               softwareProfile
            Throws:
                SoftwareProfileNotFound
                TortugaException
        """
        try:
            return self._softwareProfileManager.\
                getSoftwareProfile(softwareProfileName, optionDict)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def getSoftwareProfileById(self, softwareProfileId, optionDict=None):
        """
        Get software profile information

            Returns:
               softwareProfile
            Throws:
                SoftwareProfileNotFound
                TortugaException
        """
        try:
            return self._softwareProfileManager.\
                getSoftwareProfileById(softwareProfileId, optionDict)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def deleteSoftwareProfile(self, softwareProfileName):
        """
        Delete the specified software profile

            Returns:
               softwareProfile
            Throws:
                SoftwareProfileNotFound
                TortugaException
        """
        try:
            self._softwareProfileManager.\
                deleteSoftwareProfile(softwareProfileName)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def getSoftwareProfileList(self, tags=None):
        """
        Returns a list of all software profiles.
        """
        try:
            return self._softwareProfileManager.\
                getSoftwareProfileList(tags=tags)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def getIdleSoftwareProfileList(self):
        """
        Get software profile information

            Returns:
               idle softwareProfile list
            Throws:
                TortugaException
        """
        try:
            return self._softwareProfileManager.\
                getIdleSoftwareProfileList()
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def setIdleState(self, softwareProfileName, state):
        """
        Get idle state information

            Returns:
               -none-
            Throws:
                TortugaException
        """
        try:
            self._softwareProfileManager.\
                setIdleState(softwareProfileName, state)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def getEnabledComponentList(self, name):
        """
        Get enabled component list..

            Returns:
                list of enabled components
            Throws:
                SoftwareProfileNotFound
                TortugaException
        """
        try:
            return self._softwareProfileManager.\
                getEnabledComponentList(name)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def getPackageList(self, softwareProfileName):
        """
        Get package list for a given softwareprofile

            Returns:
                [package]
            Throws:
                SoftwareProfileNotFound
                TortugaException
        """
        try:
            return self._softwareProfileManager.\
                getPackageList(softwareProfileName)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def getPartitionList(self, softwareProfileName):
        """
        Get partition list for a given softwareprofile

            Returns:
                [partition]
            Throws:
                SoftwareProfileNotFound
                TortugaException
        """
        try:
            return self._softwareProfileManager.\
                getPartitionList(softwareProfileName)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def addUsableHardwareProfileToSoftwareProfile(self,
                                                  hardwareProfileName,
                                                  softwareProfileName):
        """
        Set useable hardware profile

            Returns:
                SoftwareUsesHardwareID
            Throws:
                SoftwareProfileNotFound
                HardwareProfileNotFound
                TortugaException
        """
        try:
            return self._softwareProfileManager.\
                addUsableHardwareProfileToSoftwareProfile(
                    hardwareProfileName, softwareProfileName)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def deleteUsableHardwareProfileFromSoftwareProfile(self,
                                                       hardwareProfileName,
                                                       softwareProfileName):
        """
        Delete useable hardware profile

            Returns:
                None
            Throws:
                SoftwareProfileNotFound
                HardwareProfileNotFound
                TortugaException
        """
        try:
            self._softwareProfileManager.\
                deleteUsableHardwareProfileFromSoftwareProfile(
                    hardwareProfileName, softwareProfileName)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def addAdmin(self, softwareProfileName, adminUsername):
        """
        Add an admin as an authorized user.

            Returns:
                None
            Throws:
                TortugaException
                AdminNotFound
                SoftwareProfileNotFound
        """
        try:
            self._softwareProfileManager.\
                addAdmin(softwareProfileName, adminUsername)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def deleteAdmin(self, softwareProfileName, adminUsername):
        """
        Remove an admin as an authorized user.

            Returns:
                None
            Throws:
                TortugaException
                AdminNotFound
                SoftwareProfileNotFound
        """
        try:
            self._softwareProfileManager.\
                deleteAdmin(softwareProfileName, adminUsername)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def updateSoftwareProfile(self, softwareProfileObject):
        """
        Update a software profile in the database that matches the passed
        in software profile object.  The ID is used as the primary matching
        criteria.

            Returns:
                None
            Throws:
                TortugaException
        """
        try:
            self._softwareProfileManager.\
                updateSoftwareProfile(softwareProfileObject)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def createSoftwareProfile(self, swProfileSpec, settingsDict=None):
        try:
            self._softwareProfileManager.createSoftwareProfile(
                swProfileSpec, settingsDict)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def getNodeList(self, softwareProfileName):
        try:
            return self._softwareProfileManager.getNodeList(
                softwareProfileName)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def enableComponent(self, softwareProfileName, kitName, kitVersion,
                        kitIteration, compName, compVersion=None):
        try:
            return self._softwareProfileManager.enableComponent(
                softwareProfileName,
                kitName,
                kitVersion,
                kitIteration,
                compName,
                compVersion)
        except Exception as ex:
            if not isinstance(ex, TortugaException):
                self.getLogger().exception(
                    'Exception raised in {0}.enableComponent()'.format(
                        self.__class__.__name__))

                # Wrap exception
                raise TortugaException(exception=ex)

            raise

    def disableComponent(self, softwareProfileName, kitName, kitVersion,
                         kitIteration, compName, compVersion=None):
        try:
            return self._softwareProfileManager.disableComponent(
                softwareProfileName,
                kitName,
                kitVersion,
                kitIteration,
                compName,
                compVersion)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def copySoftwareProfile(self, srcSoftwareProfileName,
                            dstSoftwareProfileName):
        try:
            return self._softwareProfileManager.\
                copySoftwareProfile(
                    srcSoftwareProfileName, dstSoftwareProfileName)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)

    def getUsableNodes(self, softwareProfileName):
        try:
            return self._softwareProfileManager.getUsableNodes(
                softwareProfileName)
        except TortugaException as ex:
            raise
        except Exception as ex:
            self.getLogger().exception('%s' % ex)
            raise TortugaException(exception=ex)
示例#3
0
class SoftwareProfileController(TortugaController):
    actions = [
        {
            'name': 'getSoftwareProfiles',
            'path': '/v1/softwareprofiles/',
            'action': 'getSoftwareProfiles',
            'method': ['GET'],
        },
        {
            'name': 'getSoftwareProfileById',
            'path': '/v1/softwareprofiles/:(swprofile_id)',
            'action': 'getSoftwareProfileById',
            'method': ['GET'],
        },
        {
            'name': 'deleteSoftwareProfile',
            'path': '/v1/softwareprofiles/:(softwareProfileName)',
            'action': 'deleteSoftwareProfile',
            'method': ['DELETE'],
        },
        {
            'name': 'createSoftwareProfile',
            'path': '/v1/softwareprofiles/',
            'action': 'createSoftwareProfile',
            'method': ['POST'],
        },
        {
            'name': 'copySoftwareProfile',
            'path':
            '/v1/softwareprofiles/:(srcSoftwareProfileName)/copy/:(dstSoftwareProfileName)',
            'action': 'copySoftwareProfile',
            'method': ['POST'],
        },
        {
            'name': 'getUsableNodes',
            'path': '/v1/softwareprofiles/:(softwareProfileName)/usable',
            'action': 'getUsableNodes',
            'method': ['GET'],
        },
        {
            'name': 'updateSoftwareProfile',
            'path': '/v1/softwareprofiles/:(softwareProfileId)',
            'action': 'updateSoftwareProfile',
            'method': ['PUT'],
        },
        {
            'name': 'getSoftwareProfileProvisioningInfo',
            'path': '/v1/softwareprofiles/:(softwareProfileName)'
            '/provisioningInfo',
            'action': 'getProvisioningInfo',
            'method': ['GET'],
        },
        {
            'name': 'getSoftwareProfileAdmins',
            'path': '/v1/softwareprofiles/:(softwareProfileName)/admins',
            'action': 'getAdmins',
            'method': ['GET'],
        },
        {
            'name': 'getEnabledComponents',
            'path': '/v1/softwareprofiles/:(softwareProfileName)/components',
            'action': 'getEnabledComponents',
            'method': ['GET'],
        },
        {
            'name': 'addSwAdmin',
            'path': '/v1/softwareprofiles/:(softwareProfileName)'
            '/admin/:(adminUsername)',
            'action': 'addAdmin',
            'method': ['POST'],
        },
        {
            'name': 'deleteSwAdmin',
            'path': '/v1/softwareprofiles/:(softwareProfileName)'
            '/admin/:(adminUsername)',
            'action': 'deleteAdmin',
            'method': ['DELETE'],
        },
        {
            'name': 'enableComponent',
            'path': '/v1/softwareprofiles/:(softwareProfileName)'
            '/enable_components',
            'action': 'enableComponent',
            'method': ['PUT'],
        },
        {
            'name': 'disableComponent',
            'path': '/v1/softwareprofiles/:(softwareProfileName)'
            '/disable_components',
            'action': 'disableComponent',
            'method': ['PUT'],
        },
        {
            'name': 'addUsableHardwareProfileToSoftwareProfile',
            'path': '/v1/softwareprofiles/:(softwareProfileName)'
            '/mappings/:(hardwareProfileName)',
            'action': 'addUsableHardwareProfileToSoftwareProfile',
            'method': ['POST'],
        },
        {
            'name': 'deleteUsableHardwareProfileFromSoftwareProfile',
            'path': '/v1/softwareprofiles/:(softwareProfileName)'
            '/mappings/:(hardwareProfileName)',
            'action': 'deleteUsableHardwareProfileFromSoftwareProfile',
            'method': ['DELETE'],
        },
        {
            'name': 'softwareProfileNodes',
            'path': '/v1/softwareprofiles/:(softwareProfileName)/nodes',
            'action': 'getNodes',
            'method': ['GET'],
        },
    ]

    def __init__(self, app: Application) -> None:
        super().__init__(app)

        self._softwareProfileManager = SoftwareProfileManager()

    @authentication_required()
    @cherrypy.tools.json_out()
    def getSoftwareProfiles(self, **kwargs):
        """
        TODO: implement support for optionDict through query string
        """

        try:
            tags = {}

            if 'tag' in kwargs and kwargs['tag']:
                tags.update(dict(parse_tag_query_string(kwargs['tag'])))

            if 'name' in kwargs and kwargs['name']:
                default_options = [
                    'components',
                    'partitions',
                    'hardwareprofiles',
                    'tags',
                ]

                options = make_options_from_query_string(
                    kwargs['include'] if 'include' in kwargs else None,
                    default_options)

                softwareProfiles = TortugaObjectList([
                    self._softwareProfileManager.getSoftwareProfile(
                        cherrypy.request.db,
                        kwargs['name'],
                        optionDict=options)
                ])
            else:
                softwareProfiles = \
                    self._softwareProfileManager.getSoftwareProfileList(
                        cherrypy.request.db, tags=tags)

            response = {
                'softwareprofiles': softwareProfiles.getCleanDict(),
            }
        except Exception as ex:
            self.handleException(ex)

            http_status = 404 \
                if isinstance(ex, SoftwareProfileNotFound) else 400

            response = self.errorResponse(str(ex), http_status=http_status)

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def createSoftwareProfile(self):
        """Create software profile"""

        response = None

        postdata = cherrypy.request.json

        if 'softwareProfile' not in postdata:
            raise Exception('Malformed request')

        settingsDict = postdata['settingsDict'] \
            if 'settingsDict' in postdata else {}

        self._logger.debug(
            '[%s] createSoftwareProfile(): softwareProfile=[%s]' %
            (self.__module__, postdata['softwareProfile']))

        swProfileSpec = SoftwareProfile.getFromDict(
            postdata['softwareProfile'])

        try:
            swProfileSpec.validate()
            SoftwareProfileApi().createSoftwareProfile(
                cherrypy.request.db, swProfileSpec, settingsDict=settingsDict)

        except Exception as ex:
            self._logger.exception(
                'software profile WS API createSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def deleteSoftwareProfile(self, softwareProfileName):
        """Delete software profile"""

        response = None

        # self._logger.debug('deleteSoftwareProfile()')

        try:
            SoftwareProfileApi().deleteSoftwareProfile(cherrypy.request.db,
                                                       softwareProfileName)
        except SoftwareProfileNotFound as ex:
            self.handleException(ex)
            code = self.getTortugaStatusCode(ex)
            response = self.notFoundErrorResponse(str(ex), code)
        except Exception as ex:
            self._logger.exception(
                'software profile WS API deleteSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    def getSoftwareProfileById(self, swprofile_id, **kwargs):
        """
        Get software profile by name

        TODO: implement support for optionDict through query string
        """
        optionDict = {
            'admins': True,
            'components': True,
            'nodes': True,
            'os': True,
            'partitions': True,
        }

        try:
            sp = self._softwareProfileManager.getSoftwareProfileById(
                cherrypy.request.db, swprofile_id, optionDict)

            response = {
                'softwareprofile': sp.getCleanDict(),
            }
        except SoftwareProfileNotFound as ex:
            self.handleException(ex)
            code = self.getTortugaStatusCode(ex)
            response = self.notFoundErrorResponse(str(ex), code)
        except Exception as ex:
            self._logger.exception(
                'software profile WS API getSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def updateSoftwareProfile(self, softwareProfileId):
        '''
        Handle put to softwareprofiles/:(softwareProfileId)
        '''

        response = None

        try:
            postdata = cherrypy.request.json

            swProfile = SoftwareProfile.getFromDict(postdata)

            # Make sure the id is synced
            swProfile.setId(softwareProfileId)

            self._softwareProfileManager.updateSoftwareProfile(
                cherrypy.request.db, swProfile)
        except Exception as ex:
            self._logger.exception(
                'software profile WS API updateSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getEnabledComponents(self, softwareProfileName):
        """ Return list of all enabled components. """

        # self._logger.debug(
        #     'Retrieving enabled component list for [%s]' % (
        #         softwareProfileName))

        try:
            componentList = \
                self._softwareProfileManager.getEnabledComponentList(
                    cherrypy.request.db, softwareProfileName)

            response = {'components': componentList.getCleanDict()}
        except Exception as ex:
            self._logger.exception(
                'software profile WS API getEnabledComponents() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    def addUsableHardwareProfileToSoftwareProfile(self, softwareProfileName,
                                                  hardwareProfileName):
        """
        Add hardware profile to software profile
        """

        response = None

        try:
            self._softwareProfileManager.addUsableHardwareProfileToSoftwareProfile(
                cherrypy.request.db, hardwareProfileName, softwareProfileName)
        except Exception as ex:
            self._logger.exception(
                'software profile WS API'
                ' addUsableHardwareProfileToSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def deleteUsableHardwareProfileFromSoftwareProfile(self,
                                                       softwareProfileName,
                                                       hardwareProfileName):
        """ Delete hardware profile from software profile. """

        response = None

        try:
            self._softwareProfileManager.deleteUsableHardwareProfileFromSoftwareProfile(
                cherrypy.request.db, hardwareProfileName, softwareProfileName)
        except Exception as ex:
            self._logger.exception(
                'software profile WS API'
                ' deleteUsableHardwareProfileFromSoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def addAdmin(self, softwareProfileName, adminUsername):
        response = None

        try:
            self._softwareProfileManager.addAdmin(cherrypy.request.db,
                                                  softwareProfileName,
                                                  adminUsername)
        except Exception as ex:
            self._logger.exception('software profile WS API addAdmin() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def deleteAdmin(self, softwareProfileName, adminUsername):
        try:
            self._softwareProfileManager.deleteAdmin(cherrypy.request.db,
                                                     softwareProfileName,
                                                     adminUsername)

            response = None
        except Exception as ex:
            self._logger.exception(
                'software profile WS API deleteAdmin() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def enableComponent(self, softwareProfileName):
        response = None

        try:
            postdata = cherrypy.request.json

            if 'components' not in postdata or not postdata['components']:
                raise InvalidArgument('Malformed enable component request')

            # Reserved for possible future use where it will be possible to
            # enable multiple components in one request.
            component = postdata['components'][0]

            kitName = component['kitName']
            kitVersion = component['kitVersion']
            kitIteration = component['kitIteration']
            componentName = component['componentName']
            componentVersion = component['componentVersion']

            self._softwareProfileManager.enableComponent(
                cherrypy.request.db,
                softwareProfileName,
                kitName,
                kitVersion,
                kitIteration,
                componentName,
                comp_version=componentVersion,
            )
        except Exception as ex:
            self._logger.exception(
                'software profile WS API enableComponent() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def disableComponent(self, softwareProfileName):
        response = None

        try:
            postdata = cherrypy.request.json

            if 'components' not in postdata or not postdata['components']:
                raise InvalidArgument('Malformed disable component request')

            # Reserved for possible future use where it will be possible to
            # disable multiple components in one request.
            component = postdata['components'][0]

            kitName = component['kitName']
            kitVersion = component['kitVersion']
            kitIteration = component['kitIteration']
            componentName = component['componentName']
            componentVersion = component['componentVersion']

            self._softwareProfileManager.disableComponent(
                cherrypy.request.db,
                softwareProfileName,
                kitName,
                kitVersion,
                kitIteration,
                componentName,
                componentVersion,
            )
        except Exception as ex:
            self._logger.exception(
                'software profile WS API disableComponent() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    def copySoftwareProfile(self, srcSoftwareProfileName,
                            dstSoftwareProfileName):
        response = None

        try:
            self._softwareProfileManager.copySoftwareProfile(
                cherrypy.request.db, srcSoftwareProfileName,
                dstSoftwareProfileName)
        except Exception as ex:
            self._logger.exception(
                'software profile WS API copySoftwareProfile() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getUsableNodes(self, softwareProfileName):
        try:
            nodeList = self._softwareProfileManager.getUsableNodes(
                cherrypy.request.db, softwareProfileName)

            response = {'nodes': nodeList.getCleanDict()}
        except Exception as ex:
            self._logger.exception(
                'software profile WS API getUsableNodes() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)

    @authentication_required()
    @cherrypy.tools.json_out()
    @cherrypy.tools.json_in()
    def getNodes(self, softwareProfileName):
        try:
            nodeList = self._softwareProfileManager.getNodeList(
                cherrypy.request.db, softwareProfileName)

            response = {
                'nodes': nodeList,
            }
        except Exception as ex:
            self._logger.exception('software profile WS API getNodes() failed')

            self.handleException(ex)

            response = self.errorResponse(str(ex))

        return self.formatResponse(response)