Automation Blog

from Stefan Schnell

Categories are logical folder structures that help organize and manage the the platform-specific assets of the VCF Orchestrator in a clear and structured manner. Workflows, configurations (configuration elements), resources (resource elements) and user-defined types can be organized into categories. They can be structured hierarchically, like folders in a file system and access rights can also be assigned to them. This post presents a class that simplifies the handling of categories in Python.

Category Class for Python Runtime Environment

This class also contains several methods, including creation, reading, updating and deletion (CRUD) operations of categories. Also getPath and getId to find a way around the organizational structure.

Hint: Actions follow the software development paradigm (code & namespaces/modules), while workflows, resources and configurations are managed via folder structures, called categories.

"""
@author Stefan Schnell <mail@stefan-schnell.de>
@license MIT
@version 1.0
"""

import json

from .http import Http

class Category:
    """ Handles VCF Automation categories

    Category types:
    ConfigurationElementCategory = Configuration
    PolicyTemplateCategory       = Policy
    ResourceElementCategory      = Resource
    ScriptModuleCategory         = Action
    WorkflowCategory             = Workflow
    """

    def __init__(self):
        self.__http = Http()

    def getPath(
        self,
        vcoUrl: str,
        bearerToken: str,
        categoryId: str
    ) -> str:
        """ Gets the path of a category from its id

        @param {string} vcoUrl - URL of Aria orchestrator
        @param {string} bearerToken
        @param {string} categoryId - Id of the category
        @returns {string}
        """

        returnValue: str = ""

        try:

            returnValue = self.read(
                vcoUrl = vcoUrl,
                bearerToken = bearerToken,
                categoryId = categoryId
            )["path"]

        except Exception as err:
            raise ValueError(
                f"An error occurred at get path of a category - {err}"
            ) from err

        return returnValue

    def getId(
        self,
        vcoUrl: str,
        bearerToken: str,
        categoryType: str,
        categoryPath: str
    ) -> str:
        """ Gets the id of a category from its path

        @param {string} vcoUrl - URL of Aria orchestrator
        @param {string} bearerToken
        @param {string} categoryType - Type of the category
        @param {string} categoryPath - Path of the category
        @returns {string}
        """

        id: str | None = None
        returnValue: str = ""

        try:

            categories: dict = self.read(
                vcoUrl = vcoUrl,
                bearerToken = bearerToken,
                categoryType = categoryType
            )

            for category in categories["link"]:
                id = None
                for attribute in category["attributes"]:
                    if attribute["name"] == "id":
                        id = attribute["value"]

                if id is not None:

                    path: str = self.getPath(
                        vcoUrl = vcoUrl,
                        bearerToken = bearerToken,
                        categoryId = id
                    )

                    if path == categoryPath:
                        returnValue = id
                        break

        except Exception as err:
            raise ValueError(
                f"An error occurred at get id of a category - {err}"
            ) from err

        return returnValue

    def create(
        self,
        vcoUrl: str,
        bearerToken: str,
        categoryType: str,
        categoryName: str,
        parentCategoryId: str | None = None
    ) -> str | None:
        """ Creates a category and delivers the id of if

        @param {string} vcoUrl - URL of Aria orchestrator
        @param {string} bearerToken
        @param {string} categoryType - Type of the category
        @param {string} categoryName - Name of the category
        @param {string or None} parentCategoryId - Id of the parent category
        @returns {string or None}
        """

        returnValue: str | None = None

        try:

            body: dict = {
                "name": categoryName,
                "type": categoryType
            }

            if parentCategoryId is None:

                # Creates root category
                returnValue = self.__http.request(
                    url = vcoUrl + "/api/categories",
                    bearerToken = bearerToken,
                    method = "POST",
                    body = body
                )["id"]

            else:

                # Creates child category
                returnValue = self.__http.request(
                    url = vcoUrl + "/api/categories/" + parentCategoryId,
                    bearerToken = bearerToken,
                    method = "POST",
                    body = body
                )["id"]

        except Exception as err:
            raise ValueError(
                f"An error occurred at create category - {err}"
            ) from err

        return returnValue

    def read(
        self,
        vcoUrl: str,
        bearerToken: str,
        categoryType: str | None = None,
        categoryId: str | None = None
    ) -> dict | None:
        """ Reads a category

        @param {string} vcoUrl - URL of Aria orchestrator
        @param {string} bearerToken
        @param {string or None} categoryType - Type of the category
        @param {string or None} categoryId - Id of the category
        @returns {dict or None}
        """

        returnValue: dict | None = None

        try:

            url: str = vcoUrl + "/api/categories"

            if categoryType is not None and categoryId is None:
                url += "?categoryType=" + categoryType
            elif categoryType is None and categoryId is not None:
                url += "/" + categoryId
            elif categoryType is not None and categoryId is not None:
                url += "/" + categoryId + "?categoryType=" + categoryType

            returnValue = self.__http.request(
                url = url,
                bearerToken = bearerToken
            )

        except Exception as err:
            raise ValueError(
                f"An error occurred at read category - {err}"
            ) from err

        return returnValue

    def update(
        self,
        vcoUrl: str,
        bearerToken: str,
        categoryType: str,
        categoryId: str,
        parentCategoryId: str | None = None,
        newCategoryName: str = ""
    ):
        """ Updates a category

        @param {string} vcoUrl - URL of Aria orchestrator
        @param {string} bearerToken
        @param {string} categoryType - Type of the category
        @param {string} categoryId - Id of the category
        @param {string or None} parentCategoryId - Id of the parent
        @param {string} newCategoryName - New name of the category
        """

        try:

            body: dict = {}

            if parentCategoryId is None:

                # Updates root category
                body = {
                    "type": categoryType,
                    "name": newCategoryName
                }                

            elif parentCategoryId is not None:

                # Updates child category
                body = {
                    "type": categoryType,
                    "name": newCategoryName,
                    "parent-category-id": parentCategoryId
                }

            self.__http.request(
                url =  vcoUrl + "/api/categories/" + categoryId,
                bearerToken = bearerToken,
                method = "PUT",
                body = body
            )

        except Exception as err:
            raise ValueError(
                f"An error occurred at update category - {err}"
            ) from err

    def delete(
        self,
        vcoUrl: str,
        bearerToken: str,
        categoryId: str,
        force: bool = False
    ):
        """ Deletes a category

        @param {string} vcoUrl - URL of Aria orchestrator
        @param {string} bearerToken
        @param {string} categoryId - Id of the category
        @param {boolean} force
        """

        try:

            url: str = vcoUrl + "/api/categories/" + categoryId

            if force is True:
                url += "?deleteNonEmptyContent=true"
            elif force is False:
                url += "?deleteNonEmptyContent=false"

            self.__http.request(
                url = url,
                bearerToken = bearerToken,
                method = "DELETE"
            )

        except Exception as err:
            raise ValueError(
                f"An error occurred at delete category - {err}"
            ) from err

Conclusion

This Python class greatly simplifies the handling of categories and it can be used as an integration basis in VCF Automation. It can also be used in other environments that support Python.

References