Source code for idem_vra.states.vra.abx.actions

from typing import Any

from idem_vra.helpers.mapper import add_properties
from idem_vra.helpers.mapper import omit_properties
from idem_vra.helpers.models import StateReturn


__contracts__ = ["resource"]

TREQ = {"present": {"require": ["vra.iaas.project.present"]}, "absent": {"require": []}}


async def present(hub, ctx, name: str, actionType: Any, orgId: Any, **kwargs):

    """

    :param string actionType: (required in body) Type of the action

    :param string name: (required in body) Name of the action

    :param string orgId: (required in body) Organization ID of the action.

    :param boolean asyncDeployed: (optional in body)

    :param string compressedContent: (optional in body) base64encoded ZIP of action content (source & dependencies)

    :param object configuration: (optional in body) Configuration of the action for specific providers

    :param string contentId: (optional in body) ID of the actions saved compressed content

    :param string dependencies: (optional in body) A list of libraries to import, delimited by a comma

    :param string description: (optional in body) Description of the action

    :param string entrypoint: (optional in body) Name of the entry function of the action

    :param string id: (optional in body) ID of the action

    :param object inputs: (optional in body) Map defining the inputs of the action

    :param integer memoryInMB: (optional in body) Runtime RAM constraints in megabytes

    :param object metadata: (optional in body) Additional properties used by ABX

    :param integer prePolyglotMemoryLimitInMB: (optional in body)

    :param string projectId: (optional in body) Project Id of the action (required for non-system actions)

    :param string provider: (optional in body) Provider used for code execution

    :param string runtime: (optional in body) Runtime of the action (python, nodejs, etc...)

    :param boolean scalable: (optional in body)

    :param string selfLink: (optional in body)

    :param boolean shared: (optional in body) Flag indicating if the action can be shared across projects.

    :param boolean showMemoryAlert: (optional in body)

    :param string source: (optional in body) Source of the action as string

    :param boolean system: (optional in body) Flag indicating if the action is a system action.

    :param integer timeoutSeconds: (optional in body) Defines how long an action can run (default 600)

    """

    try:
        state = ActionsStateImpl(hub, ctx)
        return await state.present(hub, ctx, name, actionType, orgId, **kwargs)
    except Exception as error:
        hub.log.error("Error during enforcing present state: actions")
        hub.log.error(str(error))
        raise error


[docs]async def absent(hub, ctx, name: str, **kwargs): """ :param string p_id: (required in path) ID of the action :param string q_projectId: (required in query) Project ID of action (required for non-system actions) :param boolean force: (optional in query) force """ """ :param string name: (required) name of the resource """ try: state = ActionsStateImpl(hub, ctx) return await state.absent(hub, ctx, name, **kwargs) except Exception as error: hub.log.error("Error during enforcing absent state: actions") hub.log.error(str(error)) raise error
[docs]async def describe(hub, ctx): try: state = ActionsStateImpl(hub, ctx) return await state.describe(hub, ctx) except Exception as error: hub.log.error("Error during describe: actions") hub.log.error(str(error)) raise error
[docs]def is_pending(hub, ret: dict, state: str = None, **pending_kwargs): try: state = ActionsStateImpl(hub, None) return state.is_pending(hub, ret, state, **pending_kwargs) except Exception as error: hub.log.error("Error during is_pending: actions") hub.log.error(str(error)) raise error
[docs]class ActionsState: def __init__(self, hub, ctx): self.hub = hub self.ctx = ctx
[docs] async def present(self, hub, ctx, name: str, actionType: Any, orgId: Any, **kwargs): search_result = (await self.paginate_find(hub, ctx))["ret"] for s in search_result.content: if name == s["name"] and True: hub.log.info( f'Returning resource actions "{s["name"]}" due to existing resource "{name}"' ) s = await self.remap_resource_structure(hub, ctx, s) return StateReturn( result=True, comment=f"Resource actions {name} already exists.", old=s, new=s, ) res = ( await hub.exec.vra.abx.actions.create_using_post( ctx, actionType, name, orgId, **kwargs ) )["ret"] res = await self.remap_resource_structure(hub, ctx, res) return StateReturn( result=True, comment=f"Creation of actions {name} success.", old=None, new=res, )
[docs] async def absent(self, hub, ctx, name: str, **kwargs): search_result = (await self.paginate_find(hub, ctx))["ret"] resource = None for s in search_result.content: if name == s["name"] and True: hub.log.info( f'Found resource actions "{s["name"]}" due to existing resource "{name}"' ) s = await self.remap_resource_structure(hub, ctx, s) resource = s if resource: # it exists! delete_kwargs = {} delete_kwargs["p_id"] = resource.get("id") delete_kwargs["q_projectId"] = resource.get("q_projectId") hub.log.debug(f"actions with name = {resource.get('name')} already exists") await hub.exec.vra.abx.actions.delete_using_delete1(ctx, **delete_kwargs) return StateReturn( result=True, comment=f"Resource with name = {resource.get('name')} deleted.", old=resource, new=None, ) return StateReturn( result=True, comment=f"Resource with name = {name} is already absent.", old=None, new=None, )
[docs] async def describe(self, hub, ctx): result = {} res = await self.paginate_find(hub, ctx) for obj in res.get("ret", {}).get("content", []): # Keep track of name and id properties as they may get remapped obj_name = obj.get("name", "unknown") obj_id = obj.get("id", "unknown") obj = await self.remap_resource_structure(hub, ctx, obj) # Define props props = [{key: value} for key, value in obj.items()] # Build result result[f"{obj_name}-{obj_id.split('-')[-1]}"] = { "vra.abx.actions.present": props } return result
[docs] async def paginate_find(self, hub, ctx, **kwargs): """ Paginate through all resources using their 'find' method. """ res = await hub.exec.vra.abx.actions.get_all_using_get(ctx, **kwargs) numberOfElements = res.get("ret", {}).get("numberOfElements", 0) totalElements = res.get("ret", {}).get("totalElements", 0) initialElements = numberOfElements if numberOfElements != totalElements and totalElements != 0: while initialElements < totalElements: hub.log.debug( f"Requesting actions with offset={initialElements} out of {totalElements}" ) pres = await hub.exec.vra.abx.actions.get_all_using_get( ctx, skip=initialElements ) initialElements += pres.get("ret", {}).get("numberOfElements", 0) aggO = res.get("ret", {}).get("content", []) aggN = pres.get("ret", {}).get("content", []) res["ret"]["content"] = [*aggO, *aggN] res["ret"]["numberOfElements"] = initialElements return res
[docs] def is_pending(self, hub, ret: dict, state: str = None, **pending_kwargs): """ State reconciliation """ hub.log.debug(f'Running is_pending for resource: {ret.get("__id__", None)}...') is_pending_result = False hub.log.debug( f'is_pending_result for resource "{ret.get("__id__", None)}": {is_pending_result}' ) return is_pending_result
[docs] async def remap_resource_structure(self, hub, ctx, obj: dict) -> dict: schema_mapper = {"add": [], "omit": ["selfLink", "contentId"]} # Perform resource mapping by adding properties and omitting properties. # Property renaming is addition followed by omission. if schema_mapper: resource_name = "actions" hub.log.debug(f"Remapping resource {resource_name}...") obj = await add_properties(obj, schema_mapper.get("add", [])) obj = omit_properties(obj, schema_mapper.get("omit", [])) return obj
# ==================================== # State override # ==================================== import gzip import base64 from idem_vra.helpers.models import StateReturn # Adding this function to override , # because out of box has orgId as mandate , But we need to have name and projectId as mandate
[docs]async def present(hub, ctx, name: str, **kwargs): try: state = ActionsStateImpl(hub, ctx) return await state.present(hub, ctx, name, **kwargs) except Exception as error: hub.log.error("Error during enforcing present state: actions") hub.log.error(str(error)) raise error
[docs]class ActionsStateImpl(ActionsState):
[docs] async def paginate_find(self, hub, ctx, **kwargs): """ Paginate through all resources using their 'find' method. """ res = await hub.exec.vra.abx.actions.get_all_using_get(ctx, **kwargs) total_pages = res["ret"]["totalPages"] page_list = list(range(1, total_pages + 1)) for i in page_list: new_data = await hub.exec.vra.abx.actions.get_all_using_get(ctx, page=i) for j in new_data["ret"]["content"]: res["ret"]["content"].append(j) return res
[docs] async def present(self, hub, ctx, name: str, **kwargs): # Search function to check all inventory search_result = (await self.paginate_find(hub, ctx))["ret"] for s in search_result.content: if name == s["name"] and True: hub.log.info( f'Returning resource actions "{s["name"]}" due to existing resource "{name}"' ) s = await self.remap_resource_structure(hub, ctx, s) return StateReturn( result=True, comment=f"Resource actions {name} already exists.", old=s, new=s, ) payload = {"name": name} # adding all extra parameters to payload for key, value in kwargs.items(): payload[key] = value # checking if Bundle is part of sls payload or not if "bundle" in payload.keys(): for bundle in payload["bundle"]: byte_encoded_data = hub.tool.binary_data.read_binary(bundle) compressed_data = gzip.compress(byte_encoded_data) base64_data = base64.b64encode(compressed_data).decode("utf-8") payload["compressedContent"] = base64_data res = await hub.exec.vra.rest.request( ctx, method="post", path="/abx/api/resources/actions", json=payload ) res = await self.remap_resource_structure(hub, ctx, res) return StateReturn( result=True, comment=f"Creation of actions {name} success.", old=None, new=res, )
[docs] async def absent(self, hub, ctx, name: str, **kwargs): search_result = (await self.paginate_find(hub, ctx))["ret"] resource = None for s in search_result.content: if name == s["name"] and True: hub.log.info( f'Found resource actions "{s["name"]}" due to existing resource "{name}"' ) s = await self.remap_resource_structure(hub, ctx, s) resource = s if resource: # it exists! hub.log.debug(f"actions with name = {resource.get('name')} already exists") await hub.exec.vra.abx.actions.delete_using_delete1( ctx, resource["id"], resource["projectId"], ) return StateReturn( result=True, comment=f"Resource with name = {resource.get('name')} deleted.", old=resource, new=None, ) return StateReturn( result=True, comment=f"Resource with name = {name} is already absent.", old=None, new=None, )
[docs] async def describe(self, hub, ctx): result = {} data = await self.paginate_find(hub, ctx) # Removing System ABX action from main payload res = [d for d in data["ret"]["content"] if not d["system"]] for i in res: if i["contentId"] is not None: data = { "actions": [ { "id": i["id"], "orgId": i["orgId"], "projectId": i["projectId"], } ] } export_action = await hub.exec.vra.rest.request( ctx, method="post", path="/abx/api/resources/actions/export", json=data, ) # Added dummy uri for this used case uri = 'file://' extracted_files = hub.tool.binary_data.write_binary( uri="zip://", byte_data=export_action["ret"], extract_all_with_extension=".zip", ) i["bundle"] = extracted_files for obj in res: # Keep track of name and id properties as they may get remapped obj_name = obj.get("name", "unknown") obj_id = obj.get("id", "unknown") obj = await self.remap_resource_structure(hub, ctx, obj) # Define props props = [{key: value} for key, value in obj.items()] # Build result result[f"{obj_name}-{obj_id.split('-')[-1]}"] = { "vra.abx.actions.present": props } return result