aboutsummaryrefslogtreecommitdiffstats
path: root/src/onapsdk/clamp
diff options
context:
space:
mode:
Diffstat (limited to 'src/onapsdk/clamp')
-rw-r--r--src/onapsdk/clamp/__init__.py14
-rw-r--r--src/onapsdk/clamp/clamp_element.py79
-rw-r--r--src/onapsdk/clamp/loop_instance.py349
-rw-r--r--src/onapsdk/clamp/schema_details.json138
-rw-r--r--src/onapsdk/clamp/templates/clamp_MinMax_config.json.j294
-rw-r--r--src/onapsdk/clamp/templates/clamp_add_drools_policy.json.j2325
-rw-r--r--src/onapsdk/clamp/templates/clamp_add_frequency.json.j2102
-rw-r--r--src/onapsdk/clamp/templates/clamp_add_tca_config.json.j230
8 files changed, 1131 insertions, 0 deletions
diff --git a/src/onapsdk/clamp/__init__.py b/src/onapsdk/clamp/__init__.py
new file mode 100644
index 0000000..621adc9
--- /dev/null
+++ b/src/onapsdk/clamp/__init__.py
@@ -0,0 +1,14 @@
+"""ONAP SDK CLAMP package."""
+# Copyright 2022 Orange, Deutsche Telekom AG
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/src/onapsdk/clamp/clamp_element.py b/src/onapsdk/clamp/clamp_element.py
new file mode 100644
index 0000000..843db42
--- /dev/null
+++ b/src/onapsdk/clamp/clamp_element.py
@@ -0,0 +1,79 @@
+"""Clamp module."""
+# Copyright 2022 Orange, Deutsche Telekom AG
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from onapsdk.configuration import settings
+from onapsdk.onap_service import OnapService as Onap
+from onapsdk.sdc.service import Service
+from onapsdk.exceptions import ResourceNotFound
+from onapsdk.utils.headers_creator import headers_clamp_creator
+
+
+class Clamp(Onap):
+ """Mother Class of all CLAMP elements."""
+
+ #class variable
+ _base_url = settings.CLAMP_URL
+ name: str = "CLAMP"
+ headers = headers_clamp_creator(Onap.headers)
+
+ @classmethod
+ def base_url(cls) -> str:
+ """Give back the base url of Clamp."""
+ return f"{cls._base_url}/restservices/clds/v2"
+
+ @classmethod
+ def check_loop_template(cls, service: Service) -> str:
+ """
+ Return loop template name if exists.
+
+ Args:
+ service (Service): the distributed sdc service with tca blueprint artifact
+
+ Raises:
+ ResourceNotFound: Template not found.
+
+ Returns:
+ if required template exists in CLAMP or not
+
+ """
+ url = f"{cls.base_url()}/templates/"
+ for template in cls.send_message_json('GET',
+ 'Get Loop Templates',
+ url):
+ if template["modelService"]["serviceDetails"]["name"] == service.name:
+ return template["name"]
+ raise ResourceNotFound("Template not found.")
+
+ @classmethod
+ def check_policies(cls, policy_name: str, req_policies: int = 30) -> bool:
+ """
+ Ensure that a policy is stored in CLAMP.
+
+ Args:
+ policy_name (str): policy acronym
+ req_policies (int): number of required policies in CLAMP
+
+ Returns:
+ if required policy exists in CLAMP or not
+
+ """
+ url = f"{cls.base_url()}/policyToscaModels/"
+ policies = cls.send_message_json('GET',
+ 'Get stocked policies',
+ url)
+ exist_policy = False
+ for policy in policies:
+ if policy["policyAcronym"] == policy_name:
+ exist_policy = True
+ return (len(policies) >= req_policies) and exist_policy
diff --git a/src/onapsdk/clamp/loop_instance.py b/src/onapsdk/clamp/loop_instance.py
new file mode 100644
index 0000000..a72f9d1
--- /dev/null
+++ b/src/onapsdk/clamp/loop_instance.py
@@ -0,0 +1,349 @@
+"""Control Loop module."""
+# Copyright 2022 Orange, Deutsche Telekom AG
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import json
+from pathlib import Path
+from jsonschema import validate, ValidationError
+
+from onapsdk.clamp.clamp_element import Clamp
+from onapsdk.utils.jinja import jinja_env
+from onapsdk.exceptions import ParameterError
+
+CLAMP_UPDDATE_REFRESH_TIMER = 60
+
+class LoopInstance(Clamp):
+ """Control Loop instantiation class."""
+
+ # class variable
+ _loop_schema = None
+ operational_policies = ""
+
+ def __init__(self, template: str, name: str, details: dict) -> None:
+ """
+ Initialize loop instance object.
+
+ Args:
+ template (str): template from which we build the loop
+ name (str) : loop creation name
+ details (dict) : dictionnary containing all loop details
+
+ """
+ super().__init__()
+ self.template = template
+ self.name = "LOOP_" + name
+ self._details = details
+
+ @property
+ def details(self) -> dict:
+ """Return and lazy load the details."""
+ if not self._details:
+ self._update_loop_details()
+ return self._details
+
+ @details.setter
+ def details(self, details: dict) -> None:
+ """Set value for details."""
+ self._details = details
+
+ def _update_loop_details(self) -> dict:
+ """
+ Update loop details.
+
+ Returns:
+ the dictionnary of loop details
+
+ """
+ url = f"{self.base_url()}/loop/{self.name}"
+ loop_details = self.send_message_json('GET',
+ 'Get loop details',
+ url)
+ return loop_details
+
+ def refresh_status(self) -> None:
+ """Reshresh loop status."""
+ url = f"{self.base_url()}/loop/getstatus/{self.name}"
+ loop_details = self.send_message_json('GET',
+ 'Get loop status',
+ url)
+
+ self.details = loop_details
+
+ @property
+ def loop_schema(self) -> dict:
+ """
+ Return and lazy load the details schema.
+
+ Returns:
+ schema to be respected to accede to loop details
+
+ """
+ if not self._loop_schema:
+ schema_file = Path.cwd() / 'src' / 'onapsdk' / 'clamp' / 'schema_details.json'
+ with open(schema_file, "rb") as plan:
+ self._loop_schema = json.load(plan)
+ return self._loop_schema
+
+ def validate_details(self) -> bool:
+ """
+ Validate Loop Instance details.
+
+ Returns:
+ schema validation status (True, False)
+
+ """
+ try:
+ validate(self.details, self.loop_schema)
+ except ValidationError as error:
+ self._logger.error(error)
+ self._logger.error("---------")
+ self._logger.error(error.absolute_path)
+ self._logger.error("---------")
+ self._logger.error(error.absolute_schema_path)
+ return False
+ return True
+
+ def create(self) -> None:
+ """Create instance and load loop details."""
+ url = f"{self.base_url()}/loop/create/{self.name}?templateName={self.template}"
+ instance_details = self.send_message_json('POST',
+ 'Create Loop Instance',
+ url)
+ self.details = instance_details
+
+ def add_operational_policy(self, policy_type: str, policy_version: str) -> None:
+ """
+ Add operational policy to the loop instance.
+
+ Args:
+ policy_type (str): the full policy model type
+ policy_version (str): policy version
+
+ Raises:
+ ParameterError : Corrupt response or a key in a dictionary not found.
+ It will also be raised when the response contains more operational
+ policies than there are currently.
+
+ """
+ url = (f"{self.base_url()}/loop/addOperationaPolicy/{self.name}/"
+ f"policyModel/{policy_type}/{policy_version}")
+ add_response = self.send_message_json('PUT',
+ 'Create Operational Policy',
+ url)
+
+ key = "operationalPolicies"
+
+ try:
+ if self.details[key] is None:
+ self.details[key] = []
+
+ response_policies = add_response[key]
+ current_policies = self.details[key]
+ except KeyError as exc:
+ msg = 'Corrupt response, current loop details. Key not found.'
+ raise ParameterError(msg) from exc
+
+ if len(response_policies) > len(current_policies):
+ self.details = add_response
+ else:
+ raise ParameterError("Couldn't add the operational policy.")
+
+ def remove_operational_policy(self, policy_type: str, policy_version: str) -> None:
+ """
+ Remove operational policy from the loop instance.
+
+ Args:
+ policy_type (str): the full policy model type
+ policy_version (str): policy version
+
+ """
+ url = (f"{self.base_url()}/loop/removeOperationaPolicy/"
+ f"{self.name}/policyModel/{policy_type}/{policy_version}")
+ self.details = self.send_message_json('PUT',
+ 'Remove Operational Policy',
+ url)
+
+ def update_microservice_policy(self) -> None:
+ """
+ Update microservice policy configuration.
+
+ Update microservice policy configuration using payload data.
+
+ """
+ url = f"{self.base_url()}/loop/updateMicroservicePolicy/{self.name}"
+ template = jinja_env().get_template("clamp_add_tca_config.json.j2")
+ microservice_name = self.details["globalPropertiesJson"]["dcaeDeployParameters"]\
+ ["uniqueBlueprintParameters"]["policy_id"]
+ data = template.render(name=microservice_name,
+ LOOP_name=self.name)
+
+ self.send_message('POST',
+ 'ADD TCA config',
+ url,
+ data=data)
+
+ def extract_operational_policy_name(self, policy_type: str) -> str:
+ """
+ Return operational policy name for a closed loop and a given policy.
+
+ Args:
+ policy_type (str): the policy acronym.
+
+ Raises:
+ ParameterError : Couldn't load the operational policy name.
+
+ Returns:
+ Operational policy name in the loop details after adding a policy.
+
+ """
+ for policy in filter(lambda x: x["policyModel"]["policyAcronym"] == policy_type,
+ self.details["operationalPolicies"]):
+ return policy["name"]
+
+ raise ParameterError("Couldn't load the operational policy name.")
+
+ def add_drools_conf(self) -> dict:
+ """Add drools configuration."""
+ self.validate_details()
+ vfmodule_dicts = self.details["modelService"]["resourceDetails"]["VFModule"]
+ entity_ids = {}
+ #Get the vf module details
+ for vfmodule in vfmodule_dicts.values():
+ entity_ids["resourceID"] = vfmodule["vfModuleModelName"]
+ entity_ids["modelInvariantId"] = vfmodule["vfModuleModelInvariantUUID"]
+ entity_ids["modelVersionId"] = vfmodule["vfModuleModelUUID"]
+ entity_ids["modelName"] = vfmodule["vfModuleModelName"]
+ entity_ids["modelVersion"] = vfmodule["vfModuleModelVersion"]
+ entity_ids["modelCustomizationId"] = vfmodule["vfModuleModelCustomizationUUID"]
+ template = jinja_env().get_template("clamp_add_drools_policy.json.j2")
+ data = template.render(name=self.extract_operational_policy_name("Drools"),
+ resourceID=entity_ids["resourceID"],
+ modelInvariantId=entity_ids["modelInvariantId"],
+ modelVersionId=entity_ids["modelVersionId"],
+ modelName=entity_ids["modelName"],
+ modelVersion=entity_ids["modelVersion"],
+ modelCustomizationId=entity_ids["modelCustomizationId"],
+ LOOP_name=self.name)
+ return data
+
+ def add_minmax_config(self) -> None:
+ """Add MinMax operational policy config."""
+ #must configure start/end time and min/max instances in json file
+ template = jinja_env().get_template("clamp_MinMax_config.json.j2")
+ return template.render(name=self.extract_operational_policy_name("MinMax"))
+
+ def add_frequency_limiter(self, limit: int = 1) -> None:
+ """Add frequency limiter config."""
+ template = jinja_env().get_template("clamp_add_frequency.json.j2")
+ return template.render(name=self.extract_operational_policy_name("FrequencyLimiter"),
+ LOOP_name=self.name,
+ limit=limit)
+
+ def add_op_policy_config(self, func, **kwargs) -> None:
+ """
+ Add operational policy configuration.
+
+ Add operation policy configuration using payload data.
+
+ Args:
+ func (function): policy configuration function in (add_drools_conf,
+ add_minmax_config,
+ add_frequency_limiter)
+
+ """
+ data = func(**kwargs)
+ if not data:
+ raise ParameterError("Payload data from configuration is None.")
+ if self.operational_policies:
+ self.operational_policies = self.operational_policies[:-1] + ","
+ data = data[1:]
+ self.operational_policies += data
+ url = f"{self.base_url()}/loop/updateOperationalPolicies/{self.name}"
+ self.send_message('POST',
+ 'ADD operational policy config',
+ url,
+ data=self.operational_policies)
+
+ self._logger.info(("Files for op policy config %s have been uploaded to loop's"
+ "Op policy"), self.name)
+
+ def submit(self):
+ """Submit policies to policy engine."""
+ state = self.details["components"]["POLICY"]["componentState"]["stateName"]
+ return state == "SENT_AND_DEPLOYED"
+
+ def stop(self):
+ """Undeploy Policies from policy engine."""
+ state = self.details["components"]["POLICY"]["componentState"]["stateName"]
+ return state == "SENT"
+
+ def restart(self):
+ """Redeploy policies to policy engine."""
+ state = self.details["components"]["POLICY"]["componentState"]["stateName"]
+ return state == "SENT_AND_DEPLOYED"
+
+ def act_on_loop_policy(self, func) -> bool:
+ """
+ Act on loop's policy.
+
+ Args:
+ func (function): function of action to be done (submit, stop, restart)
+
+ Returns:
+ action state : failed or done
+
+ """
+ url = f"{self.base_url()}/loop/{func.__name__}/{self.name}"
+ self.send_message('PUT',
+ f'{func.__name__} policy',
+ url)
+ self.refresh_status()
+ self.validate_details()
+ return func()
+
+ def deploy_microservice_to_dcae(self) -> bool:
+ """
+ Execute the deploy operation on the loop instance.
+
+ Returns:
+ loop deploy on DCAE status (True, False)
+
+ """
+ url = f"{self.base_url()}/loop/deploy/{self.name}"
+ self.send_message('PUT',
+ 'Deploy microservice to DCAE',
+ url)
+ self.validate_details()
+ state = self.details["components"]["DCAE"]["componentState"]["stateName"]
+ failure = "MICROSERVICE_INSTALLATION_FAILED"
+ success = "MICROSERVICE_INSTALLED_SUCCESSFULLY"
+ while state not in (success, failure):
+ self.refresh_status()
+ self.validate_details()
+ state = self.details["components"]["DCAE"]["componentState"]["stateName"]
+ return state == success
+
+ def undeploy_microservice_from_dcae(self) -> None:
+ """Stop the deploy operation."""
+ url = f"{self.base_url()}/loop/undeploy/{self.name}"
+ self.send_message('PUT',
+ 'Undeploy microservice from DCAE',
+ url)
+
+ def delete(self) -> None:
+ """Delete the loop instance."""
+ self._logger.debug("Delete %s loop instance", self.name)
+ url = "{}/loop/delete/{}".format(self.base_url(), self.name)
+ self.send_message('PUT',
+ 'Delete loop instance',
+ url)
diff --git a/src/onapsdk/clamp/schema_details.json b/src/onapsdk/clamp/schema_details.json
new file mode 100644
index 0000000..3caea6c
--- /dev/null
+++ b/src/onapsdk/clamp/schema_details.json
@@ -0,0 +1,138 @@
+{
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "components": {
+ "type": "object",
+ "properties": {
+ "POLICY": {
+ "type": "object",
+ "properties": {
+ "componentState": {
+ "type": "object",
+ "properties": {
+ "stateName": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "stateName"
+ ]
+ }
+ },
+ "required": [
+ "componentState"
+ ]
+ },
+ "DCAE": {
+ "type": "object",
+ "properties": {
+ "componentState": {
+ "type": "object",
+ "properties": {
+ "stateName": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "stateName"
+ ]
+ }
+ },
+ "required": [
+ "componentState"
+ ]
+ }
+ },
+ "required": [
+ "POLICY",
+ "DCAE"
+ ]
+ },
+ "modelService": {
+ "type": "object",
+ "properties": {
+ "resourceDetails": {
+ "type": "object",
+ "properties": {
+ "VFModule": {
+ "type": "object",
+ "properties": {
+ "resourceID": {
+ "type": "object",
+ "properties": {
+ "vfModuleModelName": {
+ "type": "string"
+ },
+ "vfModuleModelInvariantUUID": {
+ "type": "string"
+ },
+ "vfModuleModelUUID": {
+ "type": "string"
+ },
+ "vfModuleModelVersion": {
+ "type": "string"
+ },
+ "vfModuleModelCustomizationUUID": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "vfModuleModelName",
+ "vfModuleModelInvariantUUID",
+ "vfModuleModelUUID",
+ "vfModuleModelVersion",
+ "vfModuleModelCustomizationUUID"
+ ]
+ }
+ }
+ }
+ },
+ "required": [
+ "VFModule"
+ ]
+ }
+ },
+ "required": [
+ "resourceDetails"
+ ]
+ },
+ "operationalPolicies": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "name"
+ ]
+ }
+ },
+ "microServicePolicies": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "name"
+ ]
+ }
+ }
+ },
+ "required": [
+ "name",
+ "components",
+ "modelService",
+ "operationalPolicies",
+ "microServicePolicies"
+ ]
+ } \ No newline at end of file
diff --git a/src/onapsdk/clamp/templates/clamp_MinMax_config.json.j2 b/src/onapsdk/clamp/templates/clamp_MinMax_config.json.j2
new file mode 100644
index 0000000..2402ace
--- /dev/null
+++ b/src/onapsdk/clamp/templates/clamp_MinMax_config.json.j2
@@ -0,0 +1,94 @@
+[
+ {
+ "name": "{{ name }}",
+ "jsonRepresentation": {
+ "title": "onap.policies.controlloop.guard.common.MinMax",
+ "type": "object",
+ "description": "Supports Min/Max number of entity for scaling operations. Although min and max fields are marked as not\nrequired, you need to have at least one or the other.\n",
+ "required": [
+ "actor",
+ "operation",
+ "target"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The Control Loop id this applies to."
+ },
+ "actor": {
+ "type": "string",
+ "description": "Specifies the Actor the guard applies to."
+ },
+ "operation": {
+ "type": "string",
+ "description": "Specified the operation that the actor is performing the guard applies to."
+ },
+ "timeRange": {
+ "title": "tosca.datatypes.TimeInterval",
+ "type": "object",
+ "required": [
+ "start_time",
+ "end_time"
+ ],
+ "properties": {
+ "start_time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "end_time": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ },
+ "min": {
+ "type": "integer",
+ "description": "The minimum instances of this entity"
+ },
+ "max": {
+ "type": "integer",
+ "description": "The maximum instances of this entity"
+ },
+ "target": {
+ "type": "string",
+ "description": "The target entity that has scaling restricted"
+ }
+ }
+ },
+ "configurationsJson": {
+ "actor": "test",
+ "operation": "test",
+ "target": "test",
+ "timeRange": {
+ "start_time": "00:00:00",
+ "end_time": "01:00:00"
+ },
+ "min": 1,
+ "max": 10
+ },
+ "policyModel": {
+ "policyModelType": "onap.policies.controlloop.guard.common.MinMax",
+ "version": "1.0.0",
+ "policyAcronym": "MinMax",
+ "policyPdpGroup": {
+ "supportedPdpGroups": [
+ {
+ "defaultGroup": [
+ "xacml"
+ ]
+ }
+ ]
+ },
+ "createdDate": "2020-07-22T01:37:35.861060Z",
+ "updatedDate": "2020-07-22T01:37:51.719018Z",
+ "updatedBy": "Not found",
+ "createdBy": "Not found"
+ },
+ "createdDate": "2020-07-22T09:01:14.168344Z",
+ "updatedDate": "2020-07-22T09:01:14.168344Z",
+ "updatedBy": "clamp@clamp.onap.org",
+ "createdBy": "clamp@clamp.onap.org",
+ "pdpGroup": "defaultGroup",
+ "pdpSubgroup": "xacml"
+ }
+] \ No newline at end of file
diff --git a/src/onapsdk/clamp/templates/clamp_add_drools_policy.json.j2 b/src/onapsdk/clamp/templates/clamp_add_drools_policy.json.j2
new file mode 100644
index 0000000..40ca7cd
--- /dev/null
+++ b/src/onapsdk/clamp/templates/clamp_add_drools_policy.json.j2
@@ -0,0 +1,325 @@
+[
+ {
+ "name": "{{ name }}",
+ "jsonRepresentation": {
+ "title": "onap.policies.controlloop.operational.common.Drools",
+ "type": "object",
+ "description": "Operational policies for Drools PDP",
+ "required": [
+ "abatement",
+ "operations",
+ "trigger",
+ "timeout",
+ "id"
+ ],
+ "properties": {
+ "abatement": {
+ "type": "boolean",
+ "description": "Whether an abatement event message will be expected for the control loop from DCAE.",
+ "default": "false"
+ },
+ "operations": {
+ "type": "array",
+ "description": "List of operations to be performed when Control Loop is triggered.",
+ "items": {
+ "title": "onap.datatype.controlloop.Operation",
+ "type": "object",
+ "description": "An operation supported by an actor",
+ "required": [
+ "id",
+ "operation",
+ "retries",
+ "timeout"
+ ],
+ "properties": {
+ "failure_retries": {
+ "type": "string",
+ "description": "Points to the operation to invoke when the current operation has exceeded its max retries.",
+ "default": "final_failure_retries"
+ },
+ "id": {
+ "type": "string",
+ "description": "Unique identifier for the operation"
+ },
+ "failure_timeout": {
+ "type": "string",
+ "description": "Points to the operation to invoke when the time out for the operation occurs.",
+ "default": "final_failure_timeout"
+ },
+ "failure": {
+ "type": "string",
+ "description": "Points to the operation to invoke on Actor operation failure.",
+ "default": "final_failure"
+ },
+ "operation": {
+ "title": "onap.datatype.controlloop.Actor",
+ "type": "object",
+ "description": "An actor/operation/target definition",
+ "required": [
+ "target",
+ "actor",
+ "operation"
+ ],
+ "properties": {
+ "payload": {
+ "type": "object",
+ "description": "Name/value pairs of payload information passed by Policy to the actor",
+ "anyOf": [
+ {
+ "title": "User defined",
+ "properties": {
+
+ }
+ }
+ ]
+ },
+ "target": {
+ "title": "onap.datatype.controlloop.Target",
+ "type": "object",
+ "description": "Definition for a entity in A&AI to perform a control loop operation on",
+ "required": [
+ "targetType"
+ ],
+ "properties": {
+ "entityIds": {
+ "type": "object",
+ "description": "Map of values that identify the resource. If none are provided, it is assumed that the\nentity that generated the ONSET event will be the target.\n",
+ "anyOf": [
+ {
+ "title": "User defined",
+ "properties": {
+
+ }
+ },
+ {
+ "title": "VNF-ubuntu18agent_VF 0",
+ "properties": {
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "6daf6e05-fc26-4aa3-9f0b-d47cf3f37ece",
+ "readOnly": "True"
+ }
+ }
+ },
+ {
+ "title": "VFMODULE-Ubuntu18agentVf..base_ubuntu18..module-0",
+ "properties": {
+ "resourceID": {
+ "title": "Resource ID",
+ "type": "string",
+ "default": "Ubuntu18agentVf..base_ubuntu18..module-0",
+ "readOnly": "True"
+ },
+ "modelInvariantId": {
+ "title": "Model Invariant Id (ModelInvariantUUID)",
+ "type": "string",
+ "default": "2556faee-75dd-448f-8d2f-d4201a957e7c",
+ "readOnly": "True"
+ },
+ "modelVersionId": {
+ "title": "Model Version Id (ModelUUID)",
+ "type": "string",
+ "default": "98df9741-530a-486c-b156-b2cb62e6fc6c",
+ "readOnly": "True"
+ },
+ "modelName": {
+ "title": "Model Name",
+ "type": "string",
+ "default": "Ubuntu18agentVf..base_ubuntu18..module-0",
+ "readOnly": "True"
+ },
+ "modelVersion": {
+ "title": "Model Version",
+ "type": "string",
+ "default": "1",
+ "readOnly": "True"
+ },
+ "modelCustomizationId": {
+ "title": "Customization ID",
+ "type": "string",
+ "default": "ba567b66-e46b-4521-8fdd-54185cb21a7f",
+ "readOnly": "True"
+ }
+ }
+ }
+ ]
+ },
+ "targetType": {
+ "type": "string",
+ "description": "Category for the target type",
+ "enum": [
+ "VNF",
+ "VM",
+ "VFMODULE",
+ "PNF"
+ ]
+ }
+ }
+ },
+ "actor": {
+ "type": "string",
+ "description": "The actor performing the operation.",
+ "enum": [
+ "SDNR",
+ "SDNC",
+ "VFC",
+ "SO",
+ "APPC",
+ "CDS"
+ ],
+ "options": {
+ "enum_titles": [
+ "SDNR",
+ "SDNC",
+ "VFC",
+ "SO",
+ "APPC"
+ ]
+ }
+ },
+ "operation": {
+ "type": "string",
+ "description": "The operation the actor is performing.",
+ "enum": [
+ "BandwidthOnDemand",
+ "VF Module Delete",
+ "Reroute",
+ "VF Module Create",
+ "ModifyConfig",
+ "Rebuild",
+ "Restart",
+ "Migrate",
+ "Health-Check"
+ ],
+ "options": {
+ "enum_titles": [
+ "BandwidthOnDemand (SDNC operation)",
+ "VF Module Delete (SO operation)",
+ "Reroute (SDNC operation)",
+ "VF Module Create (SO operation)",
+ "ModifyConfig (APPC/VFC operation)",
+ "Rebuild (APPC operation)",
+ "Restart (APPC operation)",
+ "Migrate (APPC operation)",
+ "Health-Check (APPC operation)"
+ ]
+ }
+ }
+ }
+ },
+ "failure_guard": {
+ "type": "string",
+ "description": "Points to the operation to invoke when the current operation is blocked due to guard policy enforcement.",
+ "default": "final_failure_guard"
+ },
+ "retries": {
+ "type": "integer",
+ "description": "The number of retries the actor should attempt to perform the operation.",
+ "default": "0"
+ },
+ "timeout": {
+ "type": "integer",
+ "description": "The amount of time for the actor to perform the operation."
+ },
+ "failure_exception": {
+ "type": "string",
+ "description": "Points to the operation to invoke when the current operation causes an exception.",
+ "default": "final_failure_exception"
+ },
+ "description": {
+ "type": "string",
+ "description": "A user-friendly description of the intent for the operation"
+ },
+ "success": {
+ "type": "string",
+ "description": "Points to the operation to invoke on success. A value of \"final_success\" indicates and end to the operation.",
+ "default": "final_success"
+ }
+ }
+ },
+ "format": "tabs-top"
+ },
+ "trigger": {
+ "type": "string",
+ "description": "Initial operation to execute upon receiving an Onset event message for the Control Loop."
+ },
+ "timeout": {
+ "type": "integer",
+ "description": "Overall timeout for executing all the operations. This timeout should equal or exceed the total\ntimeout for each operation listed.\n"
+ },
+ "id": {
+ "type": "string",
+ "description": "The unique control loop id."
+ },
+ "controllerName": {
+ "type": "string",
+ "description": "Drools controller properties"
+ }
+ }
+ },
+ "configurationsJson": {
+ "abatement": false,
+ "operations": [
+ {
+ "failure_retries": "final_failure_retries",
+ "id": "policy-1-vfmodule-create",
+ "failure_timeout": "final_failure_timeout",
+ "failure": "final_failure",
+ "operation": {
+ "payload": {
+ "requestParameters": "{\"usePreload\":false,\"userParams\":[]}",
+ "configurationParameters": "[{\"ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[16].value\",\"oam-ip-addr\":\"$.vf-module-topology.vf-module-parameters.param[30].value\"}]"
+ },
+ "target": {
+ "entityIds": {
+ "resourceID": "{{ resourceID }}",
+ "modelInvariantId": "{{ modelInvariantId }}",
+ "modelVersionId": "{{ modelVersionId }}",
+ "modelName": "{{ modelName }}",
+ "modelVersion": "{{ modelVersion }}",
+ "modelCustomizationId": "{{ modelCustomizationId }}"
+ },
+ "targetType": "VFMODULE"
+ },
+ "actor": "SO",
+ "operation": "VF Module Create"
+ },
+ "failure_guard": "final_failure_guard",
+ "retries": 1,
+ "timeout": 300,
+ "failure_exception": "final_failure_exception",
+ "description": "test",
+ "success": "final_success"
+ }
+ ],
+ "trigger": "policy-1-vfmodule-create",
+ "timeout": 650,
+ "id": "{{ LOOP_name }}"
+ },
+ "policyModel": {
+ "policyModelType": "onap.policies.controlloop.operational.common.Drools",
+ "version": "1.0.0",
+ "policyAcronym": "Drools",
+ "policyPdpGroup": {
+ "supportedPdpGroups": [
+ {
+ "defaultGroup": [
+ "drools"
+ ]
+ }
+ ]
+ },
+ "createdDate": "2020-07-22T01:37:38.528901Z",
+ "updatedDate": "2020-07-22T01:37:51.752302Z",
+ "updatedBy": "Not found",
+ "createdBy": "Not found"
+ },
+ "createdDate": "2020-07-22T07:50:00.076714Z",
+ "updatedDate": "2020-07-22T07:50:00.076714Z",
+ "updatedBy": "clamp@clamp.onap.org",
+ "createdBy": "clamp@clamp.onap.org",
+ "pdpGroup": "defaultGroup",
+ "pdpSubgroup": "drools"
+ }
+] \ No newline at end of file
diff --git a/src/onapsdk/clamp/templates/clamp_add_frequency.json.j2 b/src/onapsdk/clamp/templates/clamp_add_frequency.json.j2
new file mode 100644
index 0000000..fabf9e6
--- /dev/null
+++ b/src/onapsdk/clamp/templates/clamp_add_frequency.json.j2
@@ -0,0 +1,102 @@
+[
+ {
+ "name": "{{ name }}",
+ "jsonRepresentation": {
+ "title": "onap.policies.controlloop.guard.common.FrequencyLimiter",
+ "type": "object",
+ "description": "Supports limiting the frequency of actions being taken by a Actor.",
+ "required": [
+ "actor",
+ "operation",
+ "limit",
+ "timeWindow",
+ "timeUnits"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The Control Loop id this applies to."
+ },
+ "actor": {
+ "type": "string",
+ "description": "Specifies the Actor the guard applies to."
+ },
+ "operation": {
+ "type": "string",
+ "description": "Specified the operation that the actor is performing the guard applies to."
+ },
+ "timeRange": {
+ "title": "tosca.datatypes.TimeInterval",
+ "type": "object",
+ "required": [
+ "start_time",
+ "end_time"
+ ],
+ "properties": {
+ "start_time": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "end_time": {
+ "type": "string",
+ "format": "date-time"
+ }
+ }
+ },
+ "limit": {
+ "type": "integer",
+ "description": "The limit",
+ "exclusiveMinimum": "0"
+ },
+ "timeWindow": {
+ "type": "integer",
+ "description": "The time window to count the actions against."
+ },
+ "timeUnits": {
+ "type": "string",
+ "description": "The units of time the window is counting.",
+ "enum": [
+ "second",
+ "minute",
+ "hour",
+ "day",
+ "week",
+ "month",
+ "year"
+ ]
+ }
+ }
+ },
+ "configurationsJson": {
+ "actor": "SO",
+ "operation": "VF Module Create",
+ "limit": {{ limit }},
+ "timeWindow": 10,
+ "timeUnits": "minute"
+ },
+ "policyModel": {
+ "policyModelType": "onap.policies.controlloop.guard.common.FrequencyLimiter",
+ "version": "1.0.0",
+ "policyAcronym": "FrequencyLimiter",
+ "policyPdpGroup": {
+ "supportedPdpGroups": [
+ {
+ "defaultGroup": [
+ "xacml"
+ ]
+ }
+ ]
+ },
+ "createdDate": "2020-07-22T01:37:35.106757Z",
+ "updatedDate": "2020-07-22T01:37:51.709386Z",
+ "updatedBy": "Not found",
+ "createdBy": "Not found"
+ },
+ "createdDate": "2020-07-22T08:27:34.576868Z",
+ "updatedDate": "2020-07-22T08:27:34.576868Z",
+ "updatedBy": "clamp@clamp.onap.org",
+ "createdBy": "clamp@clamp.onap.org",
+ "pdpGroup": "defaultGroup",
+ "pdpSubgroup": "xacml"
+ }
+] \ No newline at end of file
diff --git a/src/onapsdk/clamp/templates/clamp_add_tca_config.json.j2 b/src/onapsdk/clamp/templates/clamp_add_tca_config.json.j2
new file mode 100644
index 0000000..0919a6b
--- /dev/null
+++ b/src/onapsdk/clamp/templates/clamp_add_tca_config.json.j2
@@ -0,0 +1,30 @@
+{
+ "name": "{{ name }}",
+ "configurationsJson": {
+ "tca.policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyScope": "DCAE",
+ "thresholds": [
+ {
+ "version": "1.0.2",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "{{ LOOP_name }}",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta"
+ }
+ ],
+ "eventName": "vLoadBalancer",
+ "policyVersion": "v0.0.1",
+ "controlLoopSchemaType": "VM",
+ "policyName": "DCAE.Config_tca-hi-lo"
+ }
+ ]
+ }
+ },
+ "pdpGroup": "defaultGroup",
+ "pdpSubgroup": "xacml"
+}