Seed code 53/8053/4
authorelinuxhenrik <henrik.b.andersson@est.tech>
Thu, 7 Apr 2022 15:01:47 +0000 (17:01 +0200)
committerelinuxhenrik <henrik.b.andersson@est.tech>
Tue, 12 Apr 2022 05:53:28 +0000 (07:53 +0200)
Issue-ID: NONRTRIC-711
Signed-off-by: elinuxhenrik <henrik.b.andersson@est.tech>
Change-Id: Id092873336a6fd564ae702b4bb0e47395ab595f8

111 files changed:
.gitignore [new file with mode: 0644]
apexpolicyversion/LinkMonitor/config/LinkMonitorConfigDmaap2RestJsonEvent.json [new file with mode: 0644]
apexpolicyversion/LinkMonitor/controlloop-rest-payloads/commission.yaml [new file with mode: 0644]
apexpolicyversion/LinkMonitor/controlloop-rest-payloads/instantiation-command.json [new file with mode: 0644]
apexpolicyversion/LinkMonitor/controlloop-rest-payloads/instantiation.json [new file with mode: 0644]
apexpolicyversion/LinkMonitor/deployment/DeployPolicyPAP.json [new file with mode: 0644]
apexpolicyversion/LinkMonitor/deployment/ToscaPolicy.json [new file with mode: 0644]
apexpolicyversion/LinkMonitor/docker-compose-controlloop/config/ks.jks [new file with mode: 0644]
apexpolicyversion/LinkMonitor/docker-compose-controlloop/docker-compose.yml [new file with mode: 0644]
apexpolicyversion/LinkMonitor/docker-compose-controlloop/wait_for_port.sh [new file with mode: 0644]
apexpolicyversion/LinkMonitor/events/LinkClearedEvent.json [new file with mode: 0644]
apexpolicyversion/LinkMonitor/events/LinkFailureEvent.json [new file with mode: 0644]
apexpolicyversion/LinkMonitor/events/SomeOtherEvent.json [new file with mode: 0644]
apexpolicyversion/LinkMonitor/models/CreateLinkClearedOutfieldsLogic.js [new file with mode: 0644]
apexpolicyversion/LinkMonitor/models/CreateLinkFailureOutfieldsLogic.js [new file with mode: 0644]
apexpolicyversion/LinkMonitor/models/LinkClearedLogic.js [new file with mode: 0644]
apexpolicyversion/LinkMonitor/models/LinkFailureLogic.js [new file with mode: 0644]
apexpolicyversion/LinkMonitor/models/LinkMonitorModelJavascript_0.0.1.apex [new file with mode: 0644]
apexpolicyversion/LinkMonitor/models/NoPolicyDefinedLogic.js [new file with mode: 0644]
apexpolicyversion/LinkMonitor/models/TaskSelectionLogic.js [new file with mode: 0644]
apexpolicyversion/LinkMonitor/schemas/LinkFailureInputSchema.avsc [new file with mode: 0644]
apexpolicyversion/LinkMonitor/schemas/LinkFailureOutputSchema.avsc [new file with mode: 0644]
apexpolicyversion/LinkMonitor/tosca/ToscaTemplate.json [new file with mode: 0644]
goversion/.gitignore [new file with mode: 0644]
goversion/Dockerfile [new file with mode: 0644]
goversion/Dockerfile-ics [new file with mode: 0644]
goversion/Dockerfile-producer [new file with mode: 0644]
goversion/Dockerfile-sdnr [new file with mode: 0644]
goversion/LICENSE.txt [new file with mode: 0644]
goversion/README.md [new file with mode: 0644]
goversion/build-oruclosedloopconsumer-ubuntu.sh [new file with mode: 0644]
goversion/container-tag.yaml [new file with mode: 0644]
goversion/docker-compose.yaml [new file with mode: 0644]
goversion/go.mod [new file with mode: 0644]
goversion/go.sum [new file with mode: 0644]
goversion/internal/config/config.go [new file with mode: 0644]
goversion/internal/config/config_test.go [new file with mode: 0644]
goversion/internal/linkfailure/linkfailurehandler.go [new file with mode: 0644]
goversion/internal/linkfailure/linkfailurehandler_test.go [new file with mode: 0644]
goversion/internal/repository/csvhelp.go [new file with mode: 0644]
goversion/internal/repository/csvhelp_test.go [new file with mode: 0644]
goversion/internal/repository/lookupservice.go [new file with mode: 0644]
goversion/internal/repository/lookupservice_test.go [new file with mode: 0644]
goversion/internal/restclient/client.go [new file with mode: 0644]
goversion/internal/restclient/client_test.go [new file with mode: 0644]
goversion/internal/ves/decoder.go [new file with mode: 0644]
goversion/internal/ves/decoder_test.go [new file with mode: 0644]
goversion/internal/ves/message.go [new file with mode: 0644]
goversion/internal/ves/message_test.go [new file with mode: 0644]
goversion/main.go [new file with mode: 0644]
goversion/main_test.go [new file with mode: 0644]
goversion/mocks/CsvFileHelper.go [new file with mode: 0644]
goversion/mocks/HTTPClient.go [new file with mode: 0644]
goversion/mocks/LookupService.go [new file with mode: 0644]
goversion/o-ru-to-o-du-map.csv [new file with mode: 0644]
goversion/security/consumer.crt [new file with mode: 0644]
goversion/security/consumer.key [new file with mode: 0644]
scriptversion/LICENSE.txt [new file with mode: 0644]
scriptversion/README.md [new file with mode: 0644]
scriptversion/app/Dockerfile [new file with mode: 0644]
scriptversion/app/container-tag.yaml [new file with mode: 0644]
scriptversion/app/main.py [new file with mode: 0644]
scriptversion/app/o-ru-to-o-du-map.txt [new file with mode: 0644]
scriptversion/app/requirements.txt [new file with mode: 0644]
scriptversion/controlloop-rest-payloads/commission.yaml [new file with mode: 0644]
scriptversion/controlloop-rest-payloads/instantiation-command.json [new file with mode: 0644]
scriptversion/controlloop-rest-payloads/instantiation.json [new file with mode: 0644]
scriptversion/docker-compose-controlloop/README.md [new file with mode: 0644]
scriptversion/docker-compose-controlloop/config/db/bootstrap-database.sh [new file with mode: 0644]
scriptversion/docker-compose-controlloop/config/db/create-db.sql [new file with mode: 0644]
scriptversion/docker-compose-controlloop/config/ks.jks [new file with mode: 0644]
scriptversion/docker-compose-controlloop/docker-compose.yml [new file with mode: 0644]
scriptversion/docker-compose-controlloop/wait_for_port.sh [new file with mode: 0644]
scriptversion/docker-compose/README.md [new file with mode: 0644]
scriptversion/docker-compose/docker-compose.yaml [new file with mode: 0644]
scriptversion/docker-compose/start.sh [new file with mode: 0644]
scriptversion/helm/README.md [new file with mode: 0644]
scriptversion/helm/chartmuseum_init.sh [new file with mode: 0644]
scriptversion/helm/dmaap-mr/.helmignore [new file with mode: 0644]
scriptversion/helm/dmaap-mr/Chart.yaml [new file with mode: 0644]
scriptversion/helm/dmaap-mr/templates/_helpers.tpl [new file with mode: 0644]
scriptversion/helm/dmaap-mr/templates/deployment.yaml [new file with mode: 0644]
scriptversion/helm/dmaap-mr/templates/service.yaml [new file with mode: 0644]
scriptversion/helm/dmaap-mr/values.yaml [new file with mode: 0644]
scriptversion/helm/message-generator/.helmignore [new file with mode: 0644]
scriptversion/helm/message-generator/Chart.yaml [new file with mode: 0644]
scriptversion/helm/message-generator/templates/_helpers.tpl [new file with mode: 0644]
scriptversion/helm/message-generator/templates/deployment.yaml [new file with mode: 0644]
scriptversion/helm/message-generator/templates/service.yaml [new file with mode: 0644]
scriptversion/helm/message-generator/values.yaml [new file with mode: 0644]
scriptversion/helm/oru-app/.helmignore [new file with mode: 0644]
scriptversion/helm/oru-app/Chart.yaml [new file with mode: 0644]
scriptversion/helm/oru-app/templates/_helpers.tpl [new file with mode: 0644]
scriptversion/helm/oru-app/templates/deployment.yaml [new file with mode: 0644]
scriptversion/helm/oru-app/templates/service.yaml [new file with mode: 0644]
scriptversion/helm/oru-app/values.yaml [new file with mode: 0644]
scriptversion/helm/sdnr-simulator/.helmignore [new file with mode: 0644]
scriptversion/helm/sdnr-simulator/Chart.yaml [new file with mode: 0644]
scriptversion/helm/sdnr-simulator/templates/_helpers.tpl [new file with mode: 0644]
scriptversion/helm/sdnr-simulator/templates/deployment.yaml [new file with mode: 0644]
scriptversion/helm/sdnr-simulator/templates/service.yaml [new file with mode: 0644]
scriptversion/helm/sdnr-simulator/values.yaml [new file with mode: 0644]
scriptversion/helm/start.sh [new file with mode: 0644]
scriptversion/k8s/README.md [new file with mode: 0644]
scriptversion/k8s/linkfailure.yml [new file with mode: 0644]
scriptversion/k8s/start.sh [new file with mode: 0644]
scriptversion/simulators/Dockerfile-message-generator [new file with mode: 0644]
scriptversion/simulators/Dockerfile-sdnr-sim [new file with mode: 0644]
scriptversion/simulators/message_generator.py [new file with mode: 0644]
scriptversion/simulators/requirements.txt [new file with mode: 0644]
scriptversion/simulators/sdnr_simulator.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..5915080
--- /dev/null
@@ -0,0 +1,22 @@
+# Documentation
+.idea/
+.tox
+docs/_build/
+.DS_STORE
+.swagger*
+docs/offeredapis/swagger/README.md
+
+# Eclipse
+.checkstyle
+.classpath
+target/
+.sts4-cache
+.project
+.settings
+.pydevproject
+infer-out/
+
+.vscode
+.factorypath
+
+coverage.*
diff --git a/apexpolicyversion/LinkMonitor/config/LinkMonitorConfigDmaap2RestJsonEvent.json b/apexpolicyversion/LinkMonitor/config/LinkMonitorConfigDmaap2RestJsonEvent.json
new file mode 100644 (file)
index 0000000..56d204b
--- /dev/null
@@ -0,0 +1,95 @@
+{
+    "engineServiceParameters": {
+        "name": "LinkMonitorApexEngine",
+        "version": "0.0.1",
+        "id": 101,
+        "instanceCount": 1,
+        "deploymentPort": 12345,
+        "engineParameters": {
+            "executorParameters": {
+                "JAVASCRIPT": {
+                    "parameterClassName": "org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"
+                }
+            },
+            "contextParameters": {
+                "parameterClassName": "org.onap.policy.apex.context.parameters.ContextParameters",
+                "schemaParameters": {
+                    "Avro": {
+                        "parameterClassName": "org.onap.policy.apex.plugins.context.schema.avro.AvroSchemaHelperParameters"
+                    }
+                }
+            },
+            "taskParameters": [
+                {
+                    "key": "ORU-ODU-Map",
+                    "value": "{\"ERICSSON-O-RU-11220\": \"O-DU-1122\",
+                               \"ERICSSON-O-RU-11221\": \"O-DU-1122\",
+                               \"ERICSSON-O-RU-11222\": \"O-DU-1122\",
+                               \"ERICSSON-O-RU-11223\": \"O-DU-1122\",
+                               \"ERICSSON-O-RU-11224\": \"O-DU-1123\",
+                               \"ERICSSON-O-RU-11225\": \"O-DU-1123\",
+                               \"ERICSSON-O-RU-11226\": \"O-DU-1123\",
+                               \"ERICSSON-O-RU-11227\": \"O-DU-1124\",
+                               \"ERICSSON-O-RU-11228\": \"O-DU-1125\",
+                               \"ERICSSON-O-RU-11229\": \"O-DU-1125\"}"
+                }
+            ]
+        }
+    },
+    "eventOutputParameters": {
+        "RestProducer": {
+            "carrierTechnologyParameters": {
+                "carrierTechnology": "RESTCLIENT",
+                "parameterClassName": "org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters",
+                "parameters": {
+                    "url": "http://sdnr-sim:9990/rests/data/network-topology:network-topology/topology=topology-netconf/node={OduId}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions={OduId}/radio-resource-management-policy-ratio=rrm-pol-1",
+                    "httpMethod" : "PUT",
+                    "httpHeaders" : [
+                        ["Authorization", "Basic YWRtaW46S3A4Yko0U1hzek0wV1hsaGFrM2VIbGNzZTJnQXc4NHZhb0dHbUp2VXkyVQ=="]
+                    ]
+                }
+            },
+            "eventProtocolParameters": {
+                "eventProtocol": "JSON",
+                "parameters": {
+                    "pojoField": "LinkFailureOutput"
+                }
+            },
+            "eventNameFilter": "LinkFailureOutputEvent"
+        },
+        "StdOutProducer": {
+            "carrierTechnologyParameters": {
+                "carrierTechnology": "FILE",
+                "parameters": {
+                    "standardIo": true
+                }
+            },
+            "eventProtocolParameters": {
+                "eventProtocol": "JSON",
+                "parameters": {
+                    "pojoField": "message"
+                }
+            },
+            "eventNameFilter": "ApexMessageOutputEvent"
+        }
+    },
+    "eventInputParameters": {
+        "DMaaPConsumer": {
+            "carrierTechnologyParameters": {
+                "carrierTechnology": "RESTCLIENT",
+                "parameterClassName": "org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters",
+                "parameters": {
+                    "url": "http://onap-dmaap:3904/events/unauthenticated.SEC_FAULT_OUTPUT/users/link-monitor-nonrtric?timeout=15000&limit=100"
+                }
+            },
+            "eventProtocolParameters": {
+                "eventProtocol": "JSON",
+                "parameters": {
+                    "versionAlias": "version",
+                    "pojoField": "LinkFailureInput"
+                }
+            },
+            "eventName": "LinkFailureInputEvent"
+        }
+    }
+}
diff --git a/apexpolicyversion/LinkMonitor/controlloop-rest-payloads/commission.yaml b/apexpolicyversion/LinkMonitor/controlloop-rest-payloads/commission.yaml
new file mode 100644 (file)
index 0000000..c2731f4
--- /dev/null
@@ -0,0 +1,1594 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+data_types:
+  onap.datatypes.ToscaConceptIdentifier:
+    derived_from: tosca.datatypes.Root
+    properties:
+      name:
+        type: string
+        required: true
+      version:
+        type: string
+        required: true
+  onap.datatype.controlloop.Target:
+    derived_from: tosca.datatypes.Root
+    description: Definition for a entity in A&AI to perform a control loop operation on
+    properties:
+      targetType:
+        type: string
+        description: Category for the target type
+        required: true
+        constraints:
+        - valid_values:
+          - VNF
+          - VM
+          - VFMODULE
+          - PNF
+      entityIds:
+        type: map
+        description: |
+          Map of values that identify the resource. If none are provided, it is assumed that the
+          entity that generated the ONSET event will be the target.
+        required: false
+        metadata:
+          clamp_possible_values: ClampExecution:CSAR_RESOURCES
+        entry_schema:
+          type: string
+  onap.datatype.controlloop.Actor:
+    derived_from: tosca.datatypes.Root
+    description: An actor/operation/target definition
+    properties:
+      actor:
+        type: string
+        description: The actor performing the operation.
+        required: true
+        metadata:
+          clamp_possible_values: Dictionary:DefaultActors,ClampExecution:CDS/actor
+      operation:
+        type: string
+        description: The operation the actor is performing.
+        metadata:
+          clamp_possible_values: Dictionary:DefaultOperations,ClampExecution:CDS/operation
+        required: true
+      target:
+        type: onap.datatype.controlloop.Target
+        description: The resource the operation should be performed on.
+        required: true
+      payload:
+        type: map
+        description: Name/value pairs of payload information passed by Policy to the actor
+        required: false
+        metadata:
+          clamp_possible_values: ClampExecution:CDS/payload
+        entry_schema:
+          type: string
+  onap.datatype.controlloop.Operation:
+    derived_from: tosca.datatypes.Root
+    description: An operation supported by an actor
+    properties:
+      id:
+        type: string
+        description: Unique identifier for the operation
+        required: true
+      description:
+        type: string
+        description: A user-friendly description of the intent for the operation
+        required: false
+      operation:
+        type: onap.datatype.controlloop.Actor
+        description: The definition of the operation to be performed.
+        required: true
+      timeout:
+        type: integer
+        description: The amount of time for the actor to perform the operation.
+        required: true
+      retries:
+        type: integer
+        description: The number of retries the actor should attempt to perform the operation.
+        required: true
+        default: 0
+      success:
+        type: string
+        description: Points to the operation to invoke on success. A value of "final_success" indicates and end to the operation.
+        required: false
+        default: final_success
+      failure:
+        type: string
+        description: Points to the operation to invoke on Actor operation failure.
+        required: false
+        default: final_failure
+      failure_timeout:
+        type: string
+        description: Points to the operation to invoke when the time out for the operation occurs.
+        required: false
+        default: final_failure_timeout
+      failure_retries:
+        type: string
+        description: Points to the operation to invoke when the current operation has exceeded its max retries.
+        required: false
+        default: final_failure_retries
+      failure_exception:
+        type: string
+        description: Points to the operation to invoke when the current operation causes an exception.
+        required: false
+        default: final_failure_exception
+      failure_guard:
+        type: string
+        description: Points to the operation to invoke when the current operation is blocked due to guard policy enforcement.
+        required: false
+        default: final_failure_guard
+policy_types:
+  onap.policies.controlloop.operational.Common:
+    derived_from: tosca.policies.Root
+    version: 1.0.0
+    name: onap.policies.controlloop.operational.Common
+    description: |
+      Operational Policy for Control Loop execution. Originated in Frankfurt to support TOSCA Compliant
+      Policy Types. This does NOT support the legacy Policy YAML policy type.
+    properties:
+      id:
+        type: string
+        description: The unique control loop id.
+        required: true
+      timeout:
+        type: integer
+        description: |
+          Overall timeout for executing all the operations. This timeout should equal or exceed the total
+          timeout for each operation listed.
+        required: true
+      abatement:
+        type: boolean
+        description: Whether an abatement event message will be expected for the control loop from DCAE.
+        required: true
+        default: false
+      trigger:
+        type: string
+        description: Initial operation to execute upon receiving an Onset event message for the Control Loop.
+        required: true
+      operations:
+        type: list
+        description: List of operations to be performed when Control Loop is triggered.
+        required: true
+        entry_schema:
+          type: onap.datatype.controlloop.Operation
+  onap.policies.controlloop.operational.common.Apex:
+    derived_from: onap.policies.controlloop.operational.Common
+    type_version: 1.0.0
+    version: 1.0.0
+    name: onap.policies.controlloop.operational.common.Apex
+    description: Operational policies for Apex PDP
+    properties:
+      engineServiceParameters:
+        type: string
+        description: The engine parameters like name, instanceCount, policy implementation, parameters etc.
+        required: true
+      eventInputParameters:
+        type: string
+        description: The event input parameters.
+        required: true
+      eventOutputParameters:
+        type: string
+        description: The event output parameters.
+        required: true
+      javaProperties:
+        type: string
+        description: Name/value pairs of properties to be set for APEX if needed.
+        required: false
+node_types:
+  org.onap.policy.clamp.controlloop.Participant:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+  org.onap.policy.clamp.controlloop.ControlLoopElement:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        required: false
+        metadata:
+          common: true
+        description: Specifies the organization that provides the control loop element
+      participant_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+        metadata:
+          common: true
+      participantType:
+        type: onap.datatypes.ToscaConceptIdentifier
+        required: true
+        metadata:
+          common: true
+        description: The identity of the participant type that hosts this type of Control Loop Element
+      startPhase:
+        type: integer
+        required: false
+        constraints:
+          - greater_or_equal: 0
+        metadata:
+          common: true
+        description: A value indicating the start phase in which this control loop element will be started, the
+          first start phase is zero. Control Loop Elements are started in their start_phase order and stopped
+          in reverse start phase order. Control Loop Elements with the same start phase are started and
+          stopped simultaneously
+      uninitializedToPassiveTimeout:
+        type: integer
+        required: false
+        constraints:
+          - greater_or_equal: 0
+        default: 60
+        metadata:
+          common: true
+        description: The maximum time in seconds to wait for a state chage from uninitialized to passive
+      passiveToRunningTimeout:
+        type: integer
+        required: false
+        constraints:
+          - greater_or_equal: 0
+        default: 60
+        metadata:
+          common: true
+        description: The maximum time in seconds to wait for a state chage from passive to running
+      runningToPassiveTimeout:
+        type: integer
+        required: false
+        constraints:
+          - greater_or_equal: 0
+        default: 60
+        metadata:
+          common: true
+        description: The maximum time in seconds to wait for a state chage from running to passive
+      passiveToUninitializedTimeout:
+        type: integer
+        required: false
+        constraints:
+          - greater_or_equal: 0
+        default: 60
+        metadata:
+          common: true
+        description: The maximum time in seconds to wait for a state chage from passive to uninitialized
+  org.onap.policy.clamp.controlloop.ControlLoop:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        required: false
+        metadata:
+          common: true
+        description: Specifies the organization that provides the control loop element
+      elements:
+        type: list
+        required: true
+        metadata:
+          common: true
+        entry_schema:
+          type: onap.datatypes.ToscaConceptIdentifier
+        description: Specifies a list of control loop element definitions that make up this control loop definition
+  org.onap.policy.clamp.controlloop.PolicyControlLoopElement:
+    version: 1.0.1
+    derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement
+    properties:
+      policy_type_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+      policy_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: false
+topology_template:
+  node_templates:
+    org.onap.domain.linkmonitor.LinkMonitorPolicyControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.PolicyControlLoopElement
+      type_version: 1.0.1
+      description: Control loop element for the Link Monitor
+      properties:
+        provider: Ericsson
+        participant_id:
+          name: org.onap.PM_Policy
+          version: 1.0.0
+        participantType:
+          name: org.onap.policy.controlloop.PolicyControlLoopParticipant
+          version: 2.3.1
+        policy_type_id:
+          name: onap.policies.controlloop.operational.common.Apex
+          version: 1.0.0
+        policy_id:
+          name: operational.apex.linkmonitor
+          version: 1.0.0 
+        pdpGroup: defaultGroup
+    org.onap.domain.linkmonitor.LinkMonitorControlLoopDefinition0:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoop
+      type_version: 1.0.0
+      description: Control loop for Link Monitor
+      properties:
+        provider: Ericsson
+        elements:
+        - name: org.onap.domain.linkmonitor.LinkMonitorPolicyControlLoopElement
+          version: 1.2.3
+    org.onap.policy.controlloop.PolicyControlLoopParticipant:
+      version: 2.3.1
+      type: org.onap.policy.clamp.controlloop.Participant
+      type_version: 1.0.1
+      description: Participant for policy framework
+      properties:
+        provider: ONAP
+  policies:
+  - operational.apex.linkmonitor:
+      type: onap.policies.controlloop.operational.common.Apex
+      type_version: 1.0.0
+      version: 1.0.0
+      metadata:
+        policy-id: operational.apex.linkmonitor
+        policy-version: 1.0.0
+      properties:
+        engineServiceParameters:
+          name: LinkMonitorApexEngine
+          version: 0.0.1
+          id: 101
+          instanceCount: 1
+          deploymentPort: 12345
+          engineParameters:
+            executorParameters:
+              JAVASCRIPT:
+                parameterClassName: org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters
+            contextParameters:
+              parameterClassName: org.onap.policy.apex.context.parameters.ContextParameters
+              schemaParameters:
+                Avro:
+                  parameterClassName: org.onap.policy.apex.plugins.context.schema.avro.AvroSchemaHelperParameters
+            taskParameters:
+            - key: ORU-ODU-Map
+              value: |-
+                {"ERICSSON-O-RU-11220": "HCL-O-DU-1122",
+                                               "ERICSSON-O-RU-11221": "HCL-O-DU-1122",
+                                               "ERICSSON-O-RU-11222": "HCL-O-DU-1122",
+                                               "ERICSSON-O-RU-11223": "HCL-O-DU-1122",
+                                               "ERICSSON-O-RU-11224": "HCL-O-DU-1123",
+                                               "ERICSSON-O-RU-11225": "HCL-O-DU-1123",
+                                               "ERICSSON-O-RU-11226": "HCL-O-DU-1123",
+                                               "ERICSSON-O-RU-11227": "HCL-O-DU-1124",
+                                               "ERICSSON-O-RU-11228": "HCL-O-DU-1125",
+                                               "ERICSSON-O-RU-11229": "HCL-O-DU-1125"}
+          policy_type_impl:
+            apexPolicyModel:
+              key:
+                name: LinkMonitorModel
+                version: 0.0.1
+              keyInformation:
+                key:
+                  name: LinkMonitorModel_KeyInfo
+                  version: 0.0.1
+                keyInfoMap:
+                  entry:
+                  - key:
+                      name: ApexMessageOutputEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: ApexMessageOutputEvent
+                        version: 0.0.1
+                      UUID: cca47d74-7754-4a61-b163-ca31f66b157b
+                      description: Generated description for concept referred to by
+                        key "ApexMessageOutputEvent:0.0.1"
+                  - key:
+                      name: CreateLinkClearedOutfieldsEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: CreateLinkClearedOutfieldsEvent
+                        version: 0.0.1
+                      UUID: a295d6a3-1b73-387e-abba-b41e9b608802
+                      description: Generated description for concept referred to by
+                        key "CreateLinkClearedOutfieldsEvent:0.0.1"
+                  - key:
+                      name: CreateLinkClearedOutfieldsTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: CreateLinkClearedOutfieldsTask
+                        version: 0.0.1
+                      UUID: fd594e88-411d-4a94-b2be-697b3a0d7adf
+                      description: This task creates the output fields when link failure
+                        is cleared.
+                  - key:
+                      name: CreateLinkFailureOutfieldsEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: CreateLinkFailureOutfieldsEvent
+                        version: 0.0.1
+                      UUID: 02be2b5d-45b7-3c54-ae54-97f2b5c30125
+                      description: Generated description for concept referred to by
+                        key "CreateLinkFailureOutfieldsEvent:0.0.1"
+                  - key:
+                      name: CreateLinkFailureOutfieldsTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: CreateLinkFailureOutfieldsTask
+                        version: 0.0.1
+                      UUID: ac3d9842-80af-4a98-951c-bd79a431c613
+                      description: This task the output fields when link failure is
+                        detected.
+                  - key:
+                      name: LinkClearedTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkClearedTask
+                        version: 0.0.1
+                      UUID: eecfde90-896c-4343-8f9c-2603ced94e2d
+                      description: This task sends a message to the output when link
+                        failure is cleared.
+                  - key:
+                      name: LinkFailureInputEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureInputEvent
+                        version: 0.0.1
+                      UUID: c4500941-3f98-4080-a9cc-5b9753ed050b
+                      description: Generated description for concept referred to by
+                        key "LinkFailureInputEvent:0.0.1"
+                  - key:
+                      name: LinkFailureInputSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureInputSchema
+                        version: 0.0.1
+                      UUID: 3b3974fc-3012-3b02-9f33-c9d8eefe4dc1
+                      description: Generated description for concept referred to by
+                        key "LinkFailureInputSchema:0.0.1"
+                  - key:
+                      name: LinkFailureOutputEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureOutputEvent
+                        version: 0.0.1
+                      UUID: 4f04aa98-e917-4f4a-882a-c75ba5a99374
+                      description: Generated description for concept referred to by
+                        key "LinkFailureOutputEvent:0.0.1"
+                  - key:
+                      name: LinkFailureOutputSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureOutputSchema
+                        version: 0.0.1
+                      UUID: 2d1a7f6e-eb9a-3984-be1f-283d98111b84
+                      description: Generated description for concept referred to by
+                        key "LinkFailureOutputSchema:0.0.1"
+                  - key:
+                      name: LinkFailureTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureTask
+                        version: 0.0.1
+                      UUID: 3351b0f4-cf06-4fa2-8823-edf67bd30223
+                      description: This task updates the config for O-RU when link
+                        failure is detected.
+                  - key:
+                      name: LinkMonitorModel
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkMonitorModel
+                        version: 0.0.1
+                      UUID: 540226fb-55ee-4f0e-a444-983a0494818e
+                      description: This is the Apex Policy Model for link monitoring.
+                  - key:
+                      name: LinkMonitorModel_Events
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkMonitorModel_Events
+                        version: 0.0.1
+                      UUID: 27ad3e7e-fe3b-3bd6-9081-718705c2bcea
+                      description: Generated description for concept referred to by
+                        key "LinkMonitorModel_Events:0.0.1"
+                  - key:
+                      name: LinkMonitorModel_KeyInfo
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkMonitorModel_KeyInfo
+                        version: 0.0.1
+                      UUID: ea0b5f58-eefd-358a-9660-840c640bf981
+                      description: Generated description for concept referred to by
+                        key "LinkMonitorModel_KeyInfo:0.0.1"
+                  - key:
+                      name: LinkMonitorModel_Policies
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkMonitorModel_Policies
+                        version: 0.0.1
+                      UUID: ee9e0b0f-2b7d-3ab7-9a98-c5ec05ed823d
+                      description: Generated description for concept referred to by
+                        key "LinkMonitorModel_Policies:0.0.1"
+                  - key:
+                      name: LinkMonitorModel_Schemas
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkMonitorModel_Schemas
+                        version: 0.0.1
+                      UUID: fa5f9b8f-796c-3c70-84e9-5140c958c4bb
+                      description: Generated description for concept referred to by
+                        key "LinkMonitorModel_Schemas:0.0.1"
+                  - key:
+                      name: LinkMonitorModel_Tasks
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkMonitorModel_Tasks
+                        version: 0.0.1
+                      UUID: eec592f7-69d5-39a9-981a-e552f787ed01
+                      description: Generated description for concept referred to by
+                        key "LinkMonitorModel_Tasks:0.0.1"
+                  - key:
+                      name: LinkMonitorPolicy
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkMonitorPolicy
+                        version: 0.0.1
+                      UUID: 6c5e410f-489a-46ff-964e-982ce6e8b6d0
+                      description: Generated description for concept referred to by
+                        key "LinkMonitorPolicy:0.0.1"
+                  - key:
+                      name: MessageSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: MessageSchema
+                        version: 0.0.1
+                      UUID: ac4b34ac-39d6-3393-a267-8d5b84854018
+                      description: A schema for messages from apex
+                  - key:
+                      name: NoPolicyDefinedTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: NoPolicyDefinedTask
+                        version: 0.0.1
+                      UUID: d48b619e-d00d-4008-b884-02d76ea4350b
+                      description: This task sends a message to the output when an
+                        event is received for which no policy has been defined.
+                  - key:
+                      name: OduIdSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: OduIdSchema
+                        version: 0.0.1
+                      UUID: 50662174-a88b-3cbd-91bd-8e91b40b2660
+                      description: A schema for O-DU-ID
+                  - key:
+                      name: OruIdSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: OruIdSchema
+                        version: 0.0.1
+                      UUID: 54daf32b-015f-39cd-8530-a1175c5553e9
+                      description: A schema for O-RU-ID
+              policies:
+                key:
+                  name: LinkMonitorModel_Policies
+                  version: 0.0.1
+                policyMap:
+                  entry:
+                  - key:
+                      name: LinkMonitorPolicy
+                      version: 0.0.1
+                    value:
+                      policyKey:
+                        name: LinkMonitorPolicy
+                        version: 0.0.1
+                      template: Freestyle
+                      state:
+                        entry:
+                        - key: LinkClearedState
+                          value:
+                            stateKey:
+                              parentKeyName: LinkMonitorPolicy
+                              parentKeyVersion: 0.0.1
+                              parentLocalName: 'NULL'
+                              localName: LinkClearedState
+                            trigger:
+                              name: CreateLinkClearedOutfieldsEvent
+                              version: 0.0.1
+                            stateOutputs:
+                              entry:
+                              - key: LinkClearedLogic_Output_Direct
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkClearedState
+                                    localName: LinkClearedLogic_Output_Direct
+                                  outgoingEvent:
+                                    name: ApexMessageOutputEvent
+                                    version: 0.0.1
+                                  nextState:
+                                    parentKeyName: 'NULL'
+                                    parentKeyVersion: 0.0.0
+                                    parentLocalName: 'NULL'
+                                    localName: 'NULL'
+                            contextAlbumReference: []
+                            taskSelectionLogic:
+                              key: 'NULL'
+                              logicFlavour: UNDEFINED
+                              logic: ''
+                            stateFinalizerLogicMap:
+                              entry: []
+                            defaultTask:
+                              name: LinkClearedTask
+                              version: 0.0.1
+                            taskReferences:
+                              entry:
+                              - key:
+                                  name: LinkClearedTask
+                                  version: 0.0.1
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkClearedState
+                                    localName: LinkClearedTask
+                                  outputType: DIRECT
+                                  output:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkClearedState
+                                    localName: LinkClearedLogic_Output_Direct
+                        - key: LinkFailureOrClearedState
+                          value:
+                            stateKey:
+                              parentKeyName: LinkMonitorPolicy
+                              parentKeyVersion: 0.0.1
+                              parentLocalName: 'NULL'
+                              localName: LinkFailureOrClearedState
+                            trigger:
+                              name: LinkFailureInputEvent
+                              version: 0.0.1
+                            stateOutputs:
+                              entry:
+                              - key: CreateLinkClearedOutfieldsLogic_Output_Direct
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: CreateLinkClearedOutfieldsLogic_Output_Direct
+                                  outgoingEvent:
+                                    name: CreateLinkClearedOutfieldsEvent
+                                    version: 0.0.1
+                                  nextState:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: 'NULL'
+                                    localName: LinkClearedState
+                              - key: CreateLinkFailureOutfieldsLogic_Output_Direct
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: CreateLinkFailureOutfieldsLogic_Output_Direct
+                                  outgoingEvent:
+                                    name: CreateLinkFailureOutfieldsEvent
+                                    version: 0.0.1
+                                  nextState:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: 'NULL'
+                                    localName: LinkFailureState
+                              - key: NoPolicyDefinedLogic_Output_Direct
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: NoPolicyDefinedLogic_Output_Direct
+                                  outgoingEvent:
+                                    name: ApexMessageOutputEvent
+                                    version: 0.0.1
+                                  nextState:
+                                    parentKeyName: 'NULL'
+                                    parentKeyVersion: 0.0.0
+                                    parentLocalName: 'NULL'
+                                    localName: 'NULL'
+                            contextAlbumReference: []
+                            taskSelectionLogic:
+                              key: TaskSelectionLogic
+                              logicFlavour: JAVASCRIPT
+                              logic: |-
+                                /*
+                                 * ============LICENSE_START=======================================================
+                                 * Copyright (C) 2021 Nordix Foundation.
+                                 * ================================================================================
+                                 * 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.
+                                 *
+                                 * SPDX-License-Identifier: Apache-2.0
+                                 * ============LICENSE_END=========================================================
+                                 */
+
+                                executor.logger.info("Task Selection Execution: '"+executor.subject.id+
+                                    "'. InputFields: '"+executor.inFields+"'");
+
+                                var linkFailureInput = executor.inFields.get("LinkFailureInput");
+                                var commonEventHeader = linkFailureInput.get("event").get("commonEventHeader");
+                                var domain = commonEventHeader.get("domain");
+
+                                taskFailure = executor.subject.getTaskKey("CreateLinkFailureOutfieldsTask");
+                                taskCleared = executor.subject.getTaskKey("CreateLinkClearedOutfieldsTask");
+                                taskDefault = executor.subject.getDefaultTaskKey();
+
+                                if (domain == "fault") {
+                                    var faultFields = linkFailureInput.get("event").get("faultFields");
+                                    var alarmCondition = faultFields.get("alarmCondition");
+                                    var eventSeverity = faultFields.get("eventSeverity");
+                                    if (alarmCondition == "28" && eventSeverity != "NORMAL") {
+                                        taskFailure.copyTo(executor.selectedTask);
+                                    } else if (alarmCondition == "28" && eventSeverity == "NORMAL") {
+                                        taskCleared.copyTo(executor.selectedTask);
+                                    } else {
+                                        taskDefault.copyTo(executor.selectedTask);
+                                    }
+                                } else {
+                                    taskDefault.copyTo(executor.selectedTask);
+                                }
+
+                                true;
+                            stateFinalizerLogicMap:
+                              entry: []
+                            defaultTask:
+                              name: NoPolicyDefinedTask
+                              version: 0.0.1
+                            taskReferences:
+                              entry:
+                              - key:
+                                  name: CreateLinkClearedOutfieldsTask
+                                  version: 0.0.1
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: CreateLinkClearedOutfieldsTask
+                                  outputType: DIRECT
+                                  output:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: CreateLinkClearedOutfieldsLogic_Output_Direct
+                              - key:
+                                  name: CreateLinkFailureOutfieldsTask
+                                  version: 0.0.1
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: CreateLinkFailureOutfieldsTask
+                                  outputType: DIRECT
+                                  output:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: CreateLinkFailureOutfieldsLogic_Output_Direct
+                              - key:
+                                  name: NoPolicyDefinedTask
+                                  version: 0.0.1
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: NoPolicyDefinedTask
+                                  outputType: DIRECT
+                                  output:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureOrClearedState
+                                    localName: NoPolicyDefinedLogic_Output_Direct
+                        - key: LinkFailureState
+                          value:
+                            stateKey:
+                              parentKeyName: LinkMonitorPolicy
+                              parentKeyVersion: 0.0.1
+                              parentLocalName: 'NULL'
+                              localName: LinkFailureState
+                            trigger:
+                              name: CreateLinkFailureOutfieldsEvent
+                              version: 0.0.1
+                            stateOutputs:
+                              entry:
+                              - key: LinkFailureLogic_Output_Direct
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureState
+                                    localName: LinkFailureLogic_Output_Direct
+                                  outgoingEvent:
+                                    name: LinkFailureOutputEvent
+                                    version: 0.0.1
+                                  nextState:
+                                    parentKeyName: 'NULL'
+                                    parentKeyVersion: 0.0.0
+                                    parentLocalName: 'NULL'
+                                    localName: 'NULL'
+                            contextAlbumReference: []
+                            taskSelectionLogic:
+                              key: 'NULL'
+                              logicFlavour: UNDEFINED
+                              logic: ''
+                            stateFinalizerLogicMap:
+                              entry: []
+                            defaultTask:
+                              name: LinkFailureTask
+                              version: 0.0.1
+                            taskReferences:
+                              entry:
+                              - key:
+                                  name: LinkFailureTask
+                                  version: 0.0.1
+                                value:
+                                  key:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureState
+                                    localName: LinkFailureTask
+                                  outputType: DIRECT
+                                  output:
+                                    parentKeyName: LinkMonitorPolicy
+                                    parentKeyVersion: 0.0.1
+                                    parentLocalName: LinkFailureState
+                                    localName: LinkFailureLogic_Output_Direct
+                      firstState: LinkFailureOrClearedState
+              tasks:
+                key:
+                  name: LinkMonitorModel_Tasks
+                  version: 0.0.1
+                taskMap:
+                  entry:
+                  - key:
+                      name: CreateLinkClearedOutfieldsTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: CreateLinkClearedOutfieldsTask
+                        version: 0.0.1
+                      inputFields:
+                        entry:
+                        - key: LinkFailureInput
+                          value:
+                            key: LinkFailureInput
+                            fieldSchemaKey:
+                              name: LinkFailureInputSchema
+                              version: 0.0.1
+                            optional: false
+                      outputFields:
+                        entry:
+                        - key: OruId
+                          value:
+                            key: OruId
+                            fieldSchemaKey:
+                              name: OruIdSchema
+                              version: 0.0.1
+                            optional: false
+                      taskParameters:
+                        entry: []
+                      contextAlbumReference: []
+                      taskLogic:
+                        key: TaskLogic
+                        logicFlavour: JAVASCRIPT
+                        logic: |-
+                          /*
+                           * ============LICENSE_START=======================================================
+                           * Copyright (C) 2021 Nordix Foundation.
+                           * ================================================================================
+                           * 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.
+                           *
+                           * SPDX-License-Identifier: Apache-2.0
+                           * ============LICENSE_END=========================================================
+                           */
+
+                          executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+                          var linkFailureInput = executor.inFields.get("LinkFailureInput");
+                          var oruId = linkFailureInput.get("event").get("commonEventHeader").get("sourceName");
+
+                          executor.outFields.put("OruId", oruId);
+
+                          executor.logger.info(executor.outFields);
+
+                          true;
+                  - key:
+                      name: CreateLinkFailureOutfieldsTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: CreateLinkFailureOutfieldsTask
+                        version: 0.0.1
+                      inputFields:
+                        entry:
+                        - key: LinkFailureInput
+                          value:
+                            key: LinkFailureInput
+                            fieldSchemaKey:
+                              name: LinkFailureInputSchema
+                              version: 0.0.1
+                            optional: false
+                      outputFields:
+                        entry:
+                        - key: OduId
+                          value:
+                            key: OduId
+                            fieldSchemaKey:
+                              name: OduIdSchema
+                              version: 0.0.1
+                            optional: false
+                        - key: OruId
+                          value:
+                            key: OruId
+                            fieldSchemaKey:
+                              name: OruIdSchema
+                              version: 0.0.1
+                            optional: false
+                      taskParameters:
+                        entry: []
+                      contextAlbumReference: []
+                      taskLogic:
+                        key: TaskLogic
+                        logicFlavour: JAVASCRIPT
+                        logic: |-
+                          /*
+                           * ============LICENSE_START=======================================================
+                           * Copyright (C) 2021 Nordix Foundation.
+                           * ================================================================================
+                           * 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.
+                           *
+                           * SPDX-License-Identifier: Apache-2.0
+                           * ============LICENSE_END=========================================================
+                           */
+
+                          executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+                          var returnValue = true;
+                          var linkFailureInput = executor.inFields.get("LinkFailureInput");
+                          var oruId = linkFailureInput.get("event").get("commonEventHeader").get("sourceName");
+                          var oruOduMap = JSON.parse(executor.parameters.get("ORU-ODU-Map"));
+
+                          if (oruId in oruOduMap) {
+                              var oduId = oruOduMap[oruId];
+                              executor.outFields.put("OruId", oruId);
+                              executor.outFields.put("OduId", oduId);
+                              executor.logger.info(executor.outFields);
+                          } else {
+                              executor.message = "No O-RU found in the config with this ID: " + oruId;
+                              returnValue = false;
+                          }
+
+                          returnValue;
+                  - key:
+                      name: LinkClearedTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkClearedTask
+                        version: 0.0.1
+                      inputFields:
+                        entry:
+                        - key: OruId
+                          value:
+                            key: OruId
+                            fieldSchemaKey:
+                              name: OruIdSchema
+                              version: 0.0.1
+                            optional: false
+                      outputFields:
+                        entry:
+                        - key: message
+                          value:
+                            key: message
+                            fieldSchemaKey:
+                              name: MessageSchema
+                              version: 0.0.1
+                            optional: false
+                      taskParameters:
+                        entry: []
+                      contextAlbumReference: []
+                      taskLogic:
+                        key: TaskLogic
+                        logicFlavour: JAVASCRIPT
+                        logic: |-
+                          /*
+                           * ============LICENSE_START=======================================================
+                           * Copyright (C) 2021 Nordix Foundation.
+                           * ================================================================================
+                           * 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.
+                           *
+                           * SPDX-License-Identifier: Apache-2.0
+                           * ============LICENSE_END=========================================================
+                           */
+
+                          executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+                          var oruId = executor.inFields.get("OruId");
+
+                          executor.outFields.put("message", "CLEARED link failure for O-RU: " + oruId);
+
+                          executor.logger.info(executor.outFields);
+
+                          true;
+                  - key:
+                      name: LinkFailureTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureTask
+                        version: 0.0.1
+                      inputFields:
+                        entry:
+                        - key: OduId
+                          value:
+                            key: OduId
+                            fieldSchemaKey:
+                              name: OduIdSchema
+                              version: 0.0.1
+                            optional: false
+                        - key: OruId
+                          value:
+                            key: OruId
+                            fieldSchemaKey:
+                              name: OruIdSchema
+                              version: 0.0.1
+                            optional: false
+                      outputFields:
+                        entry:
+                        - key: LinkFailureOutput
+                          value:
+                            key: LinkFailureOutput
+                            fieldSchemaKey:
+                              name: LinkFailureOutputSchema
+                              version: 0.0.1
+                            optional: false
+                      taskParameters:
+                        entry: []
+                      contextAlbumReference: []
+                      taskLogic:
+                        key: TaskLogic
+                        logicFlavour: JAVASCRIPT
+                        logic: |-
+                          /*
+                           * ============LICENSE_START=======================================================
+                           * Copyright (C) 2021 Nordix Foundation.
+                           * ================================================================================
+                           * 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.
+                           *
+                           * SPDX-License-Identifier: Apache-2.0
+                           * ============LICENSE_END=========================================================
+                           */
+
+                          executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+                          var linkFailureOutput = executor.subject.getOutFieldSchemaHelper("LinkFailureOutput").createNewInstance();
+
+                          var oruId = executor.inFields.get("OruId");
+                          var oduId = executor.inFields.get("OduId");
+
+                          var unlockMessageArray = new java.util.ArrayList();
+                          for (var i = 0; i < 1; i++) {
+                              unlockMessageArray.add({
+                                  "name" : oruId,
+                                  "administrative_DasH_state" : "UNLOCKED"
+                              });
+                          }
+
+                          linkFailureOutput.put("o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_du_DasH_to_DasH_ru_DasH_connection", unlockMessageArray);
+                          executor.outFields.put("LinkFailureOutput", linkFailureOutput.toString());
+
+                          executor.getExecutionProperties().setProperty("OduId", oduId);
+                          executor.getExecutionProperties().setProperty("OruId", oruId);
+
+                          executor.logger.info(executor.outFields);
+
+                          true;
+                  - key:
+                      name: NoPolicyDefinedTask
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: NoPolicyDefinedTask
+                        version: 0.0.1
+                      inputFields:
+                        entry:
+                        - key: LinkFailureInput
+                          value:
+                            key: LinkFailureInput
+                            fieldSchemaKey:
+                              name: LinkFailureInputSchema
+                              version: 0.0.1
+                            optional: false
+                      outputFields:
+                        entry:
+                        - key: message
+                          value:
+                            key: message
+                            fieldSchemaKey:
+                              name: MessageSchema
+                              version: 0.0.1
+                            optional: false
+                      taskParameters:
+                        entry: []
+                      contextAlbumReference: []
+                      taskLogic:
+                        key: TaskLogic
+                        logicFlavour: JAVASCRIPT
+                        logic: |-
+                          /*
+                           * ============LICENSE_START=======================================================
+                           * Copyright (C) 2021 Nordix Foundation.
+                           * ================================================================================
+                           * 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.
+                           *
+                           * SPDX-License-Identifier: Apache-2.0
+                           * ============LICENSE_END=========================================================
+                           */
+
+                          executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+                          executor.outFields.put("message", "No policy defined for this event");
+
+                          executor.logger.info(executor.outFields);
+
+                          true;
+              events:
+                key:
+                  name: LinkMonitorModel_Events
+                  version: 0.0.1
+                eventMap:
+                  entry:
+                  - key:
+                      name: ApexMessageOutputEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: ApexMessageOutputEvent
+                        version: 0.0.1
+                      nameSpace: org.onap.policy.apex.auth.clieditor
+                      source: APEX
+                      target: APEX
+                      parameter:
+                        entry:
+                        - key: message
+                          value:
+                            key: message
+                            fieldSchemaKey:
+                              name: MessageSchema
+                              version: 0.0.1
+                            optional: false
+                  - key:
+                      name: CreateLinkClearedOutfieldsEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: CreateLinkClearedOutfieldsEvent
+                        version: 0.0.1
+                      nameSpace: org.onap.policy.apex.auth.clieditor
+                      source: APEX
+                      target: APEX
+                      parameter:
+                        entry:
+                        - key: OruId
+                          value:
+                            key: OruId
+                            fieldSchemaKey:
+                              name: OruIdSchema
+                              version: 0.0.1
+                            optional: false
+                  - key:
+                      name: CreateLinkFailureOutfieldsEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: CreateLinkFailureOutfieldsEvent
+                        version: 0.0.1
+                      nameSpace: org.onap.policy.apex.auth.clieditor
+                      source: APEX
+                      target: APEX
+                      parameter:
+                        entry:
+                        - key: OduId
+                          value:
+                            key: OduId
+                            fieldSchemaKey:
+                              name: OduIdSchema
+                              version: 0.0.1
+                            optional: false
+                        - key: OruId
+                          value:
+                            key: OruId
+                            fieldSchemaKey:
+                              name: OruIdSchema
+                              version: 0.0.1
+                            optional: false
+                  - key:
+                      name: LinkFailureInputEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureInputEvent
+                        version: 0.0.1
+                      nameSpace: org.onap.policy.apex.auth.clieditor
+                      source: DMAAP
+                      target: APEX
+                      parameter:
+                        entry:
+                        - key: LinkFailureInput
+                          value:
+                            key: LinkFailureInput
+                            fieldSchemaKey:
+                              name: LinkFailureInputSchema
+                              version: 0.0.1
+                            optional: false
+                  - key:
+                      name: LinkFailureOutputEvent
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureOutputEvent
+                        version: 0.0.1
+                      nameSpace: org.onap.policy.apex.auth.clieditor
+                      source: APEX
+                      target: OAM
+                      parameter:
+                        entry:
+                        - key: LinkFailureOutput
+                          value:
+                            key: LinkFailureOutput
+                            fieldSchemaKey:
+                              name: LinkFailureOutputSchema
+                              version: 0.0.1
+                            optional: false
+              schemas:
+                key:
+                  name: LinkMonitorModel_Schemas
+                  version: 0.0.1
+                schemas:
+                  entry:
+                  - key:
+                      name: LinkFailureInputSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureInputSchema
+                        version: 0.0.1
+                      schemaFlavour: Avro
+                      schemaDefinition: |-
+                        {
+                            "type": "record",
+                            "name": "Link_Failure_Input",
+                            "fields": [
+                                {
+                                    "name": "event",
+                                    "type": {
+                                        "type": "record",
+                                        "name": "Event_Type",
+                                        "fields": [
+                                            {
+                                                "name": "commonEventHeader",
+                                                "type": {
+                                                    "type": "record",
+                                                    "name": "Common_Event_Header_Type",
+                                                    "fields": [
+                                                        {
+                                                            "name": "domain",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "eventId",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "eventName",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "eventType",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "sequence",
+                                                            "type": "int"
+                                                        },
+                                                        {
+                                                            "name": "priority",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "reportingEntityId",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "reportingEntityName",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "sourceId",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "sourceName",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "startEpochMicrosec",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "lastEpochMicrosec",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "nfNamingCode",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "nfVendorName",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "timeZoneOffset",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "version",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "vesEventListenerVersion",
+                                                            "type": "string"
+                                                        }
+                                                    ]
+                                                }
+                                            },
+                                            {
+                                                "name": "faultFields",
+                                                "type": {
+                                                    "type": "record",
+                                                    "name": "Fault_Fields_Type",
+                                                    "fields": [
+                                                        {
+                                                            "name": "faultFieldsVersion",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "alarmCondition",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "alarmInterfaceA",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "eventSourceType",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "specificProblem",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "eventSeverity",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "vfStatus",
+                                                            "type": "string"
+                                                        },
+                                                        {
+                                                            "name": "alarmAdditionalInformation",
+                                                            "type": {
+                                                                "type": "record",
+                                                                "name": "Alarm_Additional_Information_Type",
+                                                                "fields": [
+                                                                    {
+                                                                        "name": "eventTime",
+                                                                        "type": "string"
+                                                                    },
+                                                                    {
+                                                                        "name": "equipType",
+                                                                        "type": "string"
+                                                                    },
+                                                                    {
+                                                                        "name": "vendor",
+                                                                        "type": "string"
+                                                                    },
+                                                                    {
+                                                                        "name": "model",
+                                                                        "type": "string"
+                                                                    }
+                                                                ]
+                                                            }
+                                                        }
+                                                    ]
+                                                }
+                                            }
+                                        ]
+                                    }
+                                }
+                            ]
+                        }
+                  - key:
+                      name: LinkFailureOutputSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: LinkFailureOutputSchema
+                        version: 0.0.1
+                      schemaFlavour: Avro
+                      schemaDefinition: "{\n    \"type\": \"record\",\n    \"name\":
+                        \"Link_Failure_Output\",\n    \"fields\": [\n        {\n            \"name\":
+                        \"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_du_DasH_to_DasH_ru_DasH_connection\",\n
+                        \           \"type\": {\n        \t\"type\": \"array\",\n
+                        \       \t\"items\": {\n\t\t    \"name\": \"Config_Change_Message\",\n
+                        \                   \"type\": \"record\",\n                    \"fields\":
+                        [\n                        {\n                            \"name\":
+                        \"name\",\n                            \"type\": \"string\"\n
+                        \                       },\n\t\t\t{\n                            \"name\":
+                        \"administrative_DasH_state\",\n                            \"type\":
+                        \"string\"\n                        }\n                    ]\n
+                        \               }\n\t    }\n        }\n    ]\n}"
+                  - key:
+                      name: MessageSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: MessageSchema
+                        version: 0.0.1
+                      schemaFlavour: Java
+                      schemaDefinition: java.lang.String
+                  - key:
+                      name: OduIdSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: OduIdSchema
+                        version: 0.0.1
+                      schemaFlavour: Java
+                      schemaDefinition: java.lang.String
+                  - key:
+                      name: OruIdSchema
+                      version: 0.0.1
+                    value:
+                      key:
+                        name: OruIdSchema
+                        version: 0.0.1
+                      schemaFlavour: Java
+                      schemaDefinition: java.lang.String
+        eventOutputParameters:
+          RestProducer:
+            carrierTechnologyParameters:
+              carrierTechnology: RESTCLIENT
+              parameterClassName: org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters
+              parameters:
+                url: http://sdnr-sim:9990/rests/data/network-topology:network-topology/topology=topology-netconf/node={OduId}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/du-to-ru-connection={OruId}
+                httpMethod: PUT
+                httpHeaders:
+                - - Authorization
+                  - Basic YWRtaW46S3A4Yko0U1hzek0wV1hsaGFrM2VIbGNzZTJnQXc4NHZhb0dHbUp2VXkyVQ==
+            eventProtocolParameters:
+              eventProtocol: JSON
+              parameters:
+                pojoField: LinkFailureOutput
+            eventNameFilter: LinkFailureOutputEvent
+          StdOutProducer:
+            carrierTechnologyParameters:
+              carrierTechnology: FILE
+              parameters:
+                standardIo: true
+            eventProtocolParameters:
+              eventProtocol: JSON
+              parameters:
+                pojoField: message
+            eventNameFilter: ApexMessageOutputEvent
+        eventInputParameters:
+          DMaaPConsumer:
+            carrierTechnologyParameters:
+              carrierTechnology: RESTCLIENT
+              parameterClassName: org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters
+              parameters:
+                url: http://onap-dmaap:3904/events/unauthenticated.SEC_FAULT_OUTPUT/users/link-monitor-nonrtric?timeout=15000&limit=100
+            eventProtocolParameters:
+              eventProtocol: JSON
+              parameters:
+                versionAlias: version
+                pojoField: LinkFailureInput
+            eventName: LinkFailureInputEvent
diff --git a/apexpolicyversion/LinkMonitor/controlloop-rest-payloads/instantiation-command.json b/apexpolicyversion/LinkMonitor/controlloop-rest-payloads/instantiation-command.json
new file mode 100644 (file)
index 0000000..ea21914
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "orderedState": "PASSIVE",
+    "controlLoopIdentifierList": [
+        {
+            "name": "LinkMonitorInstance0",
+            "version": "1.0.1"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/controlloop-rest-payloads/instantiation.json b/apexpolicyversion/LinkMonitor/controlloop-rest-payloads/instantiation.json
new file mode 100644 (file)
index 0000000..798de5d
--- /dev/null
@@ -0,0 +1,35 @@
+{
+    "controlLoopList": [
+        {
+            "name": "LinkMonitorInstance0",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.linkmonitor.LinkMonitorControlLoopDefinition0",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "Link Monitor control loop instance 0",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c22": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c22",
+                    "definition": {
+                        "name": "org.onap.domain.linkmonitor.LinkMonitorPolicyControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.policy.controlloop.PolicyControlLoopParticipant",
+                        "version": "2.3.1"
+                    },
+                    "participantId": {
+                        "name": "org.onap.PM_Policy",
+                        "version": "1.0.0"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Link Monitor Policy Control Loop Element"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/deployment/DeployPolicyPAP.json b/apexpolicyversion/LinkMonitor/deployment/DeployPolicyPAP.json
new file mode 100644 (file)
index 0000000..6d9bde5
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "policies": [
+    {
+      "policy-id": "onap.policies.native.apex.LinkMonitor",
+      "policy-version": "1.0.0"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/deployment/ToscaPolicy.json b/apexpolicyversion/LinkMonitor/deployment/ToscaPolicy.json
new file mode 100644 (file)
index 0000000..f2fea50
--- /dev/null
@@ -0,0 +1 @@
+{"tosca_definitions_version":"tosca_simple_yaml_1_1_0","topology_template":{"policies":[{"onap.policies.native.apex.LinkMonitor":{"type":"onap.policies.native.Apex","type_version":"1.0.0","name":"onap.policies.native.apex.LinkMonitor","version":"1.0.0","properties":{"engineServiceParameters":{"name":"LinkMonitorApexEngine","version":"0.0.1","id":101,"instanceCount":1,"deploymentPort":12345,"engineParameters":{"executorParameters":{"JAVASCRIPT":{"parameterClassName":"org.onap.policy.apex.plugins.executor.javascript.JavascriptExecutorParameters"}},"contextParameters":{"parameterClassName":"org.onap.policy.apex.context.parameters.ContextParameters","schemaParameters":{"Avro":{"parameterClassName":"org.onap.policy.apex.plugins.context.schema.avro.AvroSchemaHelperParameters"}}},"taskParameters":[{"key":"ORU-ODU-Map","value":"{\"ERICSSON-O-RU-11220\": \"O-DU-1122\",\r\n                               \"ERICSSON-O-RU-11221\": \"O-DU-1122\",\r\n                               \"ERICSSON-O-RU-11222\": \"O-DU-1122\",\r\n                               \"ERICSSON-O-RU-11223\": \"O-DU-1122\",\r\n                               \"ERICSSON-O-RU-11224\": \"O-DU-1123\",\r\n                               \"ERICSSON-O-RU-11225\": \"O-DU-1123\",\r\n                               \"ERICSSON-O-RU-11226\": \"O-DU-1123\",\r\n                               \"ERICSSON-O-RU-11227\": \"O-DU-1124\",\r\n                               \"ERICSSON-O-RU-11228\": \"O-DU-1125\",\r\n                               \"ERICSSON-O-RU-11229\": \"O-DU-1125\"}"}]},"policy_type_impl":{"apexPolicyModel":{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"keyInformation":{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"keyInfoMap":{"entry":[{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"value":{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"UUID":"cca47d74-7754-4a61-b163-ca31f66b157b","description":"Generated description for concept referred to by key \"ApexMessageOutputEvent:0.0.1\""}},{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"UUID":"a295d6a3-1b73-387e-abba-b41e9b608802","description":"Generated description for concept referred to by key \"CreateLinkClearedOutfieldsEvent:0.0.1\""}},{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"UUID":"fd594e88-411d-4a94-b2be-697b3a0d7adf","description":"This task creates the output fields when link failure is cleared."}},{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"UUID":"02be2b5d-45b7-3c54-ae54-97f2b5c30125","description":"Generated description for concept referred to by key \"CreateLinkFailureOutfieldsEvent:0.0.1\""}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"UUID":"ac3d9842-80af-4a98-951c-bd79a431c613","description":"This task the output fields when link failure is detected."}},{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"name":"LinkClearedTask","version":"0.0.1"},"UUID":"eecfde90-896c-4343-8f9c-2603ced94e2d","description":"This task sends a message to the output when link failure is cleared."}},{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"UUID":"c4500941-3f98-4080-a9cc-5b9753ed050b","description":"Generated description for concept referred to by key \"LinkFailureInputEvent:0.0.1\""}},{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"UUID":"3b3974fc-3012-3b02-9f33-c9d8eefe4dc1","description":"Generated description for concept referred to by key \"LinkFailureInputSchema:0.0.1\""}},{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"UUID":"4f04aa98-e917-4f4a-882a-c75ba5a99374","description":"Generated description for concept referred to by key \"LinkFailureOutputEvent:0.0.1\""}},{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"UUID":"2d1a7f6e-eb9a-3984-be1f-283d98111b84","description":"Generated description for concept referred to by key \"LinkFailureOutputSchema:0.0.1\""}},{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"name":"LinkFailureTask","version":"0.0.1"},"UUID":"3351b0f4-cf06-4fa2-8823-edf67bd30223","description":"This task updates the config for O-RU when link failure is detected."}},{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel","version":"0.0.1"},"UUID":"540226fb-55ee-4f0e-a444-983a0494818e","description":"This is the Apex Policy Model for link monitoring."}},{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"UUID":"27ad3e7e-fe3b-3bd6-9081-718705c2bcea","description":"Generated description for concept referred to by key \"LinkMonitorModel_Events:0.0.1\""}},{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_KeyInfo","version":"0.0.1"},"UUID":"ea0b5f58-eefd-358a-9660-840c640bf981","description":"Generated description for concept referred to by key \"LinkMonitorModel_KeyInfo:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"UUID":"ee9e0b0f-2b7d-3ab7-9a98-c5ec05ed823d","description":"Generated description for concept referred to by key \"LinkMonitorModel_Policies:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"UUID":"fa5f9b8f-796c-3c70-84e9-5140c958c4bb","description":"Generated description for concept referred to by key \"LinkMonitorModel_Schemas:0.0.1\""}},{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"UUID":"eec592f7-69d5-39a9-981a-e552f787ed01","description":"Generated description for concept referred to by key \"LinkMonitorModel_Tasks:0.0.1\""}},{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"value":{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"UUID":"6c5e410f-489a-46ff-964e-982ce6e8b6d0","description":"Generated description for concept referred to by key \"LinkMonitorPolicy:0.0.1\""}},{"key":{"name":"MessageSchema","version":"0.0.1"},"value":{"key":{"name":"MessageSchema","version":"0.0.1"},"UUID":"ac4b34ac-39d6-3393-a267-8d5b84854018","description":"A schema for messages from apex"}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"UUID":"d48b619e-d00d-4008-b884-02d76ea4350b","description":"This task sends a message to the output when an event is received for which no policy has been defined."}},{"key":{"name":"OduIdSchema","version":"0.0.1"},"value":{"key":{"name":"OduIdSchema","version":"0.0.1"},"UUID":"50662174-a88b-3cbd-91bd-8e91b40b2660","description":"A schema for O-DU-ID"}},{"key":{"name":"OruIdSchema","version":"0.0.1"},"value":{"key":{"name":"OruIdSchema","version":"0.0.1"},"UUID":"54daf32b-015f-39cd-8530-a1175c5553e9","description":"A schema for O-RU-ID"}}]}},"policies":{"key":{"name":"LinkMonitorModel_Policies","version":"0.0.1"},"policyMap":{"entry":[{"key":{"name":"LinkMonitorPolicy","version":"0.0.1"},"value":{"policyKey":{"name":"LinkMonitorPolicy","version":"0.0.1"},"template":"Freestyle","state":{"entry":[{"key":"LinkClearedState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkClearedState"},"trigger":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"LinkClearedLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedLogic_Output_Direct"},"outgoingEvent":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"NULL","logicFlavour":"UNDEFINED","logic":""},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"LinkClearedTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkClearedState","localName":"LinkClearedLogic_Output_Direct"}}}]}}},{"key":"LinkFailureOrClearedState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureOrClearedState"},"trigger":{"name":"LinkFailureInputEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"CreateLinkClearedOutfieldsLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsLogic_Output_Direct"},"outgoingEvent":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"nextState":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkClearedState"}}},{"key":"CreateLinkFailureOutfieldsLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsLogic_Output_Direct"},"outgoingEvent":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"nextState":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureState"}}},{"key":"NoPolicyDefinedLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedLogic_Output_Direct"},"outgoingEvent":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"TaskSelectionLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Selection Execution: '\"+executor.subject.id+\n    \"'. InputFields: '\"+executor.inFields+\"'\");\n\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar commonEventHeader = linkFailureInput.get(\"event\").get(\"commonEventHeader\");\nvar domain = commonEventHeader.get(\"domain\");\n\ntaskFailure = executor.subject.getTaskKey(\"CreateLinkFailureOutfieldsTask\");\ntaskCleared = executor.subject.getTaskKey(\"CreateLinkClearedOutfieldsTask\");\ntaskDefault = executor.subject.getDefaultTaskKey();\n\nif (domain == \"fault\") {\n    var faultFields = linkFailureInput.get(\"event\").get(\"faultFields\");\n    var alarmCondition = faultFields.get(\"alarmCondition\");\n    var eventSeverity = faultFields.get(\"eventSeverity\");\n    if (alarmCondition == \"28\" && eventSeverity != \"NORMAL\") {\n        taskFailure.copyTo(executor.selectedTask);\n    } else if (alarmCondition == \"28\" && eventSeverity == \"NORMAL\") {\n        taskCleared.copyTo(executor.selectedTask);\n    } else {\n        taskDefault.copyTo(executor.selectedTask);\n    }\n} else {\n    taskDefault.copyTo(executor.selectedTask);\n}\n\ntrue;"},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkClearedOutfieldsLogic_Output_Direct"}}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"CreateLinkFailureOutfieldsLogic_Output_Direct"}}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureOrClearedState","localName":"NoPolicyDefinedLogic_Output_Direct"}}}]}}},{"key":"LinkFailureState","value":{"stateKey":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"NULL","localName":"LinkFailureState"},"trigger":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"stateOutputs":{"entry":[{"key":"LinkFailureLogic_Output_Direct","value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureLogic_Output_Direct"},"outgoingEvent":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"nextState":{"parentKeyName":"NULL","parentKeyVersion":"0.0.0","parentLocalName":"NULL","localName":"NULL"}}}]},"contextAlbumReference":[],"taskSelectionLogic":{"key":"NULL","logicFlavour":"UNDEFINED","logic":""},"stateFinalizerLogicMap":{"entry":[]},"defaultTask":{"name":"LinkFailureTask","version":"0.0.1"},"taskReferences":{"entry":[{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureTask"},"outputType":"DIRECT","output":{"parentKeyName":"LinkMonitorPolicy","parentKeyVersion":"0.0.1","parentLocalName":"LinkFailureState","localName":"LinkFailureLogic_Output_Direct"}}}]}}}]},"firstState":"LinkFailureOrClearedState"}}]}},"tasks":{"key":{"name":"LinkMonitorModel_Tasks","version":"0.0.1"},"taskMap":{"entry":[{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar oruId = linkFailureInput.get(\"event\").get(\"commonEventHeader\").get(\"sourceName\");\n\nexecutor.outFields.put(\"OruId\", oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar returnValue = true;\nvar linkFailureInput = executor.inFields.get(\"LinkFailureInput\");\nvar oruId = linkFailureInput.get(\"event\").get(\"commonEventHeader\").get(\"sourceName\");\nvar oruOduMap = JSON.parse(executor.parameters.get(\"ORU-ODU-Map\"));\n\nif (oruId in oruOduMap) {\n    var oduId = oruOduMap[oruId];\n    executor.outFields.put(\"OruId\", oruId);\n    executor.outFields.put(\"OduId\", oduId);\n    executor.logger.info(executor.outFields);\n} else {\n    executor.message = \"No O-RU found in the config with this ID: \" + oruId;\n    returnValue = false;\n}\n\nreturnValue;"}}},{"key":{"name":"LinkClearedTask","version":"0.0.1"},"value":{"key":{"name":"LinkClearedTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar oruId = executor.inFields.get(\"OruId\");\n\nexecutor.outFields.put(\"message\", \"CLEARED link failure for O-RU: \" + oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"LinkFailureTask","version":"0.0.1"},"value":{"key":{"name":"LinkFailureTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"LinkFailureOutput","value":{"key":"LinkFailureOutput","fieldSchemaKey":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nvar linkFailureOutput = executor.subject.getOutFieldSchemaHelper(\"LinkFailureOutput\").createNewInstance();\n\nvar oruId = executor.inFields.get(\"OruId\");\nvar oduId = executor.inFields.get(\"OduId\");\n\nvar unlockMessageArray = new java.util.ArrayList();\nfor (var i = 0; i < 1; i++) {\n    unlockMessageArray.add({\n            \"id\":\"rrm-pol-1\",\n            \"radio_DasH_resource_DasH_management_DasH_policy_DasH_max_DasH_ratio\":25,\n            \"radio_DasH_resource_DasH_management_DasH_policy_DasH_members\":\n                [\n                    {\n                        \"mobile_DasH_country_DasH_code\":\"310\",\n                        \"mobile_DasH_network_DasH_code\":\"150\",\n                        \"slice_DasH_differentiator\":1,\n                        \"slice_DasH_service_DasH_type\":1\n                    }\n                ],\n            \"radio_DasH_resource_DasH_management_DasH_policy_DasH_min_DasH_ratio\":15,\n            \"user_DasH_label\":\"rrm-pol-1\",\n            \"resource_DasH_type\":\"prb\",\n            \"radio_DasH_resource_DasH_management_DasH_policy_DasH_dedicated_DasH_ratio\":20,\n            \"administrative_DasH_state\":\"unlocked\"\n        });\n}\n\nlinkFailureOutput.put(\"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio\", unlockMessageArray);\nexecutor.outFields.put(\"LinkFailureOutput\", linkFailureOutput.toString());\n\nexecutor.getExecutionProperties().setProperty(\"OduId\", oduId);\nexecutor.getExecutionProperties().setProperty(\"OruId\", oruId);\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}},{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"value":{"key":{"name":"NoPolicyDefinedTask","version":"0.0.1"},"inputFields":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]},"outputFields":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]},"taskParameters":{"entry":[]},"contextAlbumReference":[],"taskLogic":{"key":"TaskLogic","logicFlavour":"JAVASCRIPT","logic":"/*\n * ============LICENSE_START=======================================================\n * Copyright (C) 2021 Nordix Foundation.\n * ================================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * SPDX-License-Identifier: Apache-2.0\n * ============LICENSE_END=========================================================\n */\n\nexecutor.logger.info(\"Task Execution: '\"+executor.subject.id+\"'. Input Fields: '\"+executor.inFields+\"'\");\n\nexecutor.outFields.put(\"message\", \"No policy defined for this event\");\n\nexecutor.logger.info(executor.outFields);\n\ntrue;"}}}]}},"events":{"key":{"name":"LinkMonitorModel_Events","version":"0.0.1"},"eventMap":{"entry":[{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"value":{"key":{"name":"ApexMessageOutputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"message","value":{"key":"message","fieldSchemaKey":{"name":"MessageSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkClearedOutfieldsEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"value":{"key":{"name":"CreateLinkFailureOutfieldsEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"APEX","parameter":{"entry":[{"key":"OduId","value":{"key":"OduId","fieldSchemaKey":{"name":"OduIdSchema","version":"0.0.1"},"optional":false}},{"key":"OruId","value":{"key":"OruId","fieldSchemaKey":{"name":"OruIdSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"DMAAP","target":"APEX","parameter":{"entry":[{"key":"LinkFailureInput","value":{"key":"LinkFailureInput","fieldSchemaKey":{"name":"LinkFailureInputSchema","version":"0.0.1"},"optional":false}}]}}},{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputEvent","version":"0.0.1"},"nameSpace":"org.onap.policy.apex.auth.clieditor","source":"APEX","target":"OAM","parameter":{"entry":[{"key":"LinkFailureOutput","value":{"key":"LinkFailureOutput","fieldSchemaKey":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"optional":false}}]}}}]}},"schemas":{"key":{"name":"LinkMonitorModel_Schemas","version":"0.0.1"},"schemas":{"entry":[{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureInputSchema","version":"0.0.1"},"schemaFlavour":"Avro","schemaDefinition":"{\n    \"type\": \"record\",\n    \"name\": \"Link_Failure_Input\",\n    \"fields\": [\n        {\n            \"name\": \"event\",\n            \"type\": {\n                \"type\": \"record\",\n                \"name\": \"Event_Type\",\n                \"fields\": [\n                    {\n                        \"name\": \"commonEventHeader\",\n                        \"type\": {\n                            \"type\": \"record\",\n                            \"name\": \"Common_Event_Header_Type\",\n                            \"fields\": [\n                                {\n                                    \"name\": \"domain\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"eventId\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"eventName\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"eventType\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"sequence\",\n                                    \"type\": \"int\"\n                                },\n                                {\n                                    \"name\": \"priority\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"reportingEntityId\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"reportingEntityName\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"sourceId\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"sourceName\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"startEpochMicrosec\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"lastEpochMicrosec\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"nfNamingCode\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"nfVendorName\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"timeZoneOffset\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"version\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"vesEventListenerVersion\",\n                                    \"type\": \"string\"\n                                }\n                            ]\n                        }\n                    },\n                    {\n                        \"name\": \"faultFields\",\n                        \"type\": {\n                            \"type\": \"record\",\n                            \"name\": \"Fault_Fields_Type\",\n                            \"fields\": [\n                                {\n                                    \"name\": \"faultFieldsVersion\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"alarmCondition\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"alarmInterfaceA\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"eventSourceType\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"specificProblem\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"eventSeverity\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"vfStatus\",\n                                    \"type\": \"string\"\n                                },\n                                {\n                                    \"name\": \"alarmAdditionalInformation\",\n                                    \"type\": {\n                                        \"type\": \"record\",\n                                        \"name\": \"Alarm_Additional_Information_Type\",\n                                        \"fields\": [\n                                            {\n                                                \"name\": \"eventTime\",\n                                                \"type\": \"string\"\n                                            },\n                                            {\n                                                \"name\": \"equipType\",\n                                                \"type\": \"string\"\n                                            },\n                                            {\n                                                \"name\": \"vendor\",\n                                                \"type\": \"string\"\n                                            },\n                                            {\n                                                \"name\": \"model\",\n                                                \"type\": \"string\"\n                                            }\n                                        ]\n                                    }\n                                }\n                            ]\n                        }\n                    }\n                ]\n            }\n        }\n    ]\n}"}},{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"value":{"key":{"name":"LinkFailureOutputSchema","version":"0.0.1"},"schemaFlavour":"Avro","schemaDefinition":"{\n  \"name\": \"Link_Failure_Output\",\n  \"type\": \"record\",\n  \"fields\": [\n    {\n      \"name\": \"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio\",\n      \"type\": {\n        \"type\": \"array\",\n        \"items\": {\n          \"name\": \"o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio_record\",\n          \"type\": \"record\",\n          \"fields\": [\n            {\n              \"name\": \"id\",\n              \"type\": \"string\"\n            },\n            {\n              \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_max_DasH_ratio\",\n              \"type\": \"int\"\n            },\n            {\n              \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_members\",\n              \"type\": {\n                \"type\": \"array\",\n                \"items\": {\n                  \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_members_record\",\n                  \"type\": \"record\",\n                  \"fields\": [\n                    {\n                      \"name\": \"mobile_DasH_country_DasH_code\",\n                      \"type\": \"string\"\n                    },\n                    {\n                      \"name\": \"mobile_DasH_network_DasH_code\",\n                      \"type\": \"string\"\n                    },\n                    {\n                      \"name\": \"slice_DasH_differentiator\",\n                      \"type\": \"int\"\n                    },\n                    {\n                      \"name\": \"slice_DasH_service_DasH_type\",\n                      \"type\": \"int\"\n                    }\n                  ]\n                }\n              }\n            },\n            {\n              \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_min_DasH_ratio\",\n              \"type\": \"int\"\n            },\n            {\n              \"name\": \"user_DasH_label\",\n              \"type\": \"string\"\n            },\n            {\n              \"name\": \"resource_DasH_type\",\n              \"type\": \"string\"\n            },\n            {\n              \"name\": \"radio_DasH_resource_DasH_management_DasH_policy_DasH_dedicated_DasH_ratio\",\n              \"type\": \"int\"\n            },\n            {\n              \"name\": \"administrative_DasH_state\",\n              \"type\": \"string\"\n            }\n          ]\n        }\n      }\n    }\n  ]\n}"}},{"key":{"name":"MessageSchema","version":"0.0.1"},"value":{"key":{"name":"MessageSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"OduIdSchema","version":"0.0.1"},"value":{"key":{"name":"OduIdSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}},{"key":{"name":"OruIdSchema","version":"0.0.1"},"value":{"key":{"name":"OruIdSchema","version":"0.0.1"},"schemaFlavour":"Java","schemaDefinition":"java.lang.String"}}]}}}}},"eventOutputParameters":{"RestProducer":{"carrierTechnologyParameters":{"carrierTechnology":"RESTCLIENT","parameterClassName":"org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters","parameters":{"url":"http://sdnr-sim:9990/rests/data/network-topology:network-topology/topology=topology-netconf/node={OduId}/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions={OduId}/radio-resource-management-policy-ratio=rrm-pol-1","httpMethod":"PUT","httpHeaders":[["Authorization","Basic YWRtaW46S3A4Yko0U1hzek0wV1hsaGFrM2VIbGNzZTJnQXc4NHZhb0dHbUp2VXkyVQ=="]]}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"pojoField":"LinkFailureOutput"}},"eventNameFilter":"LinkFailureOutputEvent"},"StdOutProducer":{"carrierTechnologyParameters":{"carrierTechnology":"FILE","parameters":{"standardIo":true}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"pojoField":"message"}},"eventNameFilter":"ApexMessageOutputEvent"}},"eventInputParameters":{"DMaaPConsumer":{"carrierTechnologyParameters":{"carrierTechnology":"RESTCLIENT","parameterClassName":"org.onap.policy.apex.plugins.event.carrier.restclient.RestClientCarrierTechnologyParameters","parameters":{"url":"http://onap-dmaap:3904/events/unauthenticated.SEC_FAULT_OUTPUT/users/link-monitor-nonrtric?timeout=15000&limit=100"}},"eventProtocolParameters":{"eventProtocol":"JSON","parameters":{"versionAlias":"version","pojoField":"LinkFailureInput"}},"eventName":"LinkFailureInputEvent"}}}}}]}}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/docker-compose-controlloop/config/ks.jks b/apexpolicyversion/LinkMonitor/docker-compose-controlloop/config/ks.jks
new file mode 100644 (file)
index 0000000..001c7e1
Binary files /dev/null and b/apexpolicyversion/LinkMonitor/docker-compose-controlloop/config/ks.jks differ
diff --git a/apexpolicyversion/LinkMonitor/docker-compose-controlloop/docker-compose.yml b/apexpolicyversion/LinkMonitor/docker-compose-controlloop/docker-compose.yml
new file mode 100644 (file)
index 0000000..bd35d74
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# ===========LICENSE_START====================================================
+# Copyright (C) 2021 Nordix Foundation. All rights reserved.
+# ============================================================================
+# 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.
+# ============LICENSE_END=====================================================
+#
+version: '2'
+networks:
+  default:
+    driver: bridge
+    name: nonrtric-docker-net
+services:
+   controlloop-runtime:
+      image: nexus3.onap.org:10001/onap/policy-clamp-cl-runtime:6.1.3
+      container_name: controlloop-runtime
+      hostname: controlloop-runtime
+      ports:
+       - "6969:6969"
+      expose:
+       - 6969
+      volumes:
+       - ./config/ks.jks:/opt/app/policy/clamp/etc/ssl/policy-keystore:ro
+       - ./wait_for_port.sh:/opt/app/policy/clamp/bin/wait_for_port.sh:ro
+      environment:
+       - TOPICSERVER=onap-dmaap
+       - MARIADB_HOST=mariadb
+       - MARIADB_PORT=3306
+       - KEYSTORE=/opt/app/policy/clamp/etc/ssl/policy-keystore
+       - KEYSTORE_PASSWD=Pol1cy_0nap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_TOPIC=POLICY-CLRUNTIME-PARTICIPANT
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_SERVERS_0=onap-dmaap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_TOPICCOMMINFRASTRUCTURE=dmaap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_FETCHTIMEOUT=15000
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_USEHTTPS=false
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_TOPIC=POLICY-CLRUNTIME-PARTICIPANT
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_SERVERS_0=onap-dmaap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_TOPICCOMMINFRASTRUCTURE=dmaap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_FETCHTIMEOUT=15000
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_USEHTTPS=false
+      entrypoint: /opt/app/policy/clamp/bin/wait_for_port.sh
+      command: [
+        '-c', '/opt/app/policy/clamp/bin/controlloop-runtime.sh',
+        'mariadb', '3306',
+        'onap-dmaap', '3904'
+        ]
+   policy-participant:
+      image: nexus3.onap.org:10001/onap/policy-clamp-cl-pf-ppnt:6.1.3
+      container_name: policy-participant
+      depends_on:
+       - controlloop-runtime
+      hostname: policy-participant
+      volumes:
+       - ./config/ks.jks:/opt/app/policy/clamp/etc/ssl/policy-keystore:ro
+       - ./wait_for_port.sh:/opt/app/policy/clamp/bin/wait_for_port.sh:ro
+      environment:
+       - TOPICSERVER=onap-dmaap
+       - KEYSTORE=/opt/app/policy/clamp/etc/ssl/policy-keystore
+       - KEYSTORE_PASSWD=Pol1cy_0nap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_TOPIC=POLICY-CLRUNTIME-PARTICIPANT
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_SERVERS_0=onap-dmaap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_TOPICCOMMINFRASTRUCTURE=dmaap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_FETCHTIMEOUT=15000
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_USEHTTPS=false
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_TOPIC=POLICY-CLRUNTIME-PARTICIPANT
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_SERVERS_0=onap-dmaap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_TOPICCOMMINFRASTRUCTURE=dmaap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_FETCHTIMEOUT=15000
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_USEHTTPS=false
+      entrypoint: /opt/app/policy/clamp/bin/wait_for_port.sh
+      command: [
+        '-c', '/opt/app/policy/clamp/bin/policy-participant.sh',
+        'controlloop-runtime', '6969'
+        ]
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/docker-compose-controlloop/wait_for_port.sh b/apexpolicyversion/LinkMonitor/docker-compose-controlloop/wait_for_port.sh
new file mode 100644 (file)
index 0000000..aec5f22
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+# ============LICENSE_START====================================================
+#  Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+# =============================================================================
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END======================================================
+
+tmout=120
+cmd=
+while getopts c:t: opt; do
+    case "$opt" in
+    c) cmd="$OPTARG" ;;
+    t) tmout="$OPTARG" ;;
+    esac
+done
+nargs=$(expr $OPTIND - 1)
+shift $nargs
+
+even_args=$(expr $# % 2)
+if [ $# -lt 2 -o $even_args -ne 0 ]; then
+    echo "args: [-t timeout] [-c command] hostname1 port1 hostname2 port2 ..." >&2
+    exit 1
+fi
+
+while [ $# -ge 2 ]; do
+    export host=$1
+    export port=$2
+    shift
+    shift
+
+    echo "Waiting for $host port $port..."
+    timeout $tmout sh -c 'until nc -vz "$host" "$port"; do echo -n ".";
+        sleep 1; done'
+    rc=$?
+
+    if [ $rc != 0 ]; then
+        echo "$host port $port cannot be reached"
+        exit $rc
+    fi
+done
+
+$cmd
+
+exit 0
diff --git a/apexpolicyversion/LinkMonitor/events/LinkClearedEvent.json b/apexpolicyversion/LinkMonitor/events/LinkClearedEvent.json
new file mode 100644 (file)
index 0000000..ffea3b6
--- /dev/null
@@ -0,0 +1,38 @@
+{
+    "event": {
+        "commonEventHeader": {
+            "domain": "fault",
+            "eventId": "nt:network-topology/nt:topology/nt:node/nt:node-id",
+            "eventName": "fault_O-RAN-RU-Fault_Alarms_CUS_Link_Failure",
+            "eventType": "O-RAN-RU-Fault",
+            "sequence": 0,
+            "priority": "Normal",
+            "reportingEntityId": "SDNR",
+            "reportingEntityName": "@controllerName@",
+            "sourceId": "",
+            "sourceName": "ERICSSON-O-RU-11225",
+            "startEpochMicrosec": "@timestamp@",
+            "lastEpochMicrosec": "@timestamp@",
+            "nfNamingCode": "",
+            "nfVendorName": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-name",
+            "timeZoneOffset": "+00:00",
+            "version": "4.1",
+            "vesEventListenerVersion": "7.2.1"
+        },
+        "faultFields": {
+            "faultFieldsVersion": "4.0",
+            "alarmCondition": "28",
+            "alarmInterfaceA": "o-ran-fm:alarm-notif/fault-source",
+            "eventSourceType": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-model or \"O-RU\"",
+            "specificProblem": "",
+            "eventSeverity": "NORMAL",
+            "vfStatus": "Active",
+            "alarmAdditionalInformation": {
+                "eventTime": "@eventTime@",
+                "equipType": "@type@",
+                "vendor": "@vendor@",
+                "model": "@model@"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/events/LinkFailureEvent.json b/apexpolicyversion/LinkMonitor/events/LinkFailureEvent.json
new file mode 100644 (file)
index 0000000..98f81b1
--- /dev/null
@@ -0,0 +1,38 @@
+{
+    "event": {
+        "commonEventHeader": {
+            "domain": "fault",
+            "eventId": "nt:network-topology/nt:topology/nt:node/nt:node-id",
+            "eventName": "fault_O-RAN-RU-Fault_Alarms_CUS_Link_Failure",
+            "eventType": "O-RAN-RU-Fault",
+            "sequence": 0,
+            "priority": "Normal",
+            "reportingEntityId": "SDNR",
+            "reportingEntityName": "@controllerName@",
+            "sourceId": "",
+            "sourceName": "ERICSSON-O-RU-11225",
+            "startEpochMicrosec": "@timestamp@",
+            "lastEpochMicrosec": "@timestamp@",
+            "nfNamingCode": "",
+            "nfVendorName": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-name",
+            "timeZoneOffset": "+00:00",
+            "version": "4.1",
+            "vesEventListenerVersion": "7.2.1"
+        },
+        "faultFields": {
+            "faultFieldsVersion": "4.0",
+            "alarmCondition": "28",
+            "alarmInterfaceA": "o-ran-fm:alarm-notif/fault-source",
+            "eventSourceType": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-model or \"O-RU\"",
+            "specificProblem": "",
+            "eventSeverity": "CRITICAL",
+            "vfStatus": "Active",
+            "alarmAdditionalInformation": {
+                "eventTime": "@eventTime@",
+                "equipType": "@type@",
+                "vendor": "@vendor@",
+                "model": "@model@"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/events/SomeOtherEvent.json b/apexpolicyversion/LinkMonitor/events/SomeOtherEvent.json
new file mode 100644 (file)
index 0000000..79770e7
--- /dev/null
@@ -0,0 +1,38 @@
+{
+    "event": {
+        "commonEventHeader": {
+            "domain": "fault",
+            "eventId": "nt:network-topology/nt:topology/nt:node/nt:node-id",
+            "eventName": "fault_O-RAN-RU-Fault_Alarms_CUS_Link_Failure",
+            "eventType": "O-RAN-RU-Fault",
+            "sequence": 0,
+            "priority": "Normal",
+            "reportingEntityId": "SDNR",
+            "reportingEntityName": "@controllerName@",
+            "sourceId": "",
+            "sourceName": "ERICSSON-O-RU-11225",
+            "startEpochMicrosec": "@timestamp@",
+            "lastEpochMicrosec": "@timestamp@",
+            "nfNamingCode": "",
+            "nfVendorName": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-name",
+            "timeZoneOffset": "+00:00",
+            "version": "4.1",
+            "vesEventListenerVersion": "7.2.1"
+        },
+        "faultFields": {
+            "faultFieldsVersion": "4.0",
+            "alarmCondition": "1",
+            "alarmInterfaceA": "o-ran-fm:alarm-notif/fault-source",
+            "eventSourceType": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-model or \"O-RU\"",
+            "specificProblem": "",
+            "eventSeverity": "NORMAL",
+            "vfStatus": "Active",
+            "alarmAdditionalInformation": {
+                "eventTime": "@eventTime@",
+                "equipType": "@type@",
+                "vendor": "@vendor@",
+                "model": "@model@"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/models/CreateLinkClearedOutfieldsLogic.js b/apexpolicyversion/LinkMonitor/models/CreateLinkClearedOutfieldsLogic.js
new file mode 100644 (file)
index 0000000..e521c8e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+var linkFailureInput = executor.inFields.get("LinkFailureInput");
+var oruId = linkFailureInput.get("event").get("commonEventHeader").get("sourceName");
+
+executor.outFields.put("OruId", oruId);
+
+executor.logger.info(executor.outFields);
+
+true;
diff --git a/apexpolicyversion/LinkMonitor/models/CreateLinkFailureOutfieldsLogic.js b/apexpolicyversion/LinkMonitor/models/CreateLinkFailureOutfieldsLogic.js
new file mode 100644 (file)
index 0000000..69deb0a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+var returnValue = true;
+var linkFailureInput = executor.inFields.get("LinkFailureInput");
+var oruId = linkFailureInput.get("event").get("commonEventHeader").get("sourceName");
+var oruOduMap = JSON.parse(executor.parameters.get("ORU-ODU-Map"));
+
+if (oruId in oruOduMap) {
+    var oduId = oruOduMap[oruId];
+    executor.outFields.put("OruId", oruId);
+    executor.outFields.put("OduId", oduId);
+    executor.logger.info(executor.outFields);
+} else {
+    executor.message = "No O-RU found in the config with this ID: " + oruId;
+    returnValue = false;
+}
+
+returnValue;
diff --git a/apexpolicyversion/LinkMonitor/models/LinkClearedLogic.js b/apexpolicyversion/LinkMonitor/models/LinkClearedLogic.js
new file mode 100644 (file)
index 0000000..59453ed
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+var oruId = executor.inFields.get("OruId");
+
+executor.outFields.put("message", "CLEARED link failure for O-RU: " + oruId);
+
+executor.logger.info(executor.outFields);
+
+true;
diff --git a/apexpolicyversion/LinkMonitor/models/LinkFailureLogic.js b/apexpolicyversion/LinkMonitor/models/LinkFailureLogic.js
new file mode 100644 (file)
index 0000000..ea79c33
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+var linkFailureOutput = executor.subject.getOutFieldSchemaHelper("LinkFailureOutput").createNewInstance();
+
+var oruId = executor.inFields.get("OruId");
+var oduId = executor.inFields.get("OduId");
+
+var unlockMessageArray = new java.util.ArrayList();
+for (var i = 0; i < 1; i++) {
+    unlockMessageArray.add({
+            "id":"rrm-pol-1",
+            "radio_DasH_resource_DasH_management_DasH_policy_DasH_max_DasH_ratio":25,
+            "radio_DasH_resource_DasH_management_DasH_policy_DasH_members":
+                [
+                    {
+                        "mobile_DasH_country_DasH_code":"310",
+                        "mobile_DasH_network_DasH_code":"150",
+                        "slice_DasH_differentiator":1,
+                        "slice_DasH_service_DasH_type":1
+                    }
+                ],
+            "radio_DasH_resource_DasH_management_DasH_policy_DasH_min_DasH_ratio":15,
+            "user_DasH_label":"rrm-pol-1",
+            "resource_DasH_type":"prb",
+            "radio_DasH_resource_DasH_management_DasH_policy_DasH_dedicated_DasH_ratio":20,
+            "administrative_DasH_state":"unlocked"
+        });
+}
+
+linkFailureOutput.put("o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio", unlockMessageArray);
+executor.outFields.put("LinkFailureOutput", linkFailureOutput.toString());
+
+executor.getExecutionProperties().setProperty("OduId", oduId);
+executor.getExecutionProperties().setProperty("OruId", oruId);
+
+executor.logger.info(executor.outFields);
+
+true;
diff --git a/apexpolicyversion/LinkMonitor/models/LinkMonitorModelJavascript_0.0.1.apex b/apexpolicyversion/LinkMonitor/models/LinkMonitorModelJavascript_0.0.1.apex
new file mode 100644 (file)
index 0000000..91e73d1
--- /dev/null
@@ -0,0 +1,132 @@
+#-------------------------------------------------------------------------------
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Nordix Foundation.
+# ================================================================================
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#-------------------------------------------------------------------------------
+
+##### Model #####
+
+model create name=LinkMonitorModel version=0.0.1 uuid=540226fb-55ee-4f0e-a444-983a0494818e description="This is the Apex Policy Model for link monitoring."
+
+
+##### Schemas #####
+
+schema create name=LinkFailureInputSchema flavour=Avro schema=LS
+#MACROFILE:"examples/LinkMonitor/schemas/LinkFailureInputSchema.avsc"
+LE
+schema create name=LinkFailureOutputSchema flavour=Avro schema=LS
+#MACROFILE:"examples/LinkMonitor/schemas/LinkFailureOutputSchema.avsc"
+LE
+schema create name=MessageSchema description="A schema for messages from apex" flavour=Java schema=java.lang.String
+schema create name=OruIdSchema description="A schema for O-RU-ID" flavour=Java schema=java.lang.String
+schema create name=OduIdSchema description="A schema for O-DU-ID" flavour=Java schema=java.lang.String
+
+
+##### Tasks #####
+
+task create name=LinkFailureTask version=0.0.1 uuid=3351b0f4-cf06-4fa2-8823-edf67bd30223 description=LS
+This task updates the config for O-RU when link failure is detected.
+LE
+task inputfield create name=LinkFailureTask fieldName=OruId schemaName=OruIdSchema
+task inputfield create name=LinkFailureTask fieldName=OduId schemaName=OduIdSchema
+task outputfield create name=LinkFailureTask fieldName=LinkFailureOutput schemaName=LinkFailureOutputSchema
+task logic create name=LinkFailureTask logicFlavour=JAVASCRIPT logic=LS
+#MACROFILE:"examples/LinkMonitor/models/LinkFailureLogic.js"
+LE
+
+task create name=LinkClearedTask version=0.0.1 uuid=eecfde90-896c-4343-8f9c-2603ced94e2d description=LS
+This task sends a message to the output when link failure is cleared.
+LE
+task inputfield create name=LinkClearedTask fieldName=OruId schemaName=OruIdSchema
+task outputfield create name=LinkClearedTask fieldName=message schemaName=MessageSchema
+task logic create name=LinkClearedTask logicFlavour=JAVASCRIPT logic=LS
+#MACROFILE:"examples/LinkMonitor/models/LinkClearedLogic.js"
+LE
+
+task create name=NoPolicyDefinedTask version=0.0.1 uuid=d48b619e-d00d-4008-b884-02d76ea4350b description=LS
+This task sends a message to the output when an event is received for which no policy has been defined.
+LE
+task inputfield create name=NoPolicyDefinedTask fieldName=LinkFailureInput schemaName=LinkFailureInputSchema
+task outputfield create name=NoPolicyDefinedTask fieldName=message schemaName=MessageSchema
+task logic create name=NoPolicyDefinedTask logicFlavour=JAVASCRIPT logic=LS
+#MACROFILE:"examples/LinkMonitor/models/NoPolicyDefinedLogic.js"
+LE
+
+task create name=CreateLinkClearedOutfieldsTask version=0.0.1 uuid=fd594e88-411d-4a94-b2be-697b3a0d7adf description=LS
+This task creates the output fields when link failure is cleared.
+LE
+task inputfield create name=CreateLinkClearedOutfieldsTask fieldName=LinkFailureInput schemaName=LinkFailureInputSchema
+task outputfield create name=CreateLinkClearedOutfieldsTask fieldName=OruId schemaName=OruIdSchema
+task logic create name=CreateLinkClearedOutfieldsTask logicFlavour=JAVASCRIPT logic=LS
+#MACROFILE:"examples/LinkMonitor/models/CreateLinkClearedOutfieldsLogic.js"
+LE
+
+task create name=CreateLinkFailureOutfieldsTask version=0.0.1 uuid=ac3d9842-80af-4a98-951c-bd79a431c613 description=LS
+This task the output fields when link failure is detected.
+LE
+task inputfield create name=CreateLinkFailureOutfieldsTask fieldName=LinkFailureInput schemaName=LinkFailureInputSchema
+task outputfield create name=CreateLinkFailureOutfieldsTask fieldName=OruId schemaName=OruIdSchema
+task outputfield create name=CreateLinkFailureOutfieldsTask fieldName=OduId schemaName=OduIdSchema
+task logic create name=CreateLinkFailureOutfieldsTask logicFlavour=JAVASCRIPT logic=LS
+#MACROFILE:"examples/LinkMonitor/models/CreateLinkFailureOutfieldsLogic.js"
+LE
+
+
+##### Events #####
+
+event create name=LinkFailureInputEvent version=0.0.1 uuid=c4500941-3f98-4080-a9cc-5b9753ed050b source=DMAAP target=APEX
+event parameter create name=LinkFailureInputEvent parName=LinkFailureInput schemaName=LinkFailureInputSchema
+
+event create name=LinkFailureOutputEvent version=0.0.1 uuid=4f04aa98-e917-4f4a-882a-c75ba5a99374 source="APEX" target="OAM"
+event parameter create name=LinkFailureOutputEvent parName=LinkFailureOutput schemaName=LinkFailureOutputSchema
+
+event create name=ApexMessageOutputEvent version=0.0.1 uuid=cca47d74-7754-4a61-b163-ca31f66b157b source="APEX" target="APEX"
+event parameter create name=ApexMessageOutputEvent parName=message schemaName=MessageSchema
+
+event create name=CreateLinkClearedOutfieldsEvent version=0.0.1 source="APEX" target="APEX"
+event parameter create name=CreateLinkClearedOutfieldsEvent parName=OruId schemaName=OruIdSchema
+
+event create name=CreateLinkFailureOutfieldsEvent version=0.0.1 source="APEX" target="APEX"
+event parameter create name=CreateLinkFailureOutfieldsEvent parName=OruId schemaName=OruIdSchema
+event parameter create name=CreateLinkFailureOutfieldsEvent parName=OduId schemaName=OduIdSchema
+
+
+##### Policy #####
+
+policy create name=LinkMonitorPolicy version=0.0.1 uuid=6c5e410f-489a-46ff-964e-982ce6e8b6d0 template=Freestyle firstState=LinkFailureOrClearedState
+
+
+##### States #####
+
+policy state create name=LinkMonitorPolicy stateName=LinkFailureState triggerName=CreateLinkFailureOutfieldsEvent defaultTaskName=LinkFailureTask
+policy state output create name=LinkMonitorPolicy stateName=LinkFailureState outputName=LinkFailureLogic_Output_Direct eventName=LinkFailureOutputEvent nextState=NULL
+policy state taskref create name=LinkMonitorPolicy stateName=LinkFailureState taskLocalName=LinkFailureTask taskName=LinkFailureTask outputType=DIRECT outputName=LinkFailureLogic_Output_Direct
+
+policy state create name=LinkMonitorPolicy stateName=LinkClearedState triggerName=CreateLinkClearedOutfieldsEvent defaultTaskName=LinkClearedTask
+policy state output create name=LinkMonitorPolicy stateName=LinkClearedState outputName=LinkClearedLogic_Output_Direct eventName=ApexMessageOutputEvent nextState=NULL
+policy state taskref create name=LinkMonitorPolicy stateName=LinkClearedState taskLocalName=LinkClearedTask taskName=LinkClearedTask outputType=DIRECT outputName=LinkClearedLogic_Output_Direct
+
+policy state create name=LinkMonitorPolicy stateName=LinkFailureOrClearedState triggerName=LinkFailureInputEvent defaultTaskName=NoPolicyDefinedTask
+policy state output create name=LinkMonitorPolicy stateName=LinkFailureOrClearedState outputName=CreateLinkFailureOutfieldsLogic_Output_Direct eventName=CreateLinkFailureOutfieldsEvent nextState=LinkFailureState
+policy state taskref create name=LinkMonitorPolicy stateName=LinkFailureOrClearedState taskLocalName=CreateLinkFailureOutfieldsTask taskName=CreateLinkFailureOutfieldsTask outputType=DIRECT outputName=CreateLinkFailureOutfieldsLogic_Output_Direct
+policy state output create name=LinkMonitorPolicy stateName=LinkFailureOrClearedState outputName=CreateLinkClearedOutfieldsLogic_Output_Direct eventName=CreateLinkClearedOutfieldsEvent nextState=LinkClearedState
+policy state taskref create name=LinkMonitorPolicy stateName=LinkFailureOrClearedState taskLocalName=CreateLinkClearedOutfieldsTask taskName=CreateLinkClearedOutfieldsTask outputType=DIRECT outputName=CreateLinkClearedOutfieldsLogic_Output_Direct
+policy state output create name=LinkMonitorPolicy stateName=LinkFailureOrClearedState outputName=NoPolicyDefinedLogic_Output_Direct eventName=ApexMessageOutputEvent nextState=NULL
+policy state taskref create name=LinkMonitorPolicy stateName=LinkFailureOrClearedState taskLocalName=NoPolicyDefinedTask taskName=NoPolicyDefinedTask outputType=DIRECT outputName=NoPolicyDefinedLogic_Output_Direct
+policy state selecttasklogic create name=LinkMonitorPolicy version=0.0.1 stateName=LinkFailureOrClearedState logicFlavour=JAVASCRIPT logic=LS
+#MACROFILE:"examples/LinkMonitor/models/TaskSelectionLogic.js"
+LE
diff --git a/apexpolicyversion/LinkMonitor/models/NoPolicyDefinedLogic.js b/apexpolicyversion/LinkMonitor/models/NoPolicyDefinedLogic.js
new file mode 100644 (file)
index 0000000..0378b40
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+executor.logger.info("Task Execution: '"+executor.subject.id+"'. Input Fields: '"+executor.inFields+"'");
+
+executor.outFields.put("message", "No policy defined for this event");
+
+executor.logger.info(executor.outFields);
+
+true;
diff --git a/apexpolicyversion/LinkMonitor/models/TaskSelectionLogic.js b/apexpolicyversion/LinkMonitor/models/TaskSelectionLogic.js
new file mode 100644 (file)
index 0000000..2c3708e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+executor.logger.info("Task Selection Execution: '"+executor.subject.id+
+    "'. InputFields: '"+executor.inFields+"'");
+
+var linkFailureInput = executor.inFields.get("LinkFailureInput");
+var commonEventHeader = linkFailureInput.get("event").get("commonEventHeader");
+var domain = commonEventHeader.get("domain");
+
+taskFailure = executor.subject.getTaskKey("CreateLinkFailureOutfieldsTask");
+taskCleared = executor.subject.getTaskKey("CreateLinkClearedOutfieldsTask");
+taskDefault = executor.subject.getDefaultTaskKey();
+
+if (domain == "fault") {
+    var faultFields = linkFailureInput.get("event").get("faultFields");
+    var alarmCondition = faultFields.get("alarmCondition");
+    var eventSeverity = faultFields.get("eventSeverity");
+    if (alarmCondition == "28" && eventSeverity != "NORMAL") {
+        taskFailure.copyTo(executor.selectedTask);
+    } else if (alarmCondition == "28" && eventSeverity == "NORMAL") {
+        taskCleared.copyTo(executor.selectedTask);
+    } else {
+        taskDefault.copyTo(executor.selectedTask);
+    }
+} else {
+    taskDefault.copyTo(executor.selectedTask);
+}
+
+true;
diff --git a/apexpolicyversion/LinkMonitor/schemas/LinkFailureInputSchema.avsc b/apexpolicyversion/LinkMonitor/schemas/LinkFailureInputSchema.avsc
new file mode 100644 (file)
index 0000000..258b9fa
--- /dev/null
@@ -0,0 +1,154 @@
+{
+    "type": "record",
+    "name": "Link_Failure_Input",
+    "fields": [
+        {
+            "name": "event",
+            "type": {
+                "type": "record",
+                "name": "Event_Type",
+                "fields": [
+                    {
+                        "name": "commonEventHeader",
+                        "type": {
+                            "type": "record",
+                            "name": "Common_Event_Header_Type",
+                            "fields": [
+                                {
+                                    "name": "domain",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "eventId",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "eventName",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "eventType",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "sequence",
+                                    "type": "int"
+                                },
+                                {
+                                    "name": "priority",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "reportingEntityId",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "reportingEntityName",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "sourceId",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "sourceName",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "startEpochMicrosec",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "lastEpochMicrosec",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "nfNamingCode",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "nfVendorName",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "timeZoneOffset",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "version",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "vesEventListenerVersion",
+                                    "type": "string"
+                                }
+                            ]
+                        }
+                    },
+                    {
+                        "name": "faultFields",
+                        "type": {
+                            "type": "record",
+                            "name": "Fault_Fields_Type",
+                            "fields": [
+                                {
+                                    "name": "faultFieldsVersion",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "alarmCondition",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "alarmInterfaceA",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "eventSourceType",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "specificProblem",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "eventSeverity",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "vfStatus",
+                                    "type": "string"
+                                },
+                                {
+                                    "name": "alarmAdditionalInformation",
+                                    "type": {
+                                        "type": "record",
+                                        "name": "Alarm_Additional_Information_Type",
+                                        "fields": [
+                                            {
+                                                "name": "eventTime",
+                                                "type": "string"
+                                            },
+                                            {
+                                                "name": "equipType",
+                                                "type": "string"
+                                            },
+                                            {
+                                                "name": "vendor",
+                                                "type": "string"
+                                            },
+                                            {
+                                                "name": "model",
+                                                "type": "string"
+                                            }
+                                        ]
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                ]
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/schemas/LinkFailureOutputSchema.avsc b/apexpolicyversion/LinkMonitor/schemas/LinkFailureOutputSchema.avsc
new file mode 100644 (file)
index 0000000..c423047
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "name": "Link_Failure_Output",
+  "type": "record",
+  "fields": [
+    {
+      "name": "o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio",
+      "type": {
+        "type": "array",
+        "items": {
+          "name": "o_DasH_ran_DasH_sc_DasH_du_DasH_hello_DasH_world_ColoN_radio_DasH_resource_DasH_management_DasH_policy_DasH_ratio_record",
+          "type": "record",
+          "fields": [
+            {
+              "name": "id",
+              "type": "string"
+            },
+            {
+              "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_max_DasH_ratio",
+              "type": "int"
+            },
+            {
+              "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_members",
+              "type": {
+                "type": "array",
+                "items": {
+                  "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_members_record",
+                  "type": "record",
+                  "fields": [
+                    {
+                      "name": "mobile_DasH_country_DasH_code",
+                      "type": "string"
+                    },
+                    {
+                      "name": "mobile_DasH_network_DasH_code",
+                      "type": "string"
+                    },
+                    {
+                      "name": "slice_DasH_differentiator",
+                      "type": "int"
+                    },
+                    {
+                      "name": "slice_DasH_service_DasH_type",
+                      "type": "int"
+                    }
+                  ]
+                }
+              }
+            },
+            {
+              "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_min_DasH_ratio",
+              "type": "int"
+            },
+            {
+              "name": "user_DasH_label",
+              "type": "string"
+            },
+            {
+              "name": "resource_DasH_type",
+              "type": "string"
+            },
+            {
+              "name": "radio_DasH_resource_DasH_management_DasH_policy_DasH_dedicated_DasH_ratio",
+              "type": "int"
+            },
+            {
+              "name": "administrative_DasH_state",
+              "type": "string"
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/apexpolicyversion/LinkMonitor/tosca/ToscaTemplate.json b/apexpolicyversion/LinkMonitor/tosca/ToscaTemplate.json
new file mode 100644 (file)
index 0000000..8f425a5
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "tosca_definitions_version": "tosca_simple_yaml_1_1_0",
+  "topology_template": {
+    "policies": [
+      {
+        "onap.policies.native.apex.LinkMonitor": {
+          "type": "onap.policies.native.Apex",
+          "type_version": "1.0.0",
+          "name": "onap.policies.native.apex.LinkMonitor",
+          "version": "1.0.0",
+          "properties": {
+          }
+        }
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/goversion/.gitignore b/goversion/.gitignore
new file mode 100644 (file)
index 0000000..fcf8128
--- /dev/null
@@ -0,0 +1,7 @@
+*.out
+.history
+
+oruclosedloop
+producer
+sdnr
+ics
diff --git a/goversion/Dockerfile b/goversion/Dockerfile
new file mode 100644 (file)
index 0000000..97beddd
--- /dev/null
@@ -0,0 +1,30 @@
+##
+## Build
+##
+FROM golang:1.17.1-bullseye AS build
+
+WORKDIR /app
+
+COPY go.mod ./
+COPY go.sum ./
+RUN go mod download
+
+COPY . ./
+
+RUN go build -o /docker-oruclosedloop
+
+##
+## Deploy
+##
+FROM gcr.io/distroless/base-debian10
+
+WORKDIR /
+
+## Copy from "build" stage
+COPY --from=build /docker-oruclosedloop .
+COPY --from=build /app/security/ ./security/
+COPY --from=build /app/o-ru-to-o-du-map.csv .
+
+USER nonroot:nonroot
+
+ENTRYPOINT ["/docker-oruclosedloop"]
diff --git a/goversion/Dockerfile-ics b/goversion/Dockerfile-ics
new file mode 100644 (file)
index 0000000..9c299f1
--- /dev/null
@@ -0,0 +1,40 @@
+#  Copyright (C) 2022 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+##
+## Build
+##
+FROM golang:1.17.1-bullseye AS build
+
+WORKDIR /app
+
+COPY . ./
+
+RUN go build -o /ics ./stub/ics/
+
+##
+## Deploy
+##
+FROM gcr.io/distroless/base-debian10
+
+WORKDIR /
+
+## Copy from "build" stage
+COPY --from=build /ics .
+
+USER nonroot:nonroot
+
+ENTRYPOINT ["/ics"]
diff --git a/goversion/Dockerfile-producer b/goversion/Dockerfile-producer
new file mode 100644 (file)
index 0000000..8693bbb
--- /dev/null
@@ -0,0 +1,40 @@
+#  Copyright (C) 2022 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+##
+## Build
+##
+FROM golang:1.17.1-bullseye AS build
+
+WORKDIR /app
+
+COPY . ./
+
+RUN go build -o /producer ./stub/producer/
+
+##
+## Deploy
+##
+FROM gcr.io/distroless/base-debian10
+
+WORKDIR /
+
+## Copy from "build" stage
+COPY --from=build /producer .
+
+USER nonroot:nonroot
+
+ENTRYPOINT ["/producer"]
diff --git a/goversion/Dockerfile-sdnr b/goversion/Dockerfile-sdnr
new file mode 100644 (file)
index 0000000..49cb444
--- /dev/null
@@ -0,0 +1,40 @@
+#  Copyright (C) 2022 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+##
+## Build
+##
+FROM golang:1.17.1-bullseye AS build
+
+WORKDIR /app
+
+COPY . ./
+
+RUN go build -o /sdnrstub ./stub/sdnr/
+
+##
+## Deploy
+##
+FROM gcr.io/distroless/base-debian10
+
+WORKDIR /
+
+## Copy from "build" stage
+COPY --from=build /sdnrstub .
+
+USER nonroot:nonroot
+
+ENTRYPOINT ["/sdnrstub"]
diff --git a/goversion/LICENSE.txt b/goversion/LICENSE.txt
new file mode 100644 (file)
index 0000000..96589bf
--- /dev/null
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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/goversion/README.md b/goversion/README.md
new file mode 100644 (file)
index 0000000..45207cb
--- /dev/null
@@ -0,0 +1,75 @@
+# O-RAN-SC Non-RealTime RIC O-RU O-DU Link Failure Consumer
+
+This consumer creates a job of type `STD_Fault_Messages` in the Information Coordinator Service (ICS). When it recieves messages, it checks if they are link failure messages. If they are, it checks if the event severity is other than normal. If so, it looks up the O-DU ID mapped to the O-RU where the message originates from and sends a configuration message to the O-DU through SDNC. If the event severity is normal, then it logs, on `Debug` level, that the link failure has been cleared.
+
+## Configuration
+
+The consumer takes a number of environment variables, described below, as configuration.
+
+>- CONSUMER_HOST        **Required**. The host for the consumer.                                   Example: `http://mrproducer`
+>- CONSUMER_PORT        **Required**. The port for the consumer.                                   Example: `8095`
+>- CONSUMER_CERT_PATH   **Required**. The path to the certificate to use for https.                Defaults to `security/producer.crt`
+>- CONSUMER_KEY_PATH    **Required**. The path to the key to the certificate to use for https.     Defaults to `security/producer.key`
+>- INFO_COORD_ADDR      Optional. The address of the Information Coordinator.                      Defaults to `http://enrichmentservice:8083`.
+>- SDNR_ADDR            Optional. The address for SDNR.                                            Defaults to `http://localhost:3904`.
+>- SDNR_USER            Optional. The user for the SDNR.                                           Defaults to `admin`.
+>- SDNR_PASSWORD        Optional. The password for the SDNR user.                                  Defaults to `Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U`.
+>- ORU_TO_ODU_MAP_FILE  Optional. The file containing the mapping from O-RU ID to O-DU ID.         Defaults to `o-ru-to-o-du-map.csv`.
+>- LOG_LEVEL            Optional. The log level, which can be `Error`, `Warn`, `Info` or `Debug`.  Defaults to `Info`.
+
+Any of the addresses used by this product can be configured to use https, by specifying it as the scheme of the address URI. The client will not use server certificate verification. The consumer's own callback will only listen to the scheme configured in the scheme of the consumer host address.
+
+The configured public key and cerificate shall be PEM-encoded. A self signed certificate and key are provided in the `security` folder of the project. These files should be replaced for production. To generate a self signed key and certificate, use the example code below:
+
+    openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650
+
+## Functionality
+
+The creation of the job is not done when the consumer is started. Instead the consumer provides a REST API where it can be started and stopped, described below. The API is available on the host and port configured for the consumer
+
+>- /admin/start  Creates the job in ICS.
+>- /admin/stop   Deletes the job in ICS.
+
+If the consumer is shut down with a SIGTERM, it will also delete the job before exiting.
+
+There is also a status call provided in the REST API. This will return the running status of the consumer as JSON.
+>- /status  {"status": "started/stopped"}
+
+## Development
+
+To make it easy to test during development of the consumer, three stubs are provided in the `stub` folder.
+
+A producer stub, under the `producer` folder, that stubs the producer and pushes an array with one message with `eventSeverity` alternating between `NORMAL` and `CRITICAL`. The stub does not start to send messages until it recieves a create job call from the ICS stub. When a delete job call comes from the ICS stub it stops sending messages. To build and start the stub, do the following:
+>1. cd stub/producer
+>2. go build
+>3. ./producer
+
+An ICS stub, under the `ics` folder, that listens for create and delete job calls from the consumer. When it gets a call it calls the producer stub with the correct create or delete call and the provided job ID. By default, it listens to the port `8083`, but his can be overridden by passing a `-port [PORT]` flag when starting the stub. To build and start the stub, do the following:
+>1. cd stub/ics
+>2. go build
+>3. ./ics
+
+
+An SNDR stub, under the `sdnr` folder, that at startup will listen for REST calls and print the body of them. By default, it listens to the port `3904`, but his can be overridden by passing a `-port [PORT]` flag when starting the stub. To build and start the stub, do the following:
+>1. cd stub/sdnr
+>2. go build
+>3. ./sdnr
+
+Mocks needed for unit tests have been generated using `github.com/stretchr/testify/mock` and are checked in under the `mocks` folder. **Note!** Keep in mind that if any of the mocked interfaces change, a new mock for that interface must be generated and checked in.
+
+## License
+
+Copyright (C) 2021 Nordix Foundation.
+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.
+
+For more information about license please see the [LICENSE](LICENSE.txt) file for details.
diff --git a/goversion/build-oruclosedloopconsumer-ubuntu.sh b/goversion/build-oruclosedloopconsumer-ubuntu.sh
new file mode 100644 (file)
index 0000000..c59abd7
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/bash
+##############################################################################
+#
+#   Copyright (C) 2021: Nordix Foundation
+#
+#   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.
+#
+##############################################################################
+set -eux
+
+echo "--> build-oruclosedloopconsumer-ubuntu.sh"
+curdir=`pwd`
+# go installs tools like go-acc to $HOME/go/bin
+# ubuntu minion path lacks go
+export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
+go version
+cd test/usecases/oruclosedlooprecovery/goversion/
+
+# install the go coverage tool helper
+go get -v github.com/ory/go-acc
+
+export GO111MODULE=on
+go get github.com/stretchr/testify/mock@v1.7.0
+
+go-acc ./... --ignore mocks
+
+sed -i -e 's/oransc\.org\/usecase\/oruclosedloop/test\/usecases\/oruclosedlooprecovery\/goversion/' coverage.txt
+
+cp coverage.txt $curdir
+echo "--> build-oruclosedloopconsumer-ubuntu.sh ends"
diff --git a/goversion/container-tag.yaml b/goversion/container-tag.yaml
new file mode 100644 (file)
index 0000000..f84eeb1
--- /dev/null
@@ -0,0 +1,5 @@
+# The Jenkins job requires a tag to build the Docker image.
+# By default this file is in the docker build directory,
+# but the location can configured in the JJB template.
+---
+tag: 1.1.0
diff --git a/goversion/docker-compose.yaml b/goversion/docker-compose.yaml
new file mode 100644 (file)
index 0000000..ef5340b
--- /dev/null
@@ -0,0 +1,82 @@
+#  Copyright (C) 2022 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+version: '3.5'
+
+networks:
+  default:
+    driver: bridge
+    name: nonrtric-docker-net
+
+services:
+  ics:
+    build:
+      context: .
+      dockerfile: Dockerfile-ics
+    container_name: ics-sim
+    networks:
+      default:
+        aliases:
+          - ics-sim
+    ports:
+      - 8083:8083
+    environment:
+      - PRODUCER_ADDR=http://producer-sim:8085/
+
+  sdnr-simulator:
+    build:
+      context: .
+      dockerfile: Dockerfile-sdnr
+    container_name: sdnr-sim
+    networks:
+      default:
+        aliases:
+          - sdnr-sim
+    ports:
+      - 3904:3904
+
+  producer:
+    build:
+      context: .
+      dockerfile: Dockerfile-producer
+    container_name: producer-sim
+    networks:
+      default:
+        aliases:
+          - producer-sim
+    ports:
+      - 8085:8085
+    environment:
+      - ORU_ADDR=http://oru-app:8086
+
+  oru-app:
+    build:
+      context: .
+      dockerfile: Dockerfile
+    container_name: oru-app
+    networks:
+      default:
+        aliases:
+          - oru-app
+    ports:
+      - 8086:8086
+    environment:
+      - CONSUMER_HOST=http://producer-sim
+      - CONSUMER_PORT=8086
+      - INFO_COORD_ADDR=http://ics-sim:8083
+      - SDNR_ADDR=http://sdnr-sim:3904
+      - CONSUMER_CERT_PATH=security/consumer.crt
+      - CONSUMER_KEY_PATH=security/consumer.key
+      - LOG_LEVEL=Debug
\ No newline at end of file
diff --git a/goversion/go.mod b/goversion/go.mod
new file mode 100644 (file)
index 0000000..4bfef68
--- /dev/null
@@ -0,0 +1,19 @@
+module oransc.org/usecase/oruclosedloop
+
+go 1.17
+
+require (
+       github.com/sirupsen/logrus v1.8.1
+       github.com/stretchr/testify v1.7.0
+       github.com/hashicorp/go-retryablehttp v0.7.0
+)
+
+require (
+       github.com/davecgh/go-spew v1.1.1 // indirect
+       github.com/gorilla/mux v1.8.0
+       github.com/pmezard/go-difflib v1.0.0 // indirect
+       github.com/stretchr/objx v0.1.1 // indirect
+       golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
+       gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
+       github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
+)
diff --git a/goversion/go.sum b/goversion/go.sum
new file mode 100644 (file)
index 0000000..970999b
--- /dev/null
@@ -0,0 +1,28 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4=
+github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/goversion/internal/config/config.go b/goversion/internal/config/config.go
new file mode 100644 (file)
index 0000000..5233128
--- /dev/null
@@ -0,0 +1,91 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package config
+
+import (
+       "fmt"
+       "os"
+       "strconv"
+
+       log "github.com/sirupsen/logrus"
+)
+
+type Config struct {
+       ConsumerHost           string
+       ConsumerPort           int
+       InfoCoordinatorAddress string
+       SDNRAddress            string
+       SDNRUser               string
+       SDNPassword            string
+       ORUToODUMapFile        string
+       ConsumerCertPath       string
+       ConsumerKeyPath        string
+       LogLevel               log.Level
+}
+
+func New() *Config {
+       return &Config{
+               ConsumerHost:           getEnv("CONSUMER_HOST", ""),
+               ConsumerPort:           getEnvAsInt("CONSUMER_PORT", 0),
+               InfoCoordinatorAddress: getEnv("INFO_COORD_ADDR", "http://enrichmentservice:8083"),
+               SDNRAddress:            getEnv("SDNR_ADDR", "http://localhost:3904"),
+               SDNRUser:               getEnv("SDNR_USER", "admin"),
+               SDNPassword:            getEnv("SDNR_PASSWORD", "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"),
+               ORUToODUMapFile:        getEnv("ORU_TO_ODU_MAP_FILE", "o-ru-to-o-du-map.csv"),
+               ConsumerCertPath:       getEnv("CONSUMER_CERT_PATH", "security/consumer.crt"),
+               ConsumerKeyPath:        getEnv("CONSUMER_KEY_PATH", "security/consumer.key"),
+               LogLevel:               getLogLevel(),
+       }
+}
+
+func (c Config) String() string {
+       return fmt.Sprintf("{ConsumerHost: %v, ConsumerPort: %v, InfoCoordinatorAddress: %v, SDNRAddress: %v, SDNRUser: %v, SDNRPassword: %v, ORUToODUMapFile: %v, ConsumerCertPath: %v, ConsumerKeyPath: %v, LogLevel: %v}", c.ConsumerHost, c.ConsumerPort, c.InfoCoordinatorAddress, c.SDNRAddress, c.SDNRUser, c.SDNPassword, c.ORUToODUMapFile, c.ConsumerCertPath, c.ConsumerKeyPath, c.LogLevel)
+}
+
+func getEnv(key string, defaultVal string) string {
+       if value, exists := os.LookupEnv(key); exists {
+               return value
+       }
+
+       return defaultVal
+}
+
+func getEnvAsInt(name string, defaultVal int) int {
+       valueStr := getEnv(name, "")
+       if value, err := strconv.Atoi(valueStr); err == nil {
+               return value
+       } else if valueStr != "" {
+               log.Warnf("Invalid int value: %v for variable: %v. Default value: %v will be used", valueStr, name, defaultVal)
+       }
+
+       return defaultVal
+}
+
+func getLogLevel() log.Level {
+       logLevelStr := getEnv("LOG_LEVEL", "Info")
+       if loglevel, err := log.ParseLevel(logLevelStr); err == nil {
+               return loglevel
+       } else {
+               log.Warnf("Invalid log level: %v. Log level will be Info!", logLevelStr)
+               return log.InfoLevel
+       }
+
+}
diff --git a/goversion/internal/config/config_test.go b/goversion/internal/config/config_test.go
new file mode 100644 (file)
index 0000000..3d9983a
--- /dev/null
@@ -0,0 +1,120 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package config
+
+import (
+       "bytes"
+       "os"
+       "testing"
+
+       log "github.com/sirupsen/logrus"
+       "github.com/stretchr/testify/require"
+)
+
+func TestNew_envVarsSetConfigContainSetValues(t *testing.T) {
+       assertions := require.New(t)
+       os.Setenv("CONSUMER_HOST", "consumerHost")
+       os.Setenv("CONSUMER_PORT", "8095")
+       os.Setenv("INFO_COORD_ADDR", "infoCoordAddr")
+       os.Setenv("SDNR_ADDR", "sdnrHost:3908")
+       os.Setenv("SDNR_USER", "admin")
+       os.Setenv("SDNR_PASSWORD", "pwd")
+       os.Setenv("ORU_TO_ODU_MAP_FILE", "file")
+       os.Setenv("CONSUMER_CERT_PATH", "cert")
+       os.Setenv("CONSUMER_KEY_PATH", "key")
+       os.Setenv("LOG_LEVEL", "Debug")
+       t.Cleanup(func() {
+               os.Clearenv()
+       })
+       wantConfig := Config{
+               ConsumerHost:           "consumerHost",
+               ConsumerPort:           8095,
+               InfoCoordinatorAddress: "infoCoordAddr",
+               SDNRAddress:            "sdnrHost:3908",
+               SDNRUser:               "admin",
+               SDNPassword:            "pwd",
+               ORUToODUMapFile:        "file",
+               ConsumerCertPath:       "cert",
+               ConsumerKeyPath:        "key",
+               LogLevel:               log.DebugLevel,
+       }
+
+       got := New()
+       assertions.Equal(&wantConfig, got)
+}
+
+func TestNew_faultyIntValueSetConfigContainDefaultValueAndWarnInLog(t *testing.T) {
+       assertions := require.New(t)
+       var buf bytes.Buffer
+       log.SetOutput(&buf)
+
+       os.Setenv("CONSUMER_PORT", "wrong")
+       t.Cleanup(func() {
+               log.SetOutput(os.Stderr)
+               os.Clearenv()
+       })
+       wantConfig := Config{
+               ConsumerHost:           "",
+               ConsumerPort:           0,
+               InfoCoordinatorAddress: "http://enrichmentservice:8083",
+               SDNRAddress:            "http://localhost:3904",
+               SDNRUser:               "admin",
+               SDNPassword:            "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U",
+               ORUToODUMapFile:        "o-ru-to-o-du-map.csv",
+               ConsumerCertPath:       "security/consumer.crt",
+               ConsumerKeyPath:        "security/consumer.key",
+               LogLevel:               log.InfoLevel,
+       }
+
+       got := New()
+       assertions.Equal(&wantConfig, got)
+
+       logString := buf.String()
+       assertions.Contains(logString, "Invalid int value: wrong for variable: CONSUMER_PORT. Default value: 0 will be used")
+}
+
+func TestNew_envFaultyLogLevelConfigContainDefaultValues(t *testing.T) {
+       assertions := require.New(t)
+       var buf bytes.Buffer
+       log.SetOutput(&buf)
+
+       os.Setenv("LOG_LEVEL", "wrong")
+       t.Cleanup(func() {
+               log.SetOutput(os.Stderr)
+               os.Clearenv()
+       })
+       wantConfig := Config{
+               ConsumerHost:           "",
+               ConsumerPort:           0,
+               InfoCoordinatorAddress: "http://enrichmentservice:8083",
+               SDNRAddress:            "http://localhost:3904",
+               SDNRUser:               "admin",
+               SDNPassword:            "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U",
+               ORUToODUMapFile:        "o-ru-to-o-du-map.csv",
+               ConsumerCertPath:       "security/consumer.crt",
+               ConsumerKeyPath:        "security/consumer.key",
+               LogLevel:               log.InfoLevel,
+       }
+       got := New()
+       assertions.Equal(&wantConfig, got)
+       logString := buf.String()
+       assertions.Contains(logString, "Invalid log level: wrong. Log level will be Info!")
+}
diff --git a/goversion/internal/linkfailure/linkfailurehandler.go b/goversion/internal/linkfailure/linkfailurehandler.go
new file mode 100644 (file)
index 0000000..bf3d83b
--- /dev/null
@@ -0,0 +1,89 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package linkfailure
+
+import (
+       "net/http"
+       "strings"
+
+       log "github.com/sirupsen/logrus"
+
+       "oransc.org/usecase/oruclosedloop/internal/repository"
+       "oransc.org/usecase/oruclosedloop/internal/restclient"
+       "oransc.org/usecase/oruclosedloop/internal/ves"
+)
+
+type Configuration struct {
+       SDNRAddress  string
+       SDNRUser     string
+       SDNRPassword string
+}
+
+const rawSdnrPath = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=[O-DU-ID]/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions=[O-DU-ID]/radio-resource-management-policy-ratio=rrm-pol-1"
+const unlockMessage = `{"o-ran-sc-du-hello-world:radio-resource-management-policy-ratio":[{"id":"rrm-pol-1","radio-resource-management-policy-max-ratio":25,"radio-resource-management-policy-members":[{"mobile-country-code":"310","mobile-network-code":"150","slice-differentiator":1,"slice-service-type":1}],"radio-resource-management-policy-min-ratio":15,"user-label":"rrm-pol-1","resource-type":"prb","radio-resource-management-policy-dedicated-ratio":20,"administrative-state":"unlocked"}]}`
+
+type LinkFailureHandler struct {
+       lookupService repository.LookupService
+       config        Configuration
+       client        restclient.HTTPClient
+}
+
+func NewLinkFailureHandler(ls repository.LookupService, conf Configuration, client restclient.HTTPClient) *LinkFailureHandler {
+       return &LinkFailureHandler{
+               lookupService: ls,
+               config:        conf,
+               client:        client,
+       }
+}
+
+func (lfh LinkFailureHandler) MessagesHandler(w http.ResponseWriter, r *http.Request) {
+       log.Debug("Handling messages")
+       if messages := ves.GetVesMessages(r.Body); messages != nil {
+               faultMessages := ves.GetFaultMessages(messages)
+
+               for _, message := range *faultMessages {
+                       if message.IsLinkFailure() {
+                               lfh.sendUnlockMessage(message.GetORuId())
+                       } else if message.IsClearLinkFailure() {
+                               log.Debugf("Cleared Link failure for O-RU ID: %v", message.GetORuId())
+                       }
+               }
+       }
+}
+
+func (lfh LinkFailureHandler) sendUnlockMessage(oRuId string) {
+       if oDuId, err := lfh.lookupService.GetODuID(oRuId); err == nil {
+               sdnrPath := getSdnrPath(oDuId)
+               if error := restclient.Put(lfh.config.SDNRAddress+sdnrPath, unlockMessage, lfh.client, lfh.config.SDNRUser, lfh.config.SDNRPassword); error == nil {
+                       log.Debugf("Sent unlock message for O-RU: %v to O-DU: %v.", oRuId, oDuId)
+               } else {
+                       log.Warn("Send of unlock message failed due to ", error)
+               }
+       } else {
+               log.Warn("Send of unlock message failed due to ", err)
+       }
+
+}
+
+func getSdnrPath(oDuId string) string {
+       sdnrPath := strings.Replace(rawSdnrPath, "[O-DU-ID]", oDuId, -1)
+       return sdnrPath
+}
diff --git a/goversion/internal/linkfailure/linkfailurehandler_test.go b/goversion/internal/linkfailure/linkfailurehandler_test.go
new file mode 100644 (file)
index 0000000..050417f
--- /dev/null
@@ -0,0 +1,180 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package linkfailure
+
+import (
+       "bytes"
+       "encoding/json"
+       "io/ioutil"
+       "net/http"
+       "net/http/httptest"
+       "os"
+       "testing"
+
+       log "github.com/sirupsen/logrus"
+
+       "github.com/stretchr/testify/mock"
+       "github.com/stretchr/testify/require"
+       "oransc.org/usecase/oruclosedloop/internal/repository"
+       "oransc.org/usecase/oruclosedloop/internal/ves"
+       "oransc.org/usecase/oruclosedloop/mocks"
+)
+
+func Test_MessagesHandlerWithLinkFailure(t *testing.T) {
+       log.SetLevel(log.DebugLevel)
+       assertions := require.New(t)
+
+       var buf bytes.Buffer
+       log.SetOutput(&buf)
+       defer func() {
+               log.SetOutput(os.Stderr)
+       }()
+
+       clientMock := mocks.HTTPClient{}
+
+       clientMock.On("Do", mock.Anything).Return(&http.Response{
+               StatusCode: http.StatusOK,
+       }, nil)
+
+       lookupServiceMock := mocks.LookupService{}
+
+       lookupServiceMock.On("GetODuID", mock.Anything).Return("O-DU-1122", nil)
+
+       handlerUnderTest := NewLinkFailureHandler(&lookupServiceMock, Configuration{
+               SDNRAddress:  "http://localhost:9990",
+               SDNRUser:     "admin",
+               SDNRPassword: "pwd",
+       }, &clientMock)
+
+       responseRecorder := httptest.NewRecorder()
+       r := newRequest(http.MethodPost, "/", getFaultMessage("ERICSSON-O-RU-11220", "CRITICAL"), t)
+       handler := http.HandlerFunc(handlerUnderTest.MessagesHandler)
+       handler.ServeHTTP(responseRecorder, r)
+       assertions.Equal(http.StatusOK, responseRecorder.Result().StatusCode)
+
+       var actualRequest *http.Request
+       clientMock.AssertCalled(t, "Do", mock.MatchedBy(func(req *http.Request) bool {
+               actualRequest = req
+               return true
+       }))
+       assertions.Equal(http.MethodPut, actualRequest.Method)
+       assertions.Equal("http", actualRequest.URL.Scheme)
+       assertions.Equal("localhost:9990", actualRequest.URL.Host)
+       expectedSdnrPath := "/rests/data/network-topology:network-topology/topology=topology-netconf/node=O-DU-1122/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions=O-DU-1122/radio-resource-management-policy-ratio=rrm-pol-1"
+       assertions.Equal(expectedSdnrPath, actualRequest.URL.Path)
+       assertions.Equal("application/json; charset=utf-8", actualRequest.Header.Get("Content-Type"))
+       tempRequest, _ := http.NewRequest("", "", nil)
+       tempRequest.SetBasicAuth("admin", "pwd")
+       assertions.Equal(tempRequest.Header.Get("Authorization"), actualRequest.Header.Get("Authorization"))
+       body, _ := ioutil.ReadAll(actualRequest.Body)
+       expectedBody := []byte(`{"o-ran-sc-du-hello-world:radio-resource-management-policy-ratio":[{"id":"rrm-pol-1","radio-resource-management-policy-max-ratio":25,"radio-resource-management-policy-members":[{"mobile-country-code":"310","mobile-network-code":"150","slice-differentiator":1,"slice-service-type":1}],"radio-resource-management-policy-min-ratio":15,"user-label":"rrm-pol-1","resource-type":"prb","radio-resource-management-policy-dedicated-ratio":20,"administrative-state":"unlocked"}]}`)
+       assertions.Equal(expectedBody, body)
+       clientMock.AssertNumberOfCalls(t, "Do", 1)
+
+       logString := buf.String()
+       assertions.Contains(logString, "Sent unlock message")
+       assertions.Contains(logString, "O-RU: ERICSSON-O-RU-11220")
+       assertions.Contains(logString, "O-DU: O-DU-1122")
+}
+
+func newRequest(method string, url string, bodyAsBytes []byte, t *testing.T) *http.Request {
+       body := ioutil.NopCloser(bytes.NewReader(bodyAsBytes))
+       if req, err := http.NewRequest(method, url, body); err == nil {
+               return req
+       } else {
+               t.Fatalf("Could not create request due to: %v", err)
+               return nil
+       }
+}
+
+func Test_MessagesHandlerWithClearLinkFailure(t *testing.T) {
+       log.SetLevel(log.DebugLevel)
+       assertions := require.New(t)
+
+       var buf bytes.Buffer
+       log.SetOutput(&buf)
+       defer func() {
+               log.SetOutput(os.Stderr)
+       }()
+
+       lookupServiceMock := mocks.LookupService{}
+
+       lookupServiceMock.On("GetODuID", mock.Anything).Return("O-DU-1122", nil)
+
+       handlerUnderTest := NewLinkFailureHandler(&lookupServiceMock, Configuration{}, nil)
+
+       responseRecorder := httptest.NewRecorder()
+       r := newRequest(http.MethodPost, "/", getFaultMessage("ERICSSON-O-RU-11220", "NORMAL"), t)
+       handler := http.HandlerFunc(handlerUnderTest.MessagesHandler)
+       handler.ServeHTTP(responseRecorder, r)
+       assertions.Equal(http.StatusOK, responseRecorder.Result().StatusCode)
+
+       logString := buf.String()
+       assertions.Contains(logString, "Cleared Link failure")
+       assertions.Contains(logString, "O-RU ID: ERICSSON-O-RU-11220")
+}
+
+func Test_MessagesHandlerWithLinkFailureUnmappedORU(t *testing.T) {
+       log.SetLevel(log.DebugLevel)
+       assertions := require.New(t)
+
+       var buf bytes.Buffer
+       log.SetOutput(&buf)
+       defer func() {
+               log.SetOutput(os.Stderr)
+       }()
+
+       lookupServiceMock := mocks.LookupService{}
+
+       lookupServiceMock.On("GetODuID", mock.Anything).Return("", repository.IdNotMappedError{
+               Id: "ERICSSON-O-RU-11220",
+       })
+
+       handlerUnderTest := NewLinkFailureHandler(&lookupServiceMock, Configuration{}, nil)
+
+       responseRecorder := httptest.NewRecorder()
+       r := newRequest(http.MethodPost, "/", getFaultMessage("ERICSSON-O-RU-11220", "CRITICAL"), t)
+       handler := http.HandlerFunc(handlerUnderTest.MessagesHandler)
+       handler.ServeHTTP(responseRecorder, r)
+       assertions.Equal(http.StatusOK, responseRecorder.Result().StatusCode)
+
+       logString := buf.String()
+       assertions.Contains(logString, "O-RU-ID: ERICSSON-O-RU-11220 not mapped.")
+}
+
+func getFaultMessage(sourceName string, eventSeverity string) []byte {
+       linkFailureMessage := ves.FaultMessage{
+               Event: ves.Event{
+                       CommonEventHeader: ves.CommonEventHeader{
+                               Domain:     "fault",
+                               SourceName: sourceName,
+                       },
+                       FaultFields: ves.FaultFields{
+                               AlarmCondition: "28",
+                               EventSeverity:  eventSeverity,
+                       },
+               },
+       }
+       messageAsByteArray, _ := json.Marshal(linkFailureMessage)
+       response := [1]string{string(messageAsByteArray)}
+       responseAsByteArray, _ := json.Marshal(response)
+       return responseAsByteArray
+}
diff --git a/goversion/internal/repository/csvhelp.go b/goversion/internal/repository/csvhelp.go
new file mode 100644 (file)
index 0000000..c5afda7
--- /dev/null
@@ -0,0 +1,51 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package repository
+
+import (
+       "encoding/csv"
+       "os"
+)
+
+type CsvFileHelper interface {
+       GetCsvFromFile(name string) ([][]string, error)
+}
+
+type CsvFileHelperImpl struct{}
+
+func NewCsvFileHelperImpl() CsvFileHelperImpl {
+       return CsvFileHelperImpl{}
+}
+
+func (h CsvFileHelperImpl) GetCsvFromFile(name string) ([][]string, error) {
+       if csvFile, err := os.Open(name); err == nil {
+               defer csvFile.Close()
+               reader := csv.NewReader(csvFile)
+               reader.FieldsPerRecord = -1
+               if csvData, err := reader.ReadAll(); err == nil {
+                       return csvData, nil
+               } else {
+                       return nil, err
+               }
+       } else {
+               return nil, err
+       }
+}
diff --git a/goversion/internal/repository/csvhelp_test.go b/goversion/internal/repository/csvhelp_test.go
new file mode 100644 (file)
index 0000000..ddcc229
--- /dev/null
@@ -0,0 +1,76 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package repository
+
+import (
+       "os"
+       "testing"
+
+       "github.com/stretchr/testify/require"
+)
+
+func TestCsvFileHelperImpl_GetCsvFromFile(t *testing.T) {
+       assertions := require.New(t)
+       filePath := createTempCsvFile()
+       defer os.Remove(filePath)
+       type args struct {
+               name string
+       }
+       tests := []struct {
+               name          string
+               args          args
+               want          [][]string
+               wantErrString string
+       }{
+               {
+                       name: "Read from file should return array of content",
+                       args: args{
+                               name: filePath,
+                       },
+                       want: [][]string{{"O-RU-ID", "O-DU-ID"}},
+               },
+               {
+                       name: "File missing should return error",
+                       args: args{
+                               name: "nofile.csv",
+                       },
+                       wantErrString: "open nofile.csv: no such file or directory",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       h := NewCsvFileHelperImpl()
+                       got, err := h.GetCsvFromFile(tt.args.name)
+                       assertions.Equal(tt.want, got)
+                       if tt.wantErrString != "" {
+                               assertions.Contains(err.Error(), tt.wantErrString)
+                       }
+               })
+       }
+}
+
+func createTempCsvFile() string {
+       csvFile, _ := os.CreateTemp("", "test*.csv")
+       filePath := csvFile.Name()
+       csvFile.Write([]byte("O-RU-ID,O-DU-ID"))
+       csvFile.Close()
+       return filePath
+}
diff --git a/goversion/internal/repository/lookupservice.go b/goversion/internal/repository/lookupservice.go
new file mode 100644 (file)
index 0000000..1b6fa69
--- /dev/null
@@ -0,0 +1,73 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package repository
+
+import (
+       "fmt"
+)
+
+type IdNotMappedError struct {
+       Id string
+}
+
+func (inme IdNotMappedError) Error() string {
+       return fmt.Sprintf("O-RU-ID: %v not mapped.", inme.Id)
+}
+
+type LookupService interface {
+       Init() error
+       GetODuID(oRuId string) (string, error)
+}
+
+type LookupServiceImpl struct {
+       csvFileHelper CsvFileHelper
+       csvFileName   string
+
+       oRuIdToODuIdMap map[string]string
+}
+
+func NewLookupServiceImpl(fileHelper CsvFileHelper, fileName string) *LookupServiceImpl {
+       s := LookupServiceImpl{
+               csvFileHelper: fileHelper,
+               csvFileName:   fileName,
+       }
+       s.oRuIdToODuIdMap = make(map[string]string)
+       return &s
+}
+
+func (s LookupServiceImpl) Init() error {
+       if csvData, err := s.csvFileHelper.GetCsvFromFile(s.csvFileName); err == nil {
+               for _, each := range csvData {
+                       s.oRuIdToODuIdMap[each[0]] = each[1]
+               }
+               return nil
+       } else {
+               return err
+       }
+}
+
+func (s LookupServiceImpl) GetODuID(oRuId string) (string, error) {
+       if oDuId, ok := s.oRuIdToODuIdMap[oRuId]; ok {
+               return oDuId, nil
+       } else {
+               return "", IdNotMappedError{Id: oRuId}
+       }
+}
diff --git a/goversion/internal/repository/lookupservice_test.go b/goversion/internal/repository/lookupservice_test.go
new file mode 100644 (file)
index 0000000..8cfdbdc
--- /dev/null
@@ -0,0 +1,176 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package repository
+
+import (
+       "errors"
+       "testing"
+
+       "github.com/stretchr/testify/require"
+       "oransc.org/usecase/oruclosedloop/mocks"
+)
+
+func TestIdNotMappedError(t *testing.T) {
+       assertions := require.New(t)
+
+       actualError := IdNotMappedError{
+               Id: "1",
+       }
+       assertions.Equal("O-RU-ID: 1 not mapped.", actualError.Error())
+}
+
+func TestNewLookupServiceImpl(t *testing.T) {
+       assertions := require.New(t)
+       mockCsvFileHelper := &mocks.CsvFileHelper{}
+       type args struct {
+               fileHelper CsvFileHelper
+               fileName   string
+       }
+       tests := []struct {
+               name string
+               args args
+               want *LookupServiceImpl
+       }{
+               {
+                       name: "Should return populated service",
+                       args: args{
+                               fileHelper: mockCsvFileHelper,
+                               fileName:   "test.csv",
+                       },
+                       want: &LookupServiceImpl{
+                               csvFileHelper:   mockCsvFileHelper,
+                               csvFileName:     "test.csv",
+                               oRuIdToODuIdMap: map[string]string{},
+                       },
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       got := NewLookupServiceImpl(tt.args.fileHelper, tt.args.fileName)
+                       assertions.Equal(tt.want, got)
+               })
+       }
+}
+
+func TestLookupServiceImpl_Init(t *testing.T) {
+       assertions := require.New(t)
+       type args struct {
+               csvFileName     string
+               mockReturn      [][]string
+               mockReturnError error
+       }
+       tests := []struct {
+               name                  string
+               args                  args
+               wantedORuIdToODuIdMap map[string]string
+               wantErr               error
+       }{
+               {
+                       name: "Init with proper csv file should not return error and map should be initialized",
+                       args: args{
+                               csvFileName: "./map.csv",
+                               mockReturn:  [][]string{{"O-RU-ID", "O-DU-ID"}},
+                       },
+                       wantedORuIdToODuIdMap: map[string]string{"O-RU-ID": "O-DU-ID"},
+               },
+               {
+                       name: "Init with missing file should return error and map should not be initialized",
+                       args: args{
+                               csvFileName:     "foo.csv",
+                               mockReturnError: errors.New("Error"),
+                       },
+                       wantedORuIdToODuIdMap: map[string]string{},
+                       wantErr:               errors.New("Error"),
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       mockCsvFileHelper := &mocks.CsvFileHelper{}
+                       mockCsvFileHelper.On("GetCsvFromFile", tt.args.csvFileName).Return(tt.args.mockReturn, tt.args.mockReturnError)
+
+                       s := NewLookupServiceImpl(mockCsvFileHelper, tt.args.csvFileName)
+
+                       err := s.Init()
+
+                       assertions.Equal(tt.wantErr, err, tt.name)
+                       assertions.Equal(tt.wantedORuIdToODuIdMap, s.oRuIdToODuIdMap)
+                       mockCsvFileHelper.AssertNumberOfCalls(t, "GetCsvFromFile", 1)
+               })
+       }
+}
+
+func TestLookupServiceImpl_GetODuID(t *testing.T) {
+       assertions := require.New(t)
+       type fields struct {
+               csvFileHelper   CsvFileHelper
+               csvFileName     string
+               oRuIdToODuIdMap map[string]string
+       }
+       type args struct {
+               oRuId string
+       }
+       tests := []struct {
+               name    string
+               fields  fields
+               args    args
+               want    string
+               wantErr error
+       }{
+               {
+                       name: "Id mapped should return mapped id",
+                       fields: fields{
+                               csvFileHelper:   nil,
+                               csvFileName:     "",
+                               oRuIdToODuIdMap: map[string]string{"O-RU-ID": "O-DU-ID"},
+                       },
+                       args: args{
+                               oRuId: "O-RU-ID",
+                       },
+                       want: "O-DU-ID",
+               },
+               {
+                       name: "Id not mapped should return IdNotMappedError",
+                       fields: fields{
+                               csvFileHelper:   nil,
+                               csvFileName:     "",
+                               oRuIdToODuIdMap: map[string]string{},
+                       },
+                       args: args{
+                               oRuId: "O-RU-ID",
+                       },
+                       wantErr: IdNotMappedError{Id: "O-RU-ID"},
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       s := LookupServiceImpl{
+                               csvFileHelper:   tt.fields.csvFileHelper,
+                               csvFileName:     tt.fields.csvFileName,
+                               oRuIdToODuIdMap: tt.fields.oRuIdToODuIdMap,
+                       }
+
+                       got, err := s.GetODuID(tt.args.oRuId)
+
+                       assertions.Equal(tt.wantErr, err, tt.name)
+                       assertions.Equal(tt.want, got, tt.name)
+               })
+       }
+}
diff --git a/goversion/internal/restclient/client.go b/goversion/internal/restclient/client.go
new file mode 100644 (file)
index 0000000..fdd0549
--- /dev/null
@@ -0,0 +1,132 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package restclient
+
+import (
+       "bytes"
+       "crypto/tls"
+       "fmt"
+       "io"
+       "math"
+       "net/http"
+       "net/url"
+       "time"
+
+       "github.com/hashicorp/go-retryablehttp"
+)
+
+type RequestError struct {
+       StatusCode int
+       Body       []byte
+}
+
+func (e RequestError) Error() string {
+       return fmt.Sprintf("error response with status: %v and body: %v", e.StatusCode, string(e.Body))
+}
+
+// HTTPClient interface
+type HTTPClient interface {
+       Get(url string) (*http.Response, error)
+
+       Do(*http.Request) (*http.Response, error)
+}
+
+func PutWithoutAuth(url string, body []byte, client HTTPClient) error {
+       return do(http.MethodPut, url, body, client)
+}
+
+func Put(url string, body string, client HTTPClient, userName string, password string) error {
+       return do(http.MethodPut, url, []byte(body), client, userName, password)
+}
+
+func Delete(url string, client HTTPClient) error {
+       return do(http.MethodDelete, url, nil, client)
+}
+
+func CreateClientCertificate(certPath string, keyPath string) (tls.Certificate, error) {
+       if cert, err := tls.LoadX509KeyPair(certPath, keyPath); err == nil {
+               return cert, nil
+       } else {
+               return tls.Certificate{}, fmt.Errorf("cannot create x509 keypair from cert file %s and key file %s due to: %v", certPath, keyPath, err)
+       }
+}
+
+func CreateRetryClient(cert tls.Certificate) *http.Client {
+       rawRetryClient := retryablehttp.NewClient()
+       rawRetryClient.RetryWaitMax = time.Minute
+       rawRetryClient.RetryMax = math.MaxInt
+       rawRetryClient.HTTPClient.Transport = getSecureTransportWithoutVerify(cert)
+
+       client := rawRetryClient.StandardClient()
+       return client
+}
+
+func IsUrlSecure(configUrl string) bool {
+       u, _ := url.Parse(configUrl)
+       return u.Scheme == "https"
+}
+
+func getSecureTransportWithoutVerify(cert tls.Certificate) *http.Transport {
+       return &http.Transport{
+               TLSClientConfig: &tls.Config{
+                       Certificates: []tls.Certificate{
+                               cert,
+                       },
+                       InsecureSkipVerify: true,
+               },
+       }
+}
+
+func do(method string, url string, body []byte, client HTTPClient, userInfo ...string) error {
+       if req, reqErr := http.NewRequest(method, url, bytes.NewBuffer(body)); reqErr == nil {
+               if body != nil {
+                       req.Header.Set("Content-Type", "application/json; charset=utf-8")
+               }
+               if len(userInfo) > 0 {
+                       req.SetBasicAuth(userInfo[0], userInfo[1])
+               }
+               if response, respErr := client.Do(req); respErr == nil {
+                       if isResponseSuccess(response.StatusCode) {
+                               return nil
+                       } else {
+                               return getResponseError(response)
+                       }
+               } else {
+                       return respErr
+               }
+       } else {
+               return reqErr
+       }
+}
+
+func isResponseSuccess(statusCode int) bool {
+       return statusCode >= http.StatusOK && statusCode <= 299
+}
+
+func getResponseError(response *http.Response) RequestError {
+       defer response.Body.Close()
+       responseData, _ := io.ReadAll(response.Body)
+       putError := RequestError{
+               StatusCode: response.StatusCode,
+               Body:       responseData,
+       }
+       return putError
+}
diff --git a/goversion/internal/restclient/client_test.go b/goversion/internal/restclient/client_test.go
new file mode 100644 (file)
index 0000000..2c915fd
--- /dev/null
@@ -0,0 +1,234 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package restclient
+
+import (
+       "bytes"
+       "crypto/tls"
+       "fmt"
+       "io/ioutil"
+       "math"
+       "net/http"
+       "reflect"
+       "testing"
+       "time"
+
+       "github.com/hashicorp/go-retryablehttp"
+       "github.com/stretchr/testify/mock"
+       "github.com/stretchr/testify/require"
+       "oransc.org/usecase/oruclosedloop/mocks"
+)
+
+func TestRequestError_Error(t *testing.T) {
+       assertions := require.New(t)
+
+       actualError := RequestError{
+               StatusCode: http.StatusBadRequest,
+               Body:       []byte("error"),
+       }
+       assertions.Equal("error response with status: 400 and body: error", actualError.Error())
+}
+
+func TestPutWithoutAuth(t *testing.T) {
+       assertions := require.New(t)
+
+       clientMock := mocks.HTTPClient{}
+       clientMock.On("Do", mock.Anything).Return(&http.Response{
+               StatusCode: http.StatusOK,
+       }, nil)
+
+       error := PutWithoutAuth("url", []byte("body"), &clientMock)
+
+       assertions.Nil(error)
+       var actualRequest *http.Request
+       clientMock.AssertCalled(t, "Do", mock.MatchedBy(func(req *http.Request) bool {
+               actualRequest = req
+               return true
+       }))
+       assertions.Equal(http.MethodPut, actualRequest.Method)
+       assertions.Equal("url", actualRequest.URL.Path)
+       assertions.Equal("application/json; charset=utf-8", actualRequest.Header.Get("Content-Type"))
+       assertions.Empty(actualRequest.Header.Get("Authorization"))
+       body, _ := ioutil.ReadAll(actualRequest.Body)
+       expectedBody := []byte("body")
+       assertions.Equal(expectedBody, body)
+       clientMock.AssertNumberOfCalls(t, "Do", 1)
+}
+
+func TestPut(t *testing.T) {
+       assertions := require.New(t)
+
+       clientMock := mocks.HTTPClient{}
+       clientMock.On("Do", mock.Anything).Return(&http.Response{
+               StatusCode: http.StatusOK,
+       }, nil)
+
+       error := Put("url", "body", &clientMock, "admin", "pwd")
+
+       assertions.Nil(error)
+       var actualRequest *http.Request
+       clientMock.AssertCalled(t, "Do", mock.MatchedBy(func(req *http.Request) bool {
+               actualRequest = req
+               return true
+       }))
+       assertions.Equal(http.MethodPut, actualRequest.Method)
+       assertions.Equal("url", actualRequest.URL.Path)
+       assertions.Equal("application/json; charset=utf-8", actualRequest.Header.Get("Content-Type"))
+       tempRequest, _ := http.NewRequest("", "", nil)
+       tempRequest.SetBasicAuth("admin", "pwd")
+       assertions.Equal(tempRequest.Header.Get("Authorization"), actualRequest.Header.Get("Authorization"))
+       body, _ := ioutil.ReadAll(actualRequest.Body)
+       expectedBody := []byte("body")
+       assertions.Equal(expectedBody, body)
+       clientMock.AssertNumberOfCalls(t, "Do", 1)
+}
+
+func TestDelete(t *testing.T) {
+       assertions := require.New(t)
+
+       clientMock := mocks.HTTPClient{}
+       clientMock.On("Do", mock.Anything).Return(&http.Response{
+               StatusCode: http.StatusOK,
+       }, nil)
+
+       error := Delete("url", &clientMock)
+
+       assertions.Nil(error)
+       var actualRequest *http.Request
+       clientMock.AssertCalled(t, "Do", mock.MatchedBy(func(req *http.Request) bool {
+               actualRequest = req
+               return true
+       }))
+       assertions.Equal(http.MethodDelete, actualRequest.Method)
+       assertions.Equal("url", actualRequest.URL.Path)
+       assertions.Empty(actualRequest.Header.Get("Content-Type"))
+       assertions.Empty(actualRequest.Header.Get("Authorization"))
+       assertions.Equal(http.NoBody, actualRequest.Body)
+       clientMock.AssertNumberOfCalls(t, "Do", 1)
+}
+
+func Test_doErrorCases(t *testing.T) {
+       assertions := require.New(t)
+
+       type args struct {
+               url              string
+               mockReturnStatus int
+               mockReturnBody   []byte
+               mockReturnError  error
+       }
+       tests := []struct {
+               name    string
+               args    args
+               wantErr error
+       }{
+               {
+                       name: "Bad request should get RequestError",
+                       args: args{
+                               url:              "badRequest",
+                               mockReturnStatus: http.StatusBadRequest,
+                               mockReturnBody:   []byte("bad request"),
+                       },
+                       wantErr: RequestError{
+                               StatusCode: http.StatusBadRequest,
+                               Body:       []byte("bad request"),
+                       },
+               },
+               {
+                       name: "Server unavailable should get error",
+                       args: args{
+                               url:             "serverUnavailable",
+                               mockReturnError: fmt.Errorf("Server unavailable"),
+                       },
+                       wantErr: fmt.Errorf("Server unavailable"),
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       clientMock := mocks.HTTPClient{}
+                       clientMock.On("Do", mock.Anything).Return(&http.Response{
+                               StatusCode: tt.args.mockReturnStatus,
+                               Body:       ioutil.NopCloser(bytes.NewReader(tt.args.mockReturnBody)),
+                       }, tt.args.mockReturnError)
+
+                       err := do("PUT", tt.args.url, nil, &clientMock)
+                       assertions.Equal(tt.wantErr, err, tt.name)
+               })
+       }
+}
+
+func Test_createClientCertificate(t *testing.T) {
+       assertions := require.New(t)
+       wantedCert, _ := tls.LoadX509KeyPair("../../security/consumer.crt", "../../security/consumer.key")
+       type args struct {
+               certPath string
+               keyPath  string
+       }
+       tests := []struct {
+               name     string
+               args     args
+               wantCert tls.Certificate
+               wantErr  error
+       }{
+               {
+                       name: "Paths to cert info ok should return cerftificate",
+                       args: args{
+                               certPath: "../../security/consumer.crt",
+                               keyPath:  "../../security/consumer.key",
+                       },
+                       wantCert: wantedCert,
+               },
+               {
+                       name: "Paths to cert info not ok should return error with info about error",
+                       args: args{
+                               certPath: "wrong_cert",
+                               keyPath:  "wrong_key",
+                       },
+                       wantErr: fmt.Errorf("cannot create x509 keypair from cert file wrong_cert and key file wrong_key due to: open wrong_cert: no such file or directory"),
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       cert, err := CreateClientCertificate(tt.args.certPath, tt.args.keyPath)
+                       assertions.Equal(tt.wantCert, cert, tt.name)
+                       assertions.Equal(tt.wantErr, err, tt.name)
+               })
+       }
+}
+
+func Test_CreateRetryClient(t *testing.T) {
+       assertions := require.New(t)
+
+       client := CreateRetryClient(tls.Certificate{})
+
+       transport := client.Transport
+       assertions.Equal("*retryablehttp.RoundTripper", reflect.TypeOf(transport).String())
+       retryableTransport := transport.(*retryablehttp.RoundTripper)
+       retryableClient := retryableTransport.Client
+       assertions.Equal(time.Minute, retryableClient.RetryWaitMax)
+       assertions.Equal(math.MaxInt, retryableClient.RetryMax)
+}
+
+func TestIsUrlSecured(t *testing.T) {
+       assertions := require.New(t)
+
+       assertions.True(IsUrlSecure("https://url"))
+
+       assertions.False(IsUrlSecure("http://url"))
+}
diff --git a/goversion/internal/ves/decoder.go b/goversion/internal/ves/decoder.go
new file mode 100644 (file)
index 0000000..dca970c
--- /dev/null
@@ -0,0 +1,59 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package ves
+
+import (
+       "encoding/json"
+       "io"
+       "io/ioutil"
+
+       log "github.com/sirupsen/logrus"
+)
+
+func GetFaultMessages(messageStrings *[]string) *[]FaultMessage {
+       faultMessages := make([]FaultMessage, 0, len(*messageStrings))
+       for _, msgString := range *messageStrings {
+               var message FaultMessage
+               if err := json.Unmarshal([]byte(msgString), &message); err == nil {
+                       if message.isFault() {
+                               faultMessages = append(faultMessages, message)
+                       }
+               } else {
+                       log.Warn(err)
+               }
+       }
+       return &faultMessages
+}
+
+func GetVesMessages(r io.ReadCloser) *[]string {
+       var messages []string
+       body, err := ioutil.ReadAll(r)
+       if err != nil {
+               log.Warn(err)
+               return nil
+       }
+       err = json.Unmarshal(body, &messages)
+       if err != nil {
+               log.Warn(err)
+               return nil
+       }
+       return &messages
+}
diff --git a/goversion/internal/ves/decoder_test.go b/goversion/internal/ves/decoder_test.go
new file mode 100644 (file)
index 0000000..98bc719
--- /dev/null
@@ -0,0 +1,64 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package ves
+
+import (
+       "reflect"
+       "testing"
+)
+
+func TestGetFaultMessages(t *testing.T) {
+       type args struct {
+               messageStrings *[]string
+       }
+       tests := []struct {
+               name string
+               args args
+               want *[]FaultMessage
+       }{
+               {
+                       name: "",
+                       args: args{
+                               messageStrings: &[]string{"{\"event\":{\"commonEventHeader\":{\"domain\":\"heartbeat\"}}}",
+                                       `{"event":{"commonEventHeader":{"domain":"fault","sourceName":"ERICSSON-O-RU-11220"},"faultFields":{"eventSeverity":"CRITICAL","alarmCondition":"28"}}}`},
+                       },
+                       want: &[]FaultMessage{{
+                               Event: Event{
+                                       CommonEventHeader: CommonEventHeader{
+                                               Domain:     "fault",
+                                               SourceName: "ERICSSON-O-RU-11220",
+                                       },
+                                       FaultFields: FaultFields{
+                                               AlarmCondition: "28",
+                                               EventSeverity:  "CRITICAL",
+                                       },
+                               },
+                       }},
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       if got := GetFaultMessages(tt.args.messageStrings); !reflect.DeepEqual(got, tt.want) {
+                               t.Errorf("GetFaultMessages() = %v, want %v", got, tt.want)
+                       }
+               })
+       }
+}
diff --git a/goversion/internal/ves/message.go b/goversion/internal/ves/message.go
new file mode 100644 (file)
index 0000000..ca8a3ca
--- /dev/null
@@ -0,0 +1,64 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package ves
+
+type FaultMessage struct {
+       Event Event `json:"event"`
+}
+
+type Event struct {
+       CommonEventHeader CommonEventHeader `json:"commonEventHeader"`
+       FaultFields       FaultFields       `json:"faultFields"`
+}
+
+type CommonEventHeader struct {
+       Domain     string `json:"domain"`
+       SourceName string `json:"sourceName"`
+}
+
+type FaultFields struct {
+       AlarmCondition string `json:"alarmCondition"`
+       EventSeverity  string `json:"eventSeverity"`
+}
+
+func (message FaultMessage) isFault() bool {
+       return message.Event.CommonEventHeader.Domain == "fault"
+}
+
+func (message FaultMessage) isLinkAlarm() bool {
+       return message.Event.FaultFields.AlarmCondition == "28"
+}
+
+func (message FaultMessage) isSeverityNormal() bool {
+       return message.Event.FaultFields.EventSeverity == "NORMAL"
+}
+
+func (message FaultMessage) IsLinkFailure() bool {
+       return message.isFault() && message.isLinkAlarm() && !message.isSeverityNormal()
+}
+
+func (message FaultMessage) IsClearLinkFailure() bool {
+       return message.isFault() && message.isLinkAlarm() && message.isSeverityNormal()
+}
+
+func (message FaultMessage) GetORuId() string {
+       return message.Event.CommonEventHeader.SourceName
+}
diff --git a/goversion/internal/ves/message_test.go b/goversion/internal/ves/message_test.go
new file mode 100644 (file)
index 0000000..30c7b72
--- /dev/null
@@ -0,0 +1,262 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package ves
+
+import "testing"
+
+func TestMessage_isFault(t *testing.T) {
+       type fields struct {
+               Event Event
+       }
+       tests := []struct {
+               name   string
+               fields fields
+               want   bool
+       }{
+               {
+                       name: "is Fault",
+                       fields: fields{
+                               Event: Event{
+                                       CommonEventHeader: CommonEventHeader{
+                                               Domain: "fault",
+                                       },
+                               },
+                       },
+                       want: true,
+               },
+               {
+                       name: "is not Fault",
+                       fields: fields{
+                               Event: Event{},
+                       },
+                       want: false,
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       message := FaultMessage{
+                               Event: tt.fields.Event,
+                       }
+                       if got := message.isFault(); got != tt.want {
+                               t.Errorf("Message.isFault() = %v, want %v", got, tt.want)
+                       }
+               })
+       }
+}
+
+func TestMessage_isLinkAlarm(t *testing.T) {
+       type fields struct {
+               Event Event
+       }
+       tests := []struct {
+               name   string
+               fields fields
+               want   bool
+       }{
+               {
+                       name: "is Link alarm",
+                       fields: fields{
+                               Event: Event{
+                                       FaultFields: FaultFields{
+                                               AlarmCondition: "28",
+                                       },
+                               },
+                       },
+                       want: true,
+               },
+               {
+                       name: "is not Link alarm",
+                       fields: fields{
+                               Event: Event{
+                                       FaultFields: FaultFields{
+                                               AlarmCondition: "2",
+                                       },
+                               },
+                       },
+                       want: false,
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       message := FaultMessage{
+                               Event: tt.fields.Event,
+                       }
+                       if got := message.isLinkAlarm(); got != tt.want {
+                               t.Errorf("Message.isLinkAlarm() = %v, want %v", got, tt.want)
+                       }
+               })
+       }
+}
+
+func TestMessage_isSeverityNormal(t *testing.T) {
+       type fields struct {
+               Event Event
+       }
+       tests := []struct {
+               name   string
+               fields fields
+               want   bool
+       }{
+               {
+                       name: "is severity NORMAL",
+                       fields: fields{
+                               Event: Event{
+                                       FaultFields: FaultFields{
+                                               EventSeverity: "NORMAL",
+                                       },
+                               },
+                       },
+                       want: true,
+               },
+               {
+                       name: "is not severity NORMAL",
+                       fields: fields{
+                               Event: Event{
+                                       FaultFields: FaultFields{
+                                               AlarmCondition: "ERROR",
+                                       },
+                               },
+                       },
+                       want: false,
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       message := FaultMessage{
+                               Event: tt.fields.Event,
+                       }
+                       if got := message.isSeverityNormal(); got != tt.want {
+                               t.Errorf("Message.isSeverityNormal() = %v, want %v", got, tt.want)
+                       }
+               })
+       }
+}
+
+func TestMessage_IsLinkFailure(t *testing.T) {
+       type fields struct {
+               Event Event
+       }
+       tests := []struct {
+               name   string
+               fields fields
+               want   bool
+       }{
+               {
+                       name: "is Link Failure",
+                       fields: fields{
+                               Event: Event{
+                                       CommonEventHeader: CommonEventHeader{
+                                               Domain: "fault",
+                                       },
+                                       FaultFields: FaultFields{
+                                               AlarmCondition: "28",
+                                               EventSeverity:  "ERROR",
+                                       },
+                               },
+                       },
+                       want: true,
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       message := FaultMessage{
+                               Event: tt.fields.Event,
+                       }
+                       if got := message.IsLinkFailure(); got != tt.want {
+                               t.Errorf("Message.IsLinkFailure() = %v, want %v", got, tt.want)
+                       }
+               })
+       }
+}
+
+func TestMessage_IsClearLinkFailure(t *testing.T) {
+       type fields struct {
+               Event Event
+       }
+       tests := []struct {
+               name   string
+               fields fields
+               want   bool
+       }{
+               {
+                       name: "is not Link Failure",
+                       fields: fields{
+                               Event: Event{
+                                       CommonEventHeader: CommonEventHeader{
+                                               Domain: "fault",
+                                       },
+                                       FaultFields: FaultFields{
+                                               AlarmCondition: "28",
+                                               EventSeverity:  "NORMAL",
+                                       },
+                               },
+                       },
+                       want: true,
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       message := FaultMessage{
+                               Event: tt.fields.Event,
+                       }
+                       if got := message.IsClearLinkFailure(); got != tt.want {
+                               t.Errorf("Message.IsClearLinkFailure() = %v, want %v", got, tt.want)
+                       }
+               })
+       }
+}
+
+func TestMessage_GetORuId(t *testing.T) {
+       type fields struct {
+               Event Event
+       }
+       tests := []struct {
+               name   string
+               fields fields
+               want   string
+       }{
+               {
+                       name: "is not Link Failure",
+                       fields: fields{
+                               Event: Event{
+                                       CommonEventHeader: CommonEventHeader{
+                                               SourceName: "O-RU-ID",
+                                       },
+                                       FaultFields: FaultFields{
+                                               AlarmCondition: "28",
+                                               EventSeverity:  "NORMAL",
+                                       },
+                               },
+                       },
+                       want: "O-RU-ID",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       message := FaultMessage{
+                               Event: tt.fields.Event,
+                       }
+                       if got := message.GetORuId(); got != tt.want {
+                               t.Errorf("Message.GetORuId() = %v, want %v", got, tt.want)
+                       }
+               })
+       }
+}
diff --git a/goversion/main.go b/goversion/main.go
new file mode 100644 (file)
index 0000000..9a1d45e
--- /dev/null
@@ -0,0 +1,203 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+       "crypto/tls"
+       "encoding/json"
+       "fmt"
+       "net/http"
+       "os"
+       "os/signal"
+       "syscall"
+
+       "github.com/gorilla/mux"
+       log "github.com/sirupsen/logrus"
+       "oransc.org/usecase/oruclosedloop/internal/config"
+       "oransc.org/usecase/oruclosedloop/internal/linkfailure"
+       "oransc.org/usecase/oruclosedloop/internal/repository"
+       "oransc.org/usecase/oruclosedloop/internal/restclient"
+)
+
+const jobId = "14e7bb84-a44d-44c1-90b7-6995a92ad43c"
+var job_definition interface{}
+
+var jobRegistrationInfo = struct {
+       InfoTypeID    string      `json:"info_type_id"`
+       JobResultURI  string      `json:"job_result_uri"`
+       JobOwner      string      `json:"job_owner"`
+       JobDefinition interface{} `json:"job_definition"`
+}{
+       InfoTypeID:    "STD_Fault_Messages",
+       JobResultURI:  "",
+       JobOwner:      "O-RU Closed Loop Usecase",
+       JobDefinition: job_definition,
+}
+
+var client restclient.HTTPClient
+var configuration *config.Config
+var linkfailureConfig linkfailure.Configuration
+var lookupService repository.LookupService
+var consumerPort string
+var started bool
+
+func init() {
+       doInit()
+}
+
+func doInit() {
+       configuration = config.New()
+
+       log.SetLevel(configuration.LogLevel)
+       log.Debug("Using configuration: ", configuration)
+
+       consumerPort = fmt.Sprint(configuration.ConsumerPort)
+       jobRegistrationInfo.JobResultURI = configuration.ConsumerHost + ":" + consumerPort
+
+       linkfailureConfig = linkfailure.Configuration{
+               SDNRAddress:  configuration.SDNRAddress,
+               SDNRUser:     configuration.SDNRUser,
+               SDNRPassword: configuration.SDNPassword,
+       }
+}
+
+func main() {
+       if err := validateConfiguration(configuration); err != nil {
+               log.Fatalf("Unable to start consumer due to configuration error: %v", err)
+       }
+
+       csvFileHelper := repository.NewCsvFileHelperImpl()
+       if initErr := initializeLookupService(csvFileHelper, configuration.ORUToODUMapFile); initErr != nil {
+               log.Fatalf("Unable to create LookupService due to inability to get O-RU-ID to O-DU-ID map. Cause: %v", initErr)
+       }
+
+       var cert tls.Certificate
+       if c, err := restclient.CreateClientCertificate(configuration.ConsumerCertPath, configuration.ConsumerKeyPath); err == nil {
+               cert = c
+       } else {
+               log.Fatalf("Stopping producer due to error: %v", err)
+       }
+       client = restclient.CreateRetryClient(cert)
+
+       go func() {
+               startServer()
+               os.Exit(1) // If the startServer function exits, it is because there has been a failure in the server, so we exit.
+       }()
+
+       go func() {
+               deleteOnShutdown(make(chan os.Signal, 1))
+               os.Exit(0)
+       }()
+
+       keepConsumerAlive()
+}
+
+func validateConfiguration(configuration *config.Config) error {
+       if configuration.ConsumerHost == "" || configuration.ConsumerPort == 0 {
+               return fmt.Errorf("consumer host and port must be provided")
+       }
+
+       if configuration.ConsumerCertPath == "" || configuration.ConsumerKeyPath == "" {
+               return fmt.Errorf("missing CONSUMER_CERT and/or CONSUMER_KEY")
+       }
+
+       return nil
+}
+
+func initializeLookupService(csvFileHelper repository.CsvFileHelper, csvFile string) error {
+       lookupService = repository.NewLookupServiceImpl(csvFileHelper, csvFile)
+       return lookupService.Init()
+}
+
+func getRouter() *mux.Router {
+       messageHandler := linkfailure.NewLinkFailureHandler(lookupService, linkfailureConfig, client)
+
+       r := mux.NewRouter()
+       r.HandleFunc("/", messageHandler.MessagesHandler).Methods(http.MethodPost).Name("messageHandler")
+       r.HandleFunc("/status", statusHandler).Methods(http.MethodGet).Name("status")
+       r.HandleFunc("/admin/start", startHandler).Methods(http.MethodPost).Name("start")
+       r.HandleFunc("/admin/stop", stopHandler).Methods(http.MethodPost).Name("stop")
+
+       return r
+}
+
+func startServer() {
+       var err error
+       if restclient.IsUrlSecure(configuration.ConsumerHost) {
+               err = http.ListenAndServeTLS(fmt.Sprintf(":%v", configuration.ConsumerPort), configuration.ConsumerCertPath, configuration.ConsumerKeyPath, getRouter())
+       } else {
+               err = http.ListenAndServe(fmt.Sprintf(":%v", configuration.ConsumerPort), getRouter())
+       }
+       if err != nil {
+               log.Errorf("Server stopped unintentionally due to: %v. Deleteing job.", err)
+               if deleteErr := deleteJob(); deleteErr != nil {
+                       log.Errorf("Unable to delete consumer job due to: %v. Please remove job %v manually.", deleteErr, jobId)
+               }
+       }
+}
+
+func keepConsumerAlive() {
+       forever := make(chan int)
+       <-forever
+}
+
+func startHandler(w http.ResponseWriter, r *http.Request) {
+       body, _ := json.Marshal(jobRegistrationInfo)
+       putErr := restclient.PutWithoutAuth(configuration.InfoCoordinatorAddress+"/data-consumer/v1/info-jobs/"+jobId, body, client)
+       if putErr != nil {
+               http.Error(w, fmt.Sprintf("Unable to register consumer job due to: %v.", putErr), http.StatusBadRequest)
+               return
+       }
+       log.Debug("Registered job.")
+       started = true
+}
+
+func stopHandler(w http.ResponseWriter, r *http.Request) {
+       deleteErr := deleteJob()
+       if deleteErr != nil {
+               http.Error(w, fmt.Sprintf("Unable to delete consumer job due to: %v. Please remove job %v manually.", deleteErr, jobId), http.StatusBadRequest)
+               return
+       }
+       log.Debug("Deleted job.")
+       started = false
+}
+
+func statusHandler(w http.ResponseWriter, r *http.Request) {
+       runStatus := "started"
+       if !started {
+               runStatus = "stopped"
+       }
+       fmt.Fprintf(w, `{"status": "%v"}`, runStatus)
+}
+
+func deleteOnShutdown(s chan os.Signal) {
+       signal.Notify(s, os.Interrupt)
+       signal.Notify(s, syscall.SIGTERM)
+       <-s
+       log.Info("Shutting down gracefully.")
+       if err := deleteJob(); err != nil {
+               log.Errorf("Unable to delete job on shutdown due to: %v. Please remove job %v manually.", err, jobId)
+       }
+}
+
+func deleteJob() error {
+       return restclient.Delete(configuration.InfoCoordinatorAddress+"/data-consumer/v1/info-jobs/"+jobId, client)
+}
diff --git a/goversion/main_test.go b/goversion/main_test.go
new file mode 100644 (file)
index 0000000..6da0d95
--- /dev/null
@@ -0,0 +1,450 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+       "bytes"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "io/ioutil"
+       "net/http"
+       "net/http/httptest"
+       "os"
+       "sync"
+       "syscall"
+       "testing"
+       "time"
+
+       log "github.com/sirupsen/logrus"
+       "github.com/stretchr/testify/mock"
+       "github.com/stretchr/testify/require"
+       "oransc.org/usecase/oruclosedloop/internal/config"
+       "oransc.org/usecase/oruclosedloop/internal/linkfailure"
+       "oransc.org/usecase/oruclosedloop/mocks"
+)
+
+func Test_init(t *testing.T) {
+       assertions := require.New(t)
+
+       os.Setenv("CONSUMER_HOST", "consumerHost")
+       os.Setenv("CONSUMER_PORT", "8095")
+       t.Cleanup(func() {
+               os.Clearenv()
+       })
+
+       doInit()
+
+       wantedConfiguration := &config.Config{
+               ConsumerHost:           "consumerHost",
+               ConsumerPort:           8095,
+               InfoCoordinatorAddress: "http://enrichmentservice:8083",
+               SDNRAddress:            "http://localhost:3904",
+               SDNRUser:               "admin",
+               SDNPassword:            "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U",
+               ORUToODUMapFile:        "o-ru-to-o-du-map.csv",
+               ConsumerCertPath:       "security/consumer.crt",
+               ConsumerKeyPath:        "security/consumer.key",
+               LogLevel:               log.InfoLevel,
+       }
+       assertions.Equal(wantedConfiguration, configuration)
+
+       assertions.Equal(fmt.Sprint(wantedConfiguration.ConsumerPort), consumerPort)
+       assertions.Equal(wantedConfiguration.ConsumerHost+":"+fmt.Sprint(wantedConfiguration.ConsumerPort), jobRegistrationInfo.JobResultURI)
+
+       wantedLinkFailureConfig := linkfailure.Configuration{
+               SDNRAddress:  wantedConfiguration.SDNRAddress,
+               SDNRUser:     wantedConfiguration.SDNRUser,
+               SDNRPassword: wantedConfiguration.SDNPassword,
+       }
+       assertions.Equal(wantedLinkFailureConfig, linkfailureConfig)
+}
+
+func Test_validateConfiguration(t *testing.T) {
+       assertions := require.New(t)
+
+       type args struct {
+               configuration *config.Config
+       }
+       tests := []struct {
+               name    string
+               args    args
+               wantErr error
+       }{
+               {
+                       name: "Valid config, should return nil",
+                       args: args{
+                               configuration: &config.Config{
+                                       ConsumerHost:     "host",
+                                       ConsumerPort:     80,
+                                       ConsumerCertPath: "security/consumer.crt",
+                                       ConsumerKeyPath:  "security/consumer.key",
+                               },
+                       },
+               },
+               {
+                       name: "Invalid config, should return error",
+                       args: args{
+                               configuration: &config.Config{},
+                       },
+                       wantErr: fmt.Errorf("consumer host and port must be provided"),
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       err := validateConfiguration(tt.args.configuration)
+                       assertions.Equal(tt.wantErr, err)
+               })
+       }
+}
+
+func Test_initializeLookupService(t *testing.T) {
+       assertions := require.New(t)
+       type args struct {
+               csvFile         string
+               oRuId           string
+               mockReturn      [][]string
+               mockReturnError error
+       }
+       tests := []struct {
+               name        string
+               args        args
+               wantODuId   string
+               wantInitErr error
+       }{
+               {
+                       name: "Successful initialization, should return nil and lookup service should be initiated with data",
+                       args: args{
+                               csvFile:    "file",
+                               oRuId:      "1",
+                               mockReturn: [][]string{{"1", "2"}},
+                       },
+                       wantODuId: "2",
+               },
+               {
+                       name: "Unsuccessful initialization, should return error and lookup service should not be initiated with data",
+                       args: args{
+                               csvFile:         "file",
+                               mockReturnError: errors.New("Error"),
+                       },
+                       wantInitErr: errors.New("Error"),
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       mockCsvFileHelper := &mocks.CsvFileHelper{}
+                       mockCsvFileHelper.On("GetCsvFromFile", mock.Anything).Return(tt.args.mockReturn, tt.args.mockReturnError)
+
+                       err := initializeLookupService(mockCsvFileHelper, tt.args.csvFile)
+                       oDuId, _ := lookupService.GetODuID(tt.args.oRuId)
+                       assertions.Equal(tt.wantODuId, oDuId)
+                       assertions.Equal(tt.wantInitErr, err)
+                       mockCsvFileHelper.AssertCalled(t, "GetCsvFromFile", tt.args.csvFile)
+               })
+       }
+}
+
+func Test_getRouter_shouldContainAllPathsWithHandlers(t *testing.T) {
+       assertions := require.New(t)
+
+       r := getRouter()
+       messageHandlerRoute := r.Get("messageHandler")
+       assertions.NotNil(messageHandlerRoute)
+       supportedMethods, err := messageHandlerRoute.GetMethods()
+       assertions.Equal([]string{http.MethodPost}, supportedMethods)
+       assertions.Nil(err)
+       path, _ := messageHandlerRoute.GetPathTemplate()
+       assertions.Equal("/", path)
+
+       startHandlerRoute := r.Get("start")
+       assertions.NotNil(messageHandlerRoute)
+       supportedMethods, err = startHandlerRoute.GetMethods()
+       assertions.Equal([]string{http.MethodPost}, supportedMethods)
+       assertions.Nil(err)
+       path, _ = startHandlerRoute.GetPathTemplate()
+       assertions.Equal("/admin/start", path)
+
+       stopHandlerRoute := r.Get("stop")
+       assertions.NotNil(stopHandlerRoute)
+       supportedMethods, err = stopHandlerRoute.GetMethods()
+       assertions.Equal([]string{http.MethodPost}, supportedMethods)
+       assertions.Nil(err)
+       path, _ = stopHandlerRoute.GetPathTemplate()
+       assertions.Equal("/admin/stop", path)
+
+       statusHandlerRoute := r.Get("status")
+       assertions.NotNil(statusHandlerRoute)
+       supportedMethods, err = statusHandlerRoute.GetMethods()
+       assertions.Equal([]string{http.MethodGet}, supportedMethods)
+       assertions.Nil(err)
+       path, _ = statusHandlerRoute.GetPathTemplate()
+       assertions.Equal("/status", path)
+}
+
+func Test_startHandler(t *testing.T) {
+       assertions := require.New(t)
+
+       jobRegistrationInfo.JobResultURI = "host:80"
+       var job_definition interface{}
+
+       type args struct {
+               mockReturnBody   []byte
+               mockReturnStatus int
+       }
+       tests := []struct {
+               name         string
+               args         args
+               wantedStatus int
+               wantedBody   string
+       }{
+               {
+                       name: "Start with successful registration, should return ok",
+                       args: args{
+                               mockReturnBody:   []byte(""),
+                               mockReturnStatus: http.StatusOK,
+                       },
+                       wantedStatus: http.StatusOK,
+               },
+               {
+                       name: "Start with error response at registration, should return error",
+                       args: args{
+                               mockReturnBody:   []byte("error"),
+                               mockReturnStatus: http.StatusBadRequest,
+                       },
+                       wantedStatus: http.StatusBadRequest,
+                       wantedBody:   "Unable to register consumer job due to:",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       clientMock := setUpClientMock(tt.args.mockReturnBody, tt.args.mockReturnStatus)
+
+                       handler := http.HandlerFunc(startHandler)
+                       responseRecorder := httptest.NewRecorder()
+                       r, _ := http.NewRequest(http.MethodPost, "/start", nil)
+
+                       handler.ServeHTTP(responseRecorder, r)
+
+                       assertions.Equal(tt.wantedStatus, responseRecorder.Code, tt.name)
+                       assertions.Contains(responseRecorder.Body.String(), tt.wantedBody, tt.name)
+
+                       var wantedJobRegistrationInfo = struct {
+                               InfoTypeId    string      `json:"info_type_id"`
+                               JobResultUri  string      `json:"job_result_uri"`
+                               JobOwner      string      `json:"job_owner"`
+                               JobDefinition interface{} `json:"job_definition"`
+                       }{
+                               InfoTypeId:    "STD_Fault_Messages",
+                               JobResultUri:  "host:80",
+                               JobOwner:      "O-RU Closed Loop Usecase",
+                               JobDefinition: job_definition,
+                       }
+                       wantedBody, _ := json.Marshal(wantedJobRegistrationInfo)
+
+                       var actualRequest *http.Request
+                       clientMock.AssertCalled(t, "Do", mock.MatchedBy(func(req *http.Request) bool {
+                               actualRequest = req
+                               return true
+                       }))
+                       assertions.Equal(http.MethodPut, actualRequest.Method)
+                       assertions.Equal("http", actualRequest.URL.Scheme)
+                       assertions.Equal("enrichmentservice:8083", actualRequest.URL.Host)
+                       assertions.Equal("/data-consumer/v1/info-jobs/14e7bb84-a44d-44c1-90b7-6995a92ad43c", actualRequest.URL.Path)
+                       assertions.Equal("application/json; charset=utf-8", actualRequest.Header.Get("Content-Type"))
+                       body, _ := ioutil.ReadAll(actualRequest.Body)
+                       expectedBody := wantedBody
+                       assertions.Equal(expectedBody, body)
+                       clientMock.AssertNumberOfCalls(t, "Do", 1)
+
+                       // Check that the running status is "started"
+                       statusHandler := http.HandlerFunc(statusHandler)
+                       statusResponseRecorder := httptest.NewRecorder()
+                       statusRequest, _ := http.NewRequest(http.MethodGet, "/status", nil)
+
+                       statusHandler.ServeHTTP(statusResponseRecorder, statusRequest)
+
+                       assertions.Equal(http.StatusOK, statusResponseRecorder.Code)
+                       assertions.Equal(`{"status": "started"}`, statusResponseRecorder.Body.String())
+               })
+       }
+}
+
+func Test_stopHandler(t *testing.T) {
+       assertions := require.New(t)
+
+       jobRegistrationInfo.JobResultURI = "host:80"
+
+       type args struct {
+               mockReturnBody   []byte
+               mockReturnStatus int
+       }
+       tests := []struct {
+               name         string
+               args         args
+               wantedStatus int
+               wantedBody   string
+       }{
+               {
+                       name: "Stop with successful job deletion, should return ok",
+                       args: args{
+                               mockReturnBody:   []byte(""),
+                               mockReturnStatus: http.StatusOK,
+                       },
+                       wantedStatus: http.StatusOK,
+               },
+               {
+                       name: "Stop with error response at job deletion, should return error",
+                       args: args{
+                               mockReturnBody:   []byte("error"),
+                               mockReturnStatus: http.StatusBadRequest,
+                       },
+                       wantedStatus: http.StatusBadRequest,
+                       wantedBody:   "Please remove job 14e7bb84-a44d-44c1-90b7-6995a92ad43c manually",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       clientMock := setUpClientMock(tt.args.mockReturnBody, tt.args.mockReturnStatus)
+
+                       handler := http.HandlerFunc(stopHandler)
+                       responseRecorder := httptest.NewRecorder()
+                       r, _ := http.NewRequest(http.MethodPost, "/stop", nil)
+
+                       handler.ServeHTTP(responseRecorder, r)
+
+                       assertions.Equal(tt.wantedStatus, responseRecorder.Code, tt.name)
+                       assertions.Contains(responseRecorder.Body.String(), tt.wantedBody, tt.name)
+
+                       var actualRequest *http.Request
+                       clientMock.AssertCalled(t, "Do", mock.MatchedBy(func(req *http.Request) bool {
+                               actualRequest = req
+                               return true
+                       }))
+                       assertions.Equal(http.MethodDelete, actualRequest.Method)
+                       assertions.Equal("http", actualRequest.URL.Scheme)
+                       assertions.Equal("enrichmentservice:8083", actualRequest.URL.Host)
+                       assertions.Equal("/data-consumer/v1/info-jobs/14e7bb84-a44d-44c1-90b7-6995a92ad43c", actualRequest.URL.Path)
+                       clientMock.AssertNumberOfCalls(t, "Do", 1)
+
+                       // Check that the running status is "stopped"
+                       statusHandler := http.HandlerFunc(statusHandler)
+                       statusResponseRecorder := httptest.NewRecorder()
+                       statusRequest, _ := http.NewRequest(http.MethodGet, "/status", nil)
+
+                       statusHandler.ServeHTTP(statusResponseRecorder, statusRequest)
+
+                       assertions.Equal(http.StatusOK, statusResponseRecorder.Code)
+                       assertions.Equal(`{"status": "stopped"}`, statusResponseRecorder.Body.String())
+               })
+       }
+}
+
+func Test_deleteOnShutdown(t *testing.T) {
+       assertions := require.New(t)
+
+       var buf bytes.Buffer
+       log.SetOutput(&buf)
+
+       t.Cleanup(func() {
+               log.SetOutput(os.Stderr)
+       })
+
+       type args struct {
+               mockReturnBody   []byte
+               mockReturnStatus int
+       }
+       tests := []struct {
+               name      string
+               args      args
+               wantedLog string
+       }{
+               {
+                       name: "Delete with successful job deletion, should return ok",
+                       args: args{
+                               mockReturnBody:   []byte(""),
+                               mockReturnStatus: http.StatusOK,
+                       },
+               },
+               {
+                       name: "Stop with error response at job deletion, should return error",
+                       args: args{
+                               mockReturnBody:   []byte("error"),
+                               mockReturnStatus: http.StatusBadRequest,
+                       },
+                       wantedLog: "Please remove job 14e7bb84-a44d-44c1-90b7-6995a92ad43c manually",
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       setUpClientMock(tt.args.mockReturnBody, tt.args.mockReturnStatus)
+
+                       c := make(chan os.Signal, 1)
+                       go deleteOnShutdown(c)
+                       c <- syscall.SIGTERM
+
+                       waitForLogToBeWritten(&buf)
+
+                       log := buf.String()
+                       if tt.wantedLog != "" {
+                               assertions.Contains(log, "level=error")
+                               assertions.Contains(log, "Unable to delete job on shutdown due to:")
+                               assertions.Contains(log, tt.wantedLog)
+                       }
+               })
+       }
+}
+
+func waitForLogToBeWritten(logBuf *bytes.Buffer) {
+       wg := sync.WaitGroup{}
+       wg.Add(1)
+       for {
+               if waitTimeout(&wg, 10*time.Millisecond) && logBuf.Len() != 0 {
+                       wg.Done()
+                       break
+               }
+       }
+}
+
+// waitTimeout waits for the waitgroup for the specified max timeout.
+// Returns true if waiting timed out.
+func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
+       c := make(chan struct{})
+       go func() {
+               defer close(c)
+               wg.Wait()
+       }()
+       select {
+       case <-c:
+               return false // completed normally
+       case <-time.After(timeout):
+               return true // timed out
+       }
+}
+
+func setUpClientMock(body []byte, status int) *mocks.HTTPClient {
+       clientMock := mocks.HTTPClient{}
+       clientMock.On("Do", mock.Anything).Return(&http.Response{
+               Body:       ioutil.NopCloser(bytes.NewReader(body)),
+               StatusCode: status,
+       }, nil)
+       client = &clientMock
+       return &clientMock
+}
diff --git a/goversion/mocks/CsvFileHelper.go b/goversion/mocks/CsvFileHelper.go
new file mode 100644 (file)
index 0000000..b857de5
--- /dev/null
@@ -0,0 +1,33 @@
+// Code generated by mockery v1.0.0. DO NOT EDIT.
+
+package mocks
+
+import mock "github.com/stretchr/testify/mock"
+
+// CsvFileHelper is an autogenerated mock type for the CsvFileHelper type
+type CsvFileHelper struct {
+       mock.Mock
+}
+
+// GetCsvFromFile provides a mock function with given fields: name
+func (_m *CsvFileHelper) GetCsvFromFile(name string) ([][]string, error) {
+       ret := _m.Called(name)
+
+       var r0 [][]string
+       if rf, ok := ret.Get(0).(func(string) [][]string); ok {
+               r0 = rf(name)
+       } else {
+               if ret.Get(0) != nil {
+                       r0 = ret.Get(0).([][]string)
+               }
+       }
+
+       var r1 error
+       if rf, ok := ret.Get(1).(func(string) error); ok {
+               r1 = rf(name)
+       } else {
+               r1 = ret.Error(1)
+       }
+
+       return r0, r1
+}
diff --git a/goversion/mocks/HTTPClient.go b/goversion/mocks/HTTPClient.go
new file mode 100644 (file)
index 0000000..3037798
--- /dev/null
@@ -0,0 +1,60 @@
+// Code generated by mockery v1.0.0. DO NOT EDIT.
+
+package mocks
+
+import (
+       http "net/http"
+
+       mock "github.com/stretchr/testify/mock"
+)
+
+// HTTPClient is an autogenerated mock type for the HTTPClient type
+type HTTPClient struct {
+       mock.Mock
+}
+
+// Do provides a mock function with given fields: _a0
+func (_m *HTTPClient) Do(_a0 *http.Request) (*http.Response, error) {
+       ret := _m.Called(_a0)
+
+       var r0 *http.Response
+       if rf, ok := ret.Get(0).(func(*http.Request) *http.Response); ok {
+               r0 = rf(_a0)
+       } else {
+               if ret.Get(0) != nil {
+                       r0 = ret.Get(0).(*http.Response)
+               }
+       }
+
+       var r1 error
+       if rf, ok := ret.Get(1).(func(*http.Request) error); ok {
+               r1 = rf(_a0)
+       } else {
+               r1 = ret.Error(1)
+       }
+
+       return r0, r1
+}
+
+// Get provides a mock function with given fields: url
+func (_m *HTTPClient) Get(url string) (*http.Response, error) {
+       ret := _m.Called(url)
+
+       var r0 *http.Response
+       if rf, ok := ret.Get(0).(func(string) *http.Response); ok {
+               r0 = rf(url)
+       } else {
+               if ret.Get(0) != nil {
+                       r0 = ret.Get(0).(*http.Response)
+               }
+       }
+
+       var r1 error
+       if rf, ok := ret.Get(1).(func(string) error); ok {
+               r1 = rf(url)
+       } else {
+               r1 = ret.Error(1)
+       }
+
+       return r0, r1
+}
diff --git a/goversion/mocks/LookupService.go b/goversion/mocks/LookupService.go
new file mode 100644 (file)
index 0000000..2ba8369
--- /dev/null
@@ -0,0 +1,45 @@
+// Code generated by mockery v1.0.0. DO NOT EDIT.
+
+package mocks
+
+import mock "github.com/stretchr/testify/mock"
+
+// LookupService is an autogenerated mock type for the LookupService type
+type LookupService struct {
+       mock.Mock
+}
+
+// GetODuID provides a mock function with given fields: oRuId
+func (_m *LookupService) GetODuID(oRuId string) (string, error) {
+       ret := _m.Called(oRuId)
+
+       var r0 string
+       if rf, ok := ret.Get(0).(func(string) string); ok {
+               r0 = rf(oRuId)
+       } else {
+               r0 = ret.Get(0).(string)
+       }
+
+       var r1 error
+       if rf, ok := ret.Get(1).(func(string) error); ok {
+               r1 = rf(oRuId)
+       } else {
+               r1 = ret.Error(1)
+       }
+
+       return r0, r1
+}
+
+// Init provides a mock function with given fields:
+func (_m *LookupService) Init() error {
+       ret := _m.Called()
+
+       var r0 error
+       if rf, ok := ret.Get(0).(func() error); ok {
+               r0 = rf()
+       } else {
+               r0 = ret.Error(0)
+       }
+
+       return r0
+}
diff --git a/goversion/o-ru-to-o-du-map.csv b/goversion/o-ru-to-o-du-map.csv
new file mode 100644 (file)
index 0000000..2c5417d
--- /dev/null
@@ -0,0 +1,11 @@
+ERICSSON-O-RU-11220,O-DU-1122
+ERICSSON-O-RU-11221,O-DU-1122
+ERICSSON-O-RU-11222,O-DU-1122
+ERICSSON-O-RU-11223,O-DU-1122
+ERICSSON-O-RU-11223,O-DU-1122
+ERICSSON-O-RU-11224,O-DU-1123
+ERICSSON-O-RU-11225,O-DU-1123
+ERICSSON-O-RU-11226,O-DU-1123
+ERICSSON-O-RU-11227,O-DU-1124
+ERICSSON-O-RU-11228,O-DU-1125
+ERICSSON-O-RU-11229,O-DU-1125
\ No newline at end of file
diff --git a/goversion/security/consumer.crt b/goversion/security/consumer.crt
new file mode 100644 (file)
index 0000000..0f6d8a3
--- /dev/null
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgIUEbuDTP0ixwxCxCQ9tR5DijGCbtkwDQYJKoZIhvcNAQEL
+BQAwPzELMAkGA1UEBhMCc2UxDDAKBgNVBAoMA0VTVDERMA8GA1UECwwIRXJpY3Nz
+b24xDzANBgNVBAMMBnNlcnZlcjAeFw0yMTEwMTkxNDA1MzVaFw0zMTEwMTcxNDA1
+MzVaMD8xCzAJBgNVBAYTAnNlMQwwCgYDVQQKDANFU1QxETAPBgNVBAsMCEVyaWNz
+c29uMQ8wDQYDVQQDDAZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDnH4imV8kx/mXz6BDbq8e4oZGqGgv7V837iNspj/zIZXhEMP9311fdsZEE
+Y6VWU47bSYRn2xJOP+wmfKewbw0OcEWu/RkdvO7Y0VIVrlbEJYu88ZjK14dMUpfe
+72iMbTc5q2uYi0ImB5/m3jyMSXgso6NDWuvXrp2VSWjb1tG++des9rhvyrZyNrua
+I4iOnMvvuc71gvHol7appRu3+LRTQFYsAizdfHEQ9k949MZH4fiIu5NmCT/wNJVo
+uUZYYJseFhOlIANaXn6qmz7kKVYfxfV+Z5EccaRixaClCFwyRdmjgLyyeuI4/QPD
+x9PjmGmf6eOEC2ZHBi4OHwjIzmLnAgMBAAGjUzBRMB0GA1UdDgQWBBRjeDLPpLm2
+W623wna7xBCbHxtxVjAfBgNVHSMEGDAWgBRjeDLPpLm2W623wna7xBCbHxtxVjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAbFUAWFZaIMXmd5qv/
+xJYr1oPJpsmbgWGRWZWDZqbUabvWObyXlDJWIau60BerfcC5TmyElBjTyONSGwCT
+tq+SVB0PXpgqa8ZQ25Ytn2AMDFWhrGbOefCXs6te3HGq6BNubTWrOVIvJypCwC95
++iXVuDd4eg+n2fWv7h7fZRZHum/zLoRxB2lKoMMbc/BQX9hbtP6xyvIVvaYdhcJw
+VzJJGIDqpMiMH6IBaOFSmgfOyGblGKAicj3E3kpGBfadLx3R+9V6aG7zyBnVbr2w
+YJbV2Ay4PrF+PTpCMB/mNwC5RBTYHpSNdrCMSyq3I+QPVJq8dPJr7fd1Uwl3WHqX
+FV0h
+-----END CERTIFICATE-----
diff --git a/goversion/security/consumer.key b/goversion/security/consumer.key
new file mode 100644 (file)
index 0000000..5346bb7
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDnH4imV8kx/mXz
+6BDbq8e4oZGqGgv7V837iNspj/zIZXhEMP9311fdsZEEY6VWU47bSYRn2xJOP+wm
+fKewbw0OcEWu/RkdvO7Y0VIVrlbEJYu88ZjK14dMUpfe72iMbTc5q2uYi0ImB5/m
+3jyMSXgso6NDWuvXrp2VSWjb1tG++des9rhvyrZyNruaI4iOnMvvuc71gvHol7ap
+pRu3+LRTQFYsAizdfHEQ9k949MZH4fiIu5NmCT/wNJVouUZYYJseFhOlIANaXn6q
+mz7kKVYfxfV+Z5EccaRixaClCFwyRdmjgLyyeuI4/QPDx9PjmGmf6eOEC2ZHBi4O
+HwjIzmLnAgMBAAECggEBAMq1lZyPkh8PCUyLVX3VhC4jRybyAWBI+piKx+4EI6l/
+laP5dZcegCoo+w/mdbTpRHqAWGjec4e9+Nkoq8rLG6B2SCfaRJUYiEQSEvSBHAid
+BZqKK4B82GXQavNU91Vy1OT3vD7mpPXF6jEK6gAA0C4Wt7Lzo7ZfqEavRBDMsNnV
+jOxLwWJCFSKhfeA6grJCnagmEDKSxxazlNBgCahjPf/+IRJZ7Vk4Zjq+I/5nWKf8
+lYaQExKDIANuM/jMRnYVq5k4g2MKHUADWGTSvG1DMJiMHzdxb2miZovpIkEE86bC
+wKBuele9IR6Rb/wygYj7WdaWysZ081OT7mNyju08e4ECgYEA8+q7vv4Nlz8bAcmY
+Ip5517s15M5D9iLsE2Q5m9Zs99rUyQv0E8ekpChhtTSdvj+eNl39O4hji46Gyceu
+MYPfNL7+YWaFDxuyaXEe/OFuKbFqgE1p08HXFcQJCvgqD1MWO5b9BRDc0qpNFIA8
+eN9xFBMQ2UFaALBMAup7Ef85q4kCgYEA8pKOAIsgmlnO8P9cPzkMC1oozslraAti
+1JnOJjwPLoHFubtH2u7WoIkSvNfeNwfrsVXwAP0m7C8p7qhYppS+0XGjKpYNSezK
+1GCqCVv8R1m+AsSseSUUaQCmEydd+gQbBq3r4u3wU3ylrgAoR3m+7SVyhvD+vbwI
+7+zfj+O3zu8CgYEAqaAsQH5c5Tm1hmCztB+RjD1dFWl8ScevdSzWA1HzJcrA/6+Y
+ZckI7kBG8sVMjemgFR735FbNI1hS1DBRK44Rw5SvQv0Qu5j/UeShMCt1ePkwn1k2
+p1S+Rxy1TTOXzGBzra0q+ELpzncwc3lalJSPBu7bYLrZ5HC167E1NSbQ7EECgYBo
+e/IIj+TyNz7pFcVhQixK84HiWGYYQddHJhzi4TnU2XcWonG3/uqZ6ZEVoJIJ+DJw
+h0jC1EggscwJDaBp2GY9Bwq2PD3rGsDfK+fx8ho/jYtH2/lCkVMyS2I9m9Zh68TM
+YrvZWo4LGASxZ0XyS6GOunOTZlkD1uuulMRTUU4KJwKBgQCwyjs0/ElVFvO0lPIC
+JJ//B5rqI7hNMJuTBvr4yiqVZdbgFukaU7FBVyNYDMpZi/nRbpglm+psFcwXtL8n
+bHOIGLkh8vB7OuETRYhXs567lPYtO4BmHZlXW70Sq/0xqi/Mmz1RuEg4SQ1Ug5oy
+wG6IV5EWSQAhsGirdybQ+bY7Kw==
+-----END PRIVATE KEY-----
diff --git a/scriptversion/LICENSE.txt b/scriptversion/LICENSE.txt
new file mode 100644 (file)
index 0000000..e8798fc
--- /dev/null
@@ -0,0 +1,18 @@
+LICENSE.txt
+
+The content of this sub-directory is based on ONAP SDNC project,
+with appropriate licenses specified in the individual files.
+The modifications are covered by the following license:
+
+Unless otherwise specified, all software contained herein is licensed
+under the Apache License, Version 2.0 (the "Software License");
+you may not use this software except in compliance with the Software
+License. You may obtain a copy of the Software License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the Software License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the Software License for the specific language governing permissions
+and limitations under the Software License.
diff --git a/scriptversion/README.md b/scriptversion/README.md
new file mode 100644 (file)
index 0000000..6b59388
--- /dev/null
@@ -0,0 +1,84 @@
+# Use case Link Failure
+
+## General
+
+The Link Failure use case test provides a python script that regularly polls DMaaP Message Router (MR) for "CUS Link Failure"
+messages.
+
+When such a message appears with the "eventSeverity" set to anything but "NORMAL", a configuration change message with the
+"administrative-state" set to "UNLOCKED" will be sent to the O-DU mapped to the O-RU that sent the alarm.
+
+When such a message appears with the "eventSeverity" set to "NORMAL" a printout will be made to signal that the
+alarm has been cleared, provided that the verbose option has been used when the test was started.
+
+## Prerequisits
+
+To run this script Python3 needs to be installed. To install the script's dependencies, run the following command from
+the `app` folder: `pip install -r requirements.txt`
+
+Also, the MR needs to be up and running with a topic created for the alarms and there must be an endpoint for the
+configuration change event that will accept these.
+
+The host names and the ports to the MR and SDNR services can be provided when the container is started if the default
+values are not correct. The topic can also be changed.
+
+The mapping from O-RU ID to O-DU ID is specified in the file `o-ru-to-o-du-map.txt`. This can be replaced by providing
+a different file when starting the application.
+
+For convenience, a message generator and a change event endpoint simulator are provided.
+
+## How to run from command line
+
+Go to the `app/` folder and run `python3 main.py`. The script will start and run until stopped. Use the `-h` option to
+see the options available for the script.
+
+## How to run in Docker
+
+Go to the `app/` folder and run `docker build -t oru-app .`.
+
+The container must be connected to the same network as the MR and SDNR are running in. Some of the parameters to the application
+can be provided with the `-e PARAM_NAME=PARAM_VALUE` notation. Start the container by using the command, with available params listed:
+ `docker run --network [NETWORK NAME] --name oru-app -e VERBOSE=on -e MR-HOST=[HOST NAME OF MR] -e MR-PORT=[PORT OF MR] -e SDNR-HOST=[HOST NAME OF SDNR] -e SDNR-PORT=[PORT OF SDNR] oru-app`.
+
+To build the image for the message generator, run the following command from the `simulators` folder:
+`docker build -f Dockerfile-message-generator -t message-generator .`
+
+The message generator's container must be connected to the same network as the other components are running in. Some of the
+parameters to the application can be provided with the `-e PARAM_NAME=PARAM_VALUE` notation. Start the container by
+using the command, with available params listed:
+ `docker run --network [NETWORK NAME] --name message-generator -e MR-HOST=[HOST NAME OF MR] -e MR-PORT=[PORT OF MR] message-generator`.
+
+To build the image for the SDNR simulator, run the following command from the `simulators` folder:
+`docker build -f Dockerfile-sdnr-sim -t sdnr-simulator .`
+
+The SDNR simulator's container must be connected to the same network as the the other components are running in. Some of the
+parameters to the application can be provided with the `-e PARAM_NAME=PARAM_VALUE` notation. Start the container by
+using the command, with available params listed:
+ `docker run --network [NETWORK NAME] --name sdnr-simulator -e MR-HOST=[HOST NAME OF MR] -e MR-PORT=[PORT OF MR] sdnr-simulator`.
+
+## Use docker-compose
+
+Go to the `docker-compose/` folder and run `bash start.sh`.
+
+This scripts will start up four components:
+dmaap-mr
+oru-app
+sdnr-simulator
+message-generator
+
+## License
+
+Copyright (C) 2021 Nordix Foundation.
+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.
+
+For more information about license please see the [LICENSE](LICENSE.txt) file for details.
diff --git a/scriptversion/app/Dockerfile b/scriptversion/app/Dockerfile
new file mode 100644 (file)
index 0000000..21b24b1
--- /dev/null
@@ -0,0 +1,41 @@
+#  ============LICENSE_START===============================================
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+
+FROM python:3.8-slim-buster
+
+COPY . /usr/src/app/
+
+WORKDIR /usr/src/app
+
+## install curl & ping to help debug
+RUN apt update
+RUN apt install curl -y
+RUN apt-get install iputils-ping -y
+
+RUN pip install -r requirements.txt
+
+ARG user=nonrtric
+ARG group=nonrtric
+
+RUN groupadd $user && \
+    useradd -r -g $group $user
+RUN chown -R $user:$group /usr/src/app/
+
+USER ${user}
+
+CMD [ "python3", "-u", "main.py" ]
diff --git a/scriptversion/app/container-tag.yaml b/scriptversion/app/container-tag.yaml
new file mode 100644 (file)
index 0000000..230e590
--- /dev/null
@@ -0,0 +1,2 @@
+---
+tag: 1.0.0
diff --git a/scriptversion/app/main.py b/scriptversion/app/main.py
new file mode 100644 (file)
index 0000000..52f0ca8
--- /dev/null
@@ -0,0 +1,183 @@
+
+#  ============LICENSE_START===============================================
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+import argparse
+import ast
+import json
+import os
+import requests
+import time
+
+MR_PATH = "/events/[TOPIC]/users/test/"
+SDNR_PATH = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=[O-DU-ID]/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions=[O-DU-ID]/radio-resource-management-policy-ratio=rrm-pol-1"
+FAUILT_ID = "28"
+
+UNLOCK_MESSAGE = {
+    "o-ran-sc-du-hello-world:radio-resource-management-policy-ratio":
+    [
+        {
+            "id":"rrm-pol-1",
+            "radio-resource-management-policy-max-ratio":25,
+            "radio-resource-management-policy-members":
+                [
+                    {
+                        "mobile-country-code":"310",
+                        "mobile-network-code":"150",
+                        "slice-differentiator":1,
+                        "slice-service-type":1
+                    }
+                ],
+            "radio-resource-management-policy-min-ratio":15,
+            "user-label":"rrm-pol-1",
+            "resource-type":"prb",
+            "radio-resource-management-policy-dedicated-ratio":20,
+            "administrative-state":"unlocked"
+        }
+    ]
+}
+
+
+def is_message_new_link_failure(message):
+    msg_as_json = json.loads(message)
+    event_headers = msg_as_json["event"]["commonEventHeader"]
+
+    link_failure = False
+    if (event_headers["domain"] == "fault"):
+        fault_fields = msg_as_json["event"]["faultFields"]
+        link_failure = fault_fields["alarmCondition"] == FAUILT_ID and fault_fields["eventSeverity"] != "NORMAL"
+
+    return link_failure
+
+
+def is_message_clear_link_failure(message):
+    msg_as_json = json.loads(message)
+    event_headers = msg_as_json["event"]["commonEventHeader"]
+
+    link_failure_clear = False
+    if (event_headers["domain"] == "fault"):
+        fault_fields = msg_as_json["event"]["faultFields"]
+        link_failure_clear = fault_fields["alarmCondition"] == FAUILT_ID and fault_fields["eventSeverity"] == "NORMAL"
+
+    return link_failure_clear
+
+
+def handle_link_failure(message, o_ru_to_o_du_map, sdnr_address, sdnr_user, sdnr_pwd):
+    verboseprint("Got a link failure: ")
+    alarm_msg_as_json = json.loads(message)
+    event_headers = alarm_msg_as_json["event"]["commonEventHeader"]
+    o_ru_id = event_headers["sourceName"]
+    verboseprint("O-RU ID: " + o_ru_id)
+    if o_ru_id in o_ru_to_o_du_map:
+        o_du_id = o_ru_to_o_du_map[o_ru_id]
+        verboseprint("O-DU ID: " + o_du_id)
+        unlock_msg = json.loads(json.dumps(UNLOCK_MESSAGE))
+        send_path = SDNR_PATH.replace("[O-DU-ID]", o_du_id)
+        requests.put(sdnr_address + send_path, auth=(sdnr_user, sdnr_pwd), json=unlock_msg)
+    else:
+        print("ERROR: No mapping for O-RU ID: " + o_ru_id)
+
+
+def handle_clear_link_failure(message):
+    msg_as_json = json.loads(message)
+    event_headers = msg_as_json["event"]["commonEventHeader"]
+    o_ru_id = event_headers["sourceName"]
+    verboseprint("Cleared Link Failure for O-RU ID: " + o_ru_id)
+
+
+def read_o_ru_to_o_du_map_from_file(map_file):
+    file = open(map_file, "r")
+    contents = file.read()
+    dictionary = ast.literal_eval(contents)
+    file.close()
+    return dictionary
+
+
+def poll_and_handle_messages(mr_address, sdnr_address, sdnr_user, sdnr_pwd):
+    while True:
+        try:
+            verboseprint("Polling")
+            response = requests.get(mr_address)
+            messages = response.json()
+            for message in messages:
+                if (is_message_new_link_failure(message)):
+                    handle_link_failure(message, o_ru_to_o_du_map, sdnr_address, sdnr_user, sdnr_pwd)
+                elif (is_message_clear_link_failure(message)):
+                    handle_clear_link_failure(message)
+        except Exception as inst:
+            print(inst)
+
+        time.sleep(pollTime)
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(prog='PROG')
+    parser.add_argument('--mrHost', help='The URL of the MR host (default: %(default)s)', default="http://message-router.onap")
+    parser.add_argument('--mrPort', help='The port of the MR host (default: %(default)d)', type=int, default=3904)
+    parser.add_argument('--mrTopic', help='The topic to poll messages from (default: %(default)s)', default="unauthenticated.SEC_FAULT_OUTPUT")
+    parser.add_argument('--sdnrHost', help='The URL of the SNDR host (default: %(default)s)', default="http://localhost")
+    parser.add_argument('--sdnrPort', help='The port of the SDNR host (default: %(default)d)', type=int, default=9990)
+    parser.add_argument('--sdnrUser', help='Username for SDNR', default="admin")
+    parser.add_argument('--sdnrPwd', help='Password for SDNR', default="Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U")
+    parser.add_argument('--oRuTooDuMapFile', help='A file with the mapping between O-RU ID and O-DU ID as a dictionary (default: %(default)s)', default="o-ru-to-o-du-map.txt")
+    parser.add_argument('--pollTime', help='The time between polls (default: %(default)d)', type=int, default=10)
+    parser.add_argument('-v', '--verbose', action='store_true', help='Turn on verbose printing')
+    parser.add_argument('--version', action='version', version='%(prog)s 1.0')
+    args = vars(parser.parse_args())
+    mr_host = args["mrHost"]
+    if os.getenv("MR-HOST") is not None:
+        mr_host = os.getenv("MR-HOST")
+        print("Using MR Host from os: " + mr_host)
+    mr_port = args["mrPort"]
+    if os.getenv("MR-PORT") is not None:
+        mr_port = os.getenv("MR-PORT")
+        print("Using MR Port from os: " + mr_port)
+    mr_topic = args["mrTopic"]
+    sdnr_host = args["sdnrHost"]
+    if os.getenv("SDNR-HOST") is not None:
+        sdnr_host = os.getenv("SDNR-HOST")
+        print("Using SNDR Host from os: " + sdnr_host)
+    sdnr_port = args["sdnrPort"]
+    if os.getenv("SDNR-PORT") is not None:
+        sdnr_port = os.getenv("SDNR-PORT")
+        print("Using SNDR Host from os: " + sdnr_port)
+    sdnr_user = args["sdnrUser"]
+    if os.getenv("SDNR-USER") is not None:
+        sdnr_user = os.getenv("SDNR-USER")
+        print("Using SNDR User from os: " + sdnr_user)
+    sdnr_pwd = args["sdnrPwd"]
+    if os.getenv("SDNR-PWD") is not None:
+        sdnr_pwd = os.getenv("SDNR-PWD")
+        print("Using SNDR Password from os: " + sdnr_pwd)
+    o_ru_to_o_du_map = read_o_ru_to_o_du_map_from_file(args["oRuTooDuMapFile"])
+    pollTime = args["pollTime"]
+
+    if os.getenv("VERBOSE") is not None or args["verbose"]:
+
+        def verboseprint(*args, **kwargs):
+            print(*args, **kwargs)
+
+    else:
+        verboseprint = lambda *a, **k: None  # do-nothing function
+
+    verboseprint("Using MR address: " + mr_host + ":" + str(mr_port) + " and topic: " + mr_topic)
+    verboseprint("Using SDNR address: " + sdnr_host + ":" + str(sdnr_port))
+    verboseprint("Starting with " + str(pollTime) + " seconds between polls")
+    mr_address = mr_host + ":" + str(mr_port) + MR_PATH.replace("[TOPIC]", mr_topic)
+    sdnr_address = sdnr_host + ":" + str(sdnr_port)
+
+    poll_and_handle_messages(mr_address, sdnr_address, sdnr_user, sdnr_pwd)
diff --git a/scriptversion/app/o-ru-to-o-du-map.txt b/scriptversion/app/o-ru-to-o-du-map.txt
new file mode 100644 (file)
index 0000000..314495c
--- /dev/null
@@ -0,0 +1,13 @@
+{
+    "ERICSSON-O-RU-11220": "O-DU-1122",
+    "ERICSSON-O-RU-11221": "O-DU-1122",
+    "ERICSSON-O-RU-11222": "O-DU-1122",
+    "ERICSSON-O-RU-11223": "O-DU-1122",
+    "ERICSSON-O-RU-11223": "O-DU-1122",
+    "ERICSSON-O-RU-11224": "O-DU-1123",
+    "ERICSSON-O-RU-11225": "O-DU-1123",
+    "ERICSSON-O-RU-11226": "O-DU-1123",
+    "ERICSSON-O-RU-11227": "O-DU-1124",
+    "ERICSSON-O-RU-11228": "O-DU-1125",
+    "ERICSSON-O-RU-11229": "O-DU-1125",
+}
\ No newline at end of file
diff --git a/scriptversion/app/requirements.txt b/scriptversion/app/requirements.txt
new file mode 100644 (file)
index 0000000..b22100f
--- /dev/null
@@ -0,0 +1,5 @@
+certifi==2020.12.5
+chardet==4.0.0
+idna==2.10
+requests==2.25.1
+urllib3==1.26.4
\ No newline at end of file
diff --git a/scriptversion/controlloop-rest-payloads/commission.yaml b/scriptversion/controlloop-rest-payloads/commission.yaml
new file mode 100644 (file)
index 0000000..2963a8c
--- /dev/null
@@ -0,0 +1,187 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+data_types:
+  onap.datatypes.ToscaConceptIdentifier:
+    derived_from: tosca.datatypes.Root
+    properties:
+      name:
+        type: string
+        required: true
+      version:
+        type: string
+        required: true
+node_types:
+  org.onap.policy.clamp.controlloop.Participant:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+  org.onap.policy.clamp.controlloop.ControlLoop:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+      elements:
+        type: list
+        required: true
+        entry_schema:
+          type: onap.datatypes.ToscaConceptIdentifier
+  org.onap.policy.clamp.controlloop.ControlLoopElement:
+    version: 1.0.1
+    derived_from: tosca.nodetypes.Root
+    properties:
+      provider:
+        type: string
+        requred: false
+      participant_id:
+        type: onap.datatypes.ToscaConceptIdentifier
+        requred: true
+  org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement:
+    version: 1.0.1
+    derived_from: org.onap.policy.clamp.controlloop.ControlLoopElement
+    properties:
+      chart:
+        type: string
+        required: true
+      configs:
+        type: list
+        required: false
+      requirements:
+        type: string
+        requred: false
+      templates:
+        type: list
+        required: false
+        entry_schema:
+      values:
+        type: string
+        requred: true
+topology_template:
+  node_templates:
+    org.onap.domain.linkmonitor.LinkMonitorControlLoopDefinition1:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.ControlLoop
+      type_version: 1.0.1
+      description: Control loop for Link Monitor
+      properties:
+        provider: Ericsson
+        elements:
+        - name: org.onap.domain.linkmonitor.OruAppK8SMicroserviceControlLoopElement
+          version: 1.2.3
+        - name: org.onap.domain.linkmonitor.MessageGeneratorK8SMicroserviceControlLoopElement
+          version: 1.2.3
+        - name: org.onap.domain.linkmonitor.SdnrSimulatorK8SMicroserviceControlLoopElement
+          version: 1.2.3
+        - name: org.onap.domain.linkmonitor.DmaapMrK8SMicroserviceControlLoopElement
+          version: 1.2.3
+    org.onap.k8s.controlloop.K8SControlLoopParticipant:
+      version: 2.3.4
+      type: org.onap.policy.clamp.controlloop.Participant
+      type_version: 1.0.1
+      description: Participant for k8s
+      properties:
+        provider: ONAP
+    org.onap.domain.linkmonitor.OruAppK8SMicroserviceControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement
+      type_version: 1.0.1
+      description: Control loop element for oru-app
+      properties:
+        provider: ONAP
+        participant_id:
+          name: K8sParticipant0
+          version: 1.0.0
+        participantType:
+          name: org.onap.k8s.controlloop.K8SControlLoopParticipant
+          version: 2.3.4
+        chart:
+          chartId:
+            name: oru-app
+            version: 0.1.0
+          releaseName: oru-app
+          repository:
+            repoName: chartmuseum
+          namespace: nonrtric
+    org.onap.domain.linkmonitor.MessageGeneratorK8SMicroserviceControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement
+      type_version: 1.0.1
+      description: Control loop element for message-generator
+      properties:
+        provider: ONAP
+        participant_id:
+          name: K8sParticipant0
+          version: 1.0.0
+        participantType:
+          name: org.onap.k8s.controlloop.K8SControlLoopParticipant
+          version: 2.3.4
+        chart:
+          chartId:
+            name: message-generator
+            version: 0.1.0
+          releaseName: message-generator
+          repository:
+            repoName: chartmuseum
+          namespace: nonrtric
+          overrideParams:
+            image.tag: v2
+    org.onap.domain.linkmonitor.SdnrSimulatorK8SMicroserviceControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement
+      type_version: 1.0.1
+      description: Control loop element for sdnr-simulator
+      properties:
+        provider: ONAP
+        participant_id:
+          name: K8sParticipant0
+          version: 1.0.0
+        participantType:
+          name: org.onap.k8s.controlloop.K8SControlLoopParticipant
+          version: 2.3.4
+        chart:
+          chartId:
+            name: sdnr-simulator
+            version: 0.1.0
+          releaseName: sdnr-simulator
+          repository:
+            repoName: chartmuseum
+          namespace: nonrtric
+    org.onap.domain.linkmonitor.DmaapMrK8SMicroserviceControlLoopElement:
+      version: 1.2.3
+      type: org.onap.policy.clamp.controlloop.K8SMicroserviceControlLoopElement
+      type_version: 1.0.1
+      description: Control loop element for dmaap-mr
+      properties:
+        provider: ONAP
+        participant_id:
+          name: K8sParticipant0
+          version: 1.0.0
+        participantType:
+          name: org.onap.k8s.controlloop.K8SControlLoopParticipant
+          version: 2.3.4
+        chart:
+          chartId:
+            name: dmaap-mr
+            version: 0.1.0
+          releaseName: dmaap-mr
+          repository:
+            repoName: chartmuseum
+          namespace: nonrtric
\ No newline at end of file
diff --git a/scriptversion/controlloop-rest-payloads/instantiation-command.json b/scriptversion/controlloop-rest-payloads/instantiation-command.json
new file mode 100644 (file)
index 0000000..b1da263
--- /dev/null
@@ -0,0 +1,9 @@
+{
+    "orderedState": "PASSIVE",
+    "controlLoopIdentifierList": [
+        {
+            "name": "LinkMonitorInstance1",
+            "version": "1.0.1"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/scriptversion/controlloop-rest-payloads/instantiation.json b/scriptversion/controlloop-rest-payloads/instantiation.json
new file mode 100644 (file)
index 0000000..ec3b9f1
--- /dev/null
@@ -0,0 +1,89 @@
+{
+    "controlLoopList": [
+        {
+            "name": "LinkMonitorInstance1",
+            "version": "1.0.1",
+            "definition": {
+                "name": "org.onap.domain.linkmonitor.LinkMonitorControlLoopDefinition1",
+                "version": "1.2.3"
+            },
+            "state": "UNINITIALISED",
+            "orderedState": "UNINITIALISED",
+            "description": "Link Monitor control loop instance 1",
+            "elements": {
+                "709c62b3-8918-41b9-a747-d21eb79c6c12": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c12",
+                    "definition": {
+                        "name": "org.onap.domain.linkmonitor.OruAppK8SMicroserviceControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.k8s.controlloop.K8SControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "participantId": {
+                        "name": "K8sParticipant0",
+                        "version": "1.0.0"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Oru App k8s Control Loop Element"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c13": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c13",
+                    "definition": {
+                        "name": "org.onap.domain.linkmonitor.MessageGeneratorK8SMicroserviceControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.k8s.controlloop.K8SControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "participantId": {
+                        "name": "K8sParticipant0",
+                        "version": "1.0.0"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Message Generator k8s Control Loop Element"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c14": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c14",
+                    "definition": {
+                        "name": "org.onap.domain.linkmonitor.SdnrSimulatorK8SMicroserviceControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.k8s.controlloop.K8SControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "participantId": {
+                        "name": "K8sParticipant0",
+                        "version": "1.0.0"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Sdnr Simulator k8s Control Loop Element"
+                },
+                "709c62b3-8918-41b9-a747-d21eb79c6c15": {
+                    "id": "709c62b3-8918-41b9-a747-d21eb79c6c15",
+                    "definition": {
+                        "name": "org.onap.domain.linkmonitor.DmaapMrK8SMicroserviceControlLoopElement",
+                        "version": "1.2.3"
+                    },
+                    "participantType": {
+                        "name": "org.onap.k8s.controlloop.K8SControlLoopParticipant",
+                        "version": "2.3.4"
+                    },
+                    "participantId": {
+                        "name": "K8sParticipant0",
+                        "version": "1.0.0"
+                    },
+                    "state": "UNINITIALISED",
+                    "orderedState": "UNINITIALISED",
+                    "description": "Dmaap Mr k8s Control Loop Element"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/scriptversion/docker-compose-controlloop/README.md b/scriptversion/docker-compose-controlloop/README.md
new file mode 100644 (file)
index 0000000..965da2b
--- /dev/null
@@ -0,0 +1,49 @@
+This docker-compose will create a control loop that will deploy all components of the closed loop recovery use case into a k8s cluster using the k8s participant from CLAMP in ONAP.
+
+It will also bring up the chartmuseum registry that will be used by helm when deploying the charts.
+The script named chartmuseum_init.sh will push all the charts into the chartmuseum.
+This script is mounted into the k8s-participant docker container but can also be run locally.
+
+Depending on the type of k8s cluster and the operating system being used, different settings might need to be done for the k8s-participant docker container. For example, in case of minikube, the following should be added under k8s-participant (assuming that kube-config file of the host machine has been copied into the config directory):
+
+volumes:
+ - ./config/kube-config:/home/policy/.kube/config:ro
+ - ~/.minikube/profiles/minikube:/home/policy/.minikube/profiles/minikube
+
+This will mount the kube-config file into the k8s-participant docker container so that it is able to deploy services into the minikube instance running in the host machine. The minikube directory contains the client-certificate and client-key.
+
+Since the kube-api server is running in the host machine instead of the k8s-participant docker container, some extra steps are needed:
+
+1) Linux
+
+Run the following command in the host machine so that the localhost referred to in the kube-config file points to the host machine:
+
+iptables -A INPUT -i docker0 -j ACCEPT
+
+2) Mac
+
+Mac OS does not seem to have the iptables command. However, in order to refer to the host machine from inside the docker container, one may use "host.docker.internal" but this gives rise to another problem:
+
+Unable to connect to the server: x509: certificate is valid for minikubeCA, control-plane.minikube.internal, kubernetes.default.svc.cluster.local, kubernetes.default.svc, kubernetes.default, kubernetes, localhost, not host.docker.internal
+
+As a workaround, the TLS can be disabled. So, the following part should be modified in the kube-config file:
+
+- cluster:
+    server: https://host.docker.internal:<PORT>
+    insecure-skip-tls-verify: true
+
+
+## License
+
+Copyright (C) 2021 Nordix Foundation.
+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/scriptversion/docker-compose-controlloop/config/db/bootstrap-database.sh b/scriptversion/docker-compose-controlloop/config/db/bootstrap-database.sh
new file mode 100644 (file)
index 0000000..6a6310d
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+###
+# ============LICENSE_START=======================================================
+# ONAP CLAMP
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# Modifications Copyright (C) 2021 Nordix Foundation. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END============================================
+# ===================================================================
+#
+###
+
+mysql -uroot -p$MYSQL_ROOT_PASSWORD -f < /docker-entrypoint-initdb.d/create-db.sql
+mysql -uroot -p$MYSQL_ROOT_PASSWORD --execute "CREATE USER 'policy_user'@'%' IDENTIFIED BY 'policy_user';"
+mysql -uroot -p$MYSQL_ROOT_PASSWORD --execute "GRANT ALL PRIVILEGES ON controlloop.* TO 'policy_user'@'%';"
\ No newline at end of file
diff --git a/scriptversion/docker-compose-controlloop/config/db/create-db.sql b/scriptversion/docker-compose-controlloop/config/db/create-db.sql
new file mode 100644 (file)
index 0000000..bc64431
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Create CLDS database objects (tables, etc.)
+#
+#
+CREATE DATABASE IF NOT EXISTS `cldsdb4`;
+CREATE DATABASE IF NOT EXISTS `policyadmin`;
+CREATE DATABASE IF NOT EXISTS `controlloop`;
+USE `cldsdb4`;
+DROP USER 'clds';
+CREATE USER 'clds';
+GRANT ALL on cldsdb4.* to 'clds' identified by 'sidnnd83K' with GRANT OPTION;
+FLUSH PRIVILEGES;
+
diff --git a/scriptversion/docker-compose-controlloop/config/ks.jks b/scriptversion/docker-compose-controlloop/config/ks.jks
new file mode 100644 (file)
index 0000000..001c7e1
Binary files /dev/null and b/scriptversion/docker-compose-controlloop/config/ks.jks differ
diff --git a/scriptversion/docker-compose-controlloop/docker-compose.yml b/scriptversion/docker-compose-controlloop/docker-compose.yml
new file mode 100644 (file)
index 0000000..80d5186
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# ===========LICENSE_START====================================================
+# Copyright (C) 2021 Nordix Foundation. All rights reserved.
+# ============================================================================
+# 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.
+# ============LICENSE_END=====================================================
+#
+version: '2'
+networks:
+  default:
+    driver: bridge
+    name: nonrtric-docker-net
+services:
+   mariadb:
+      image: nexus3.onap.org:10001/mariadb:10.5.8
+      container_name: mariadb
+      hostname: mariadb
+      volumes:
+       - db-vol:/var/lib/mysql
+       - "./config/db/:/docker-entrypoint-initdb.d:rw"
+      environment:
+       - MYSQL_ROOT_PASSWORD=strong_pitchou
+      ports:
+       - "3306:3306"
+      expose:
+       - 3306
+   controlloop-runtime:
+      image: nexus3.onap.org:10001/onap/policy-clamp-cl-runtime:6.1.3
+      container_name: controlloop-runtime
+      depends_on:
+       - mariadb
+      hostname: controlloop-runtime
+      ports:
+       - "6969:6969"
+      expose:
+       - 6969
+      volumes:
+       - ./config/ks.jks:/opt/app/policy/clamp/etc/ssl/policy-keystore:ro
+       - ./wait_for_port.sh:/opt/app/policy/clamp/bin/wait_for_port.sh:ro
+      environment:
+       - TOPICSERVER=onap-dmaap
+       - MARIADB_HOST=mariadb
+       - MARIADB_PORT=3306
+       - KEYSTORE=/opt/app/policy/clamp/etc/ssl/policy-keystore
+       - KEYSTORE_PASSWD=Pol1cy_0nap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_TOPIC=POLICY-CLRUNTIME-PARTICIPANT
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_SERVERS_0=onap-dmaap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_TOPICCOMMINFRASTRUCTURE=dmaap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_FETCHTIMEOUT=15000
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSOURCES_0_USEHTTPS=false
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_TOPIC=POLICY-CLRUNTIME-PARTICIPANT
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_SERVERS_0=onap-dmaap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_TOPICCOMMINFRASTRUCTURE=dmaap
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_FETCHTIMEOUT=15000
+       - RUNTIME_TOPICPARAMETERGROUP_TOPICSINKS_0_USEHTTPS=false
+      entrypoint: /opt/app/policy/clamp/bin/wait_for_port.sh
+      command: [
+        '-c', '/opt/app/policy/clamp/bin/controlloop-runtime.sh',
+        'mariadb', '3306',
+        'onap-dmaap', '3904'
+        ]
+   k8s-participant:
+      image: nexus3.onap.org:10001/onap/policy-clamp-cl-k8s-ppnt:6.1.3
+      container_name: k8s-participant
+      depends_on:
+       - mariadb
+       - controlloop-runtime
+      hostname: k8s-participant
+      volumes:
+       - ./config/ks.jks:/opt/app/policy/clamp/etc/ssl/policy-keystore:ro
+       - ./../helm:/home/policy/helm
+       - ./wait_for_port.sh:/opt/app/policy/clamp/bin/wait_for_port.sh:ro
+       - <PATH TO kube-config>:/home/policy/.kube/config:ro
+      environment:
+       - TOPICSERVER=onap-dmaap
+       - KEYSTORE=/opt/app/policy/clamp/etc/ssl/policy-keystore
+       - KEYSTORE_PASSWD=Pol1cy_0nap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_TOPIC=POLICY-CLRUNTIME-PARTICIPANT
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_SERVERS_0=onap-dmaap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_TOPICCOMMINFRASTRUCTURE=dmaap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_FETCHTIMEOUT=15000
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSOURCES_0_USEHTTPS=false
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_TOPIC=POLICY-CLRUNTIME-PARTICIPANT
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_SERVERS_0=onap-dmaap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_TOPICCOMMINFRASTRUCTURE=dmaap
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_FETCHTIMEOUT=15000
+       - PARTICIPANT_INTERMEDIARYPARAMETERS_CLAMPCONTROLLOOPTOPICS_TOPICSINKS_0_USEHTTPS=false
+      entrypoint: sh -c "/opt/app/policy/clamp/bin/wait_for_port.sh controlloop-runtime 6969 && /home/policy/helm/chartmuseum_init.sh && /opt/app/policy/clamp/bin/kubernetes-participant.sh"
+   chartmuseum:
+      image: ghcr.io/helm/chartmuseum:v0.13.1
+      container_name: chartmuseum
+      hostname: chartmuseum
+      volumes:
+       - ./charts:/charts
+      environment:
+       - STORAGE=local
+       - STORAGE_LOCAL_ROOTDIR=/charts
+volumes:
+  db-vol:
\ No newline at end of file
diff --git a/scriptversion/docker-compose-controlloop/wait_for_port.sh b/scriptversion/docker-compose-controlloop/wait_for_port.sh
new file mode 100644 (file)
index 0000000..aec5f22
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+# ============LICENSE_START====================================================
+#  Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+# =============================================================================
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END======================================================
+
+tmout=120
+cmd=
+while getopts c:t: opt; do
+    case "$opt" in
+    c) cmd="$OPTARG" ;;
+    t) tmout="$OPTARG" ;;
+    esac
+done
+nargs=$(expr $OPTIND - 1)
+shift $nargs
+
+even_args=$(expr $# % 2)
+if [ $# -lt 2 -o $even_args -ne 0 ]; then
+    echo "args: [-t timeout] [-c command] hostname1 port1 hostname2 port2 ..." >&2
+    exit 1
+fi
+
+while [ $# -ge 2 ]; do
+    export host=$1
+    export port=$2
+    shift
+    shift
+
+    echo "Waiting for $host port $port..."
+    timeout $tmout sh -c 'until nc -vz "$host" "$port"; do echo -n ".";
+        sleep 1; done'
+    rc=$?
+
+    if [ $rc != 0 ]; then
+        echo "$host port $port cannot be reached"
+        exit $rc
+    fi
+done
+
+$cmd
+
+exit 0
diff --git a/scriptversion/docker-compose/README.md b/scriptversion/docker-compose/README.md
new file mode 100644 (file)
index 0000000..541b43e
--- /dev/null
@@ -0,0 +1,24 @@
+## Run script
+
+`bash start.sh`
+
+This scripts will build images and start up four components in docker enviroment by applying docker-compose yaml file:
+- dmaap-mr
+- oru-app
+- sdnr-simulator
+- message-generator
+
+## License
+
+Copyright (C) 2021 Nordix Foundation.
+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/scriptversion/docker-compose/docker-compose.yaml b/scriptversion/docker-compose/docker-compose.yaml
new file mode 100644 (file)
index 0000000..5fa6094
--- /dev/null
@@ -0,0 +1,60 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+version: '3.5'
+
+networks:
+  default:
+    driver: bridge
+    name: nonrtric-docker-net
+
+services:
+  message-generator:
+    image: message-generator
+    container_name: message-generator
+    networks:
+      default:
+        aliases:
+          - message-generator
+    environment:
+      - MR-HOST=http://dmaap-mr
+      - MR-PORT=3904
+
+  sdnr-simulator:
+    image: sdnr-simulator
+    container_name: sdnr-simulator
+    networks:
+      default:
+        aliases:
+          - sdnr-simulator
+    ports:
+      - 9990:9990
+    environment:
+      - MR-HOST=http://dmaap-mr
+      - MR-PORT=3904
+
+  oru-app:
+    image: oru-app
+    container_name: oru-app
+    networks:
+      default:
+        aliases:
+          - oru-app
+    environment:
+      - MR-HOST=http://dmaap-mr
+      - MR-PORT=3904
+      - SDNR-HOST=http://sdnr-simulator
+      - SDNR-PORT=9990
+      - VERBOSE=on
\ No newline at end of file
diff --git a/scriptversion/docker-compose/start.sh b/scriptversion/docker-compose/start.sh
new file mode 100644 (file)
index 0000000..419bef1
--- /dev/null
@@ -0,0 +1,51 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
+docker stop $(docker ps -aq)
+docker system prune -f
+
+# build o-ru application image
+cd ${SHELL_FOLDER}/../app/
+docker build -t oru-app .
+
+# build simulator image of sdnr
+cd ${SHELL_FOLDER}/../simulators/
+docker build -f Dockerfile-sdnr-sim -t sdnr-simulator .
+
+# build message generator image
+docker build -f Dockerfile-message-generator -t message-generator .
+
+# start up dmaap message router
+cd ${SHELL_FOLDER}/../../../../../docker-compose/
+docker-compose -f docker-compose.yaml -f mr/docker-compose.yml up -d
+
+# wait until mr up & running
+for i in {1..60}; do
+    res=$(curl -o /dev/null -sw %{http_code} http://localhost:3904/topics)
+    echo "$res"
+    expect="200"
+    if [ "$res" == "$expect" ]; then
+        echo -e "dmaap-mr is alive!\n"
+        break;
+    else
+        sleep $i
+    fi
+done
+
+# start up oru, message-generator and sdnr-simulator
+cd ${SHELL_FOLDER}
+docker-compose up -d
\ No newline at end of file
diff --git a/scriptversion/helm/README.md b/scriptversion/helm/README.md
new file mode 100644 (file)
index 0000000..a40e78b
--- /dev/null
@@ -0,0 +1,24 @@
+## Run script
+
+`bash start.sh`
+
+This scripts will build images and start up four components in k8s enviroment by applying helm chart files:
+- dmaap-mr
+- oru-app
+- sdnr-simulator
+- message-generator
+
+## License
+
+Copyright (C) 2021 Nordix Foundation.
+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/scriptversion/helm/chartmuseum_init.sh b/scriptversion/helm/chartmuseum_init.sh
new file mode 100644 (file)
index 0000000..4b0c7ee
--- /dev/null
@@ -0,0 +1,41 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
+cd ${SHELL_FOLDER}
+
+# build dmaap-mr helm chart & push to chartmuseum
+cd ${SHELL_FOLDER}/dmaap-mr/
+helm package .
+curl --data-binary "@dmaap-mr-0.1.0.tgz" http://chartmuseum:8080/api/charts
+
+# build message-generator helm chart & push to chartmuseum
+cd ${SHELL_FOLDER}/message-generator/
+helm package .
+curl --data-binary "@message-generator-0.1.0.tgz" http://chartmuseum:8080/api/charts
+
+# build oru-app helm chart & push to chartmuseum
+cd ${SHELL_FOLDER}/oru-app/
+helm package .
+curl --data-binary "@oru-app-0.1.0.tgz" http://chartmuseum:8080/api/charts
+
+# build sdnr-simulator helm chart & push to chartmuseum
+cd ${SHELL_FOLDER}/sdnr-simulator/
+helm package .
+curl --data-binary "@sdnr-simulator-0.1.0.tgz" http://chartmuseum:8080/api/charts
+
+# add chartmuseum repo to helm
+helm repo add chartmuseum http://chartmuseum:8080
\ No newline at end of file
diff --git a/scriptversion/helm/dmaap-mr/.helmignore b/scriptversion/helm/dmaap-mr/.helmignore
new file mode 100644 (file)
index 0000000..0e8a0eb
--- /dev/null
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/scriptversion/helm/dmaap-mr/Chart.yaml b/scriptversion/helm/dmaap-mr/Chart.yaml
new file mode 100644 (file)
index 0000000..95b7f51
--- /dev/null
@@ -0,0 +1,39 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: v1
+name: dmaap-mr
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/scriptversion/helm/dmaap-mr/templates/_helpers.tpl b/scriptversion/helm/dmaap-mr/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..c5fe556
--- /dev/null
@@ -0,0 +1,79 @@
+{{/*
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+*/}}
+
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "dmaap-mr.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "dmaap-mr.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "dmaap-mr.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "dmaap-mr.labels" -}}
+helm.sh/chart: {{ include "dmaap-mr.chart" . }}
+{{ include "dmaap-mr.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "dmaap-mr.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "dmaap-mr.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "dmaap-mr.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "dmaap-mr.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/scriptversion/helm/dmaap-mr/templates/deployment.yaml b/scriptversion/helm/dmaap-mr/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..d8ce48d
--- /dev/null
@@ -0,0 +1,80 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "dmaap-mr.fullname" . }}
+  labels:
+    {{- include "dmaap-mr.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "dmaap-mr.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "dmaap-mr.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          env:
+          - name: TOPIC_READ
+            value: http://dmaap-mr:3904/events/unauthenticated.SEC_FAULT_OUTPUT
+          - name: TOPIC_WRITE
+            value: http://dmaap-mr:3904/events/unauthenticated.SEC_FAULT_OUTPUT
+          - name: GENERIC_TOPICS_UPLOAD_BASEURL
+            value: http://dmaap-mr:3904
+          ports:
+            - name: http
+              containerPort: 3904
+              protocol: TCP
+          livenessProbe:
+            httpGet:
+              path: /
+              port: http
+          readinessProbe:
+            httpGet:
+              path: /
+              port: http
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/scriptversion/helm/dmaap-mr/templates/service.yaml b/scriptversion/helm/dmaap-mr/templates/service.yaml
new file mode 100644 (file)
index 0000000..be88c95
--- /dev/null
@@ -0,0 +1,30 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "dmaap-mr.fullname" . }}
+  labels:
+    {{- include "dmaap-mr.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+    - port: {{ .Values.service.port }}
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    {{- include "dmaap-mr.selectorLabels" . | nindent 4 }}
diff --git a/scriptversion/helm/dmaap-mr/values.yaml b/scriptversion/helm/dmaap-mr/values.yaml
new file mode 100644 (file)
index 0000000..3fd2b09
--- /dev/null
@@ -0,0 +1,65 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+# Default values for dmaap-mr.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+  repository: mrstub
+  pullPolicy: IfNotPresent
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: "latest"
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+podAnnotations: {}
+
+podSecurityContext: {}
+  # fsGroup: 2000
+
+securityContext: {}
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 3904
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/scriptversion/helm/message-generator/.helmignore b/scriptversion/helm/message-generator/.helmignore
new file mode 100644 (file)
index 0000000..0e8a0eb
--- /dev/null
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/scriptversion/helm/message-generator/Chart.yaml b/scriptversion/helm/message-generator/Chart.yaml
new file mode 100644 (file)
index 0000000..59720da
--- /dev/null
@@ -0,0 +1,39 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: v1
+name: message-generator
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/scriptversion/helm/message-generator/templates/_helpers.tpl b/scriptversion/helm/message-generator/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..68ed9c2
--- /dev/null
@@ -0,0 +1,79 @@
+{{/*
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+*/}}
+
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "message-generator.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "message-generator.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "message-generator.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "message-generator.labels" -}}
+helm.sh/chart: {{ include "message-generator.chart" . }}
+{{ include "message-generator.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "message-generator.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "message-generator.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "message-generator.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "message-generator.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/scriptversion/helm/message-generator/templates/deployment.yaml b/scriptversion/helm/message-generator/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..817134e
--- /dev/null
@@ -0,0 +1,70 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "message-generator.fullname" . }}
+  labels:
+    {{- include "message-generator.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "message-generator.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "message-generator.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          env:
+          - name: MR-HOST
+            value: "{{ .Values.messagerouter.host }}"
+          - name: MR-PORT
+            value: "{{ .Values.messagerouter.port }}"
+          ports:
+            - name: http
+              containerPort: 80
+              protocol: TCP
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/scriptversion/helm/message-generator/templates/service.yaml b/scriptversion/helm/message-generator/templates/service.yaml
new file mode 100644 (file)
index 0000000..6770d67
--- /dev/null
@@ -0,0 +1,30 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "message-generator.fullname" . }}
+  labels:
+    {{- include "message-generator.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+    - port: {{ .Values.service.port }}
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    {{- include "message-generator.selectorLabels" . | nindent 4 }}
diff --git a/scriptversion/helm/message-generator/values.yaml b/scriptversion/helm/message-generator/values.yaml
new file mode 100644 (file)
index 0000000..88cac99
--- /dev/null
@@ -0,0 +1,69 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+# Default values for message-generator.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+  repository: message-generator
+  pullPolicy: IfNotPresent
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: "latest"
+
+messagerouter:
+  host: http://dmaap-mr
+  port: 3904
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+podAnnotations: {}
+
+podSecurityContext: {}
+  # fsGroup: 2000
+
+securityContext: {}
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/scriptversion/helm/oru-app/.helmignore b/scriptversion/helm/oru-app/.helmignore
new file mode 100644 (file)
index 0000000..0e8a0eb
--- /dev/null
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/scriptversion/helm/oru-app/Chart.yaml b/scriptversion/helm/oru-app/Chart.yaml
new file mode 100644 (file)
index 0000000..ed7203c
--- /dev/null
@@ -0,0 +1,39 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: v1
+name: oru-app
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/scriptversion/helm/oru-app/templates/_helpers.tpl b/scriptversion/helm/oru-app/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..8824c6a
--- /dev/null
@@ -0,0 +1,79 @@
+{{/*
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+*/}}
+
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "oru-app.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "oru-app.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "oru-app.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "oru-app.labels" -}}
+helm.sh/chart: {{ include "oru-app.chart" . }}
+{{ include "oru-app.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "oru-app.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "oru-app.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "oru-app.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "oru-app.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/scriptversion/helm/oru-app/templates/deployment.yaml b/scriptversion/helm/oru-app/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..7f648d9
--- /dev/null
@@ -0,0 +1,76 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "oru-app.fullname" . }}
+  labels:
+    {{- include "oru-app.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "oru-app.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "oru-app.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          env:
+          - name: MR-HOST
+            value: "{{ .Values.messagerouter.host }}"
+          - name: MR-PORT
+            value: "{{ .Values.messagerouter.port }}"
+          - name: SDNR-HOST
+            value: "{{ .Values.sdnr.host }}"
+          - name: SDNR-PORT
+            value: "{{ .Values.sdnr.port }}"
+          - name: VERBOSE
+            value: "on"
+          ports:
+            - name: http
+              containerPort: 80
+              protocol: TCP
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/scriptversion/helm/oru-app/templates/service.yaml b/scriptversion/helm/oru-app/templates/service.yaml
new file mode 100644 (file)
index 0000000..8ead821
--- /dev/null
@@ -0,0 +1,30 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "oru-app.fullname" . }}
+  labels:
+    {{- include "oru-app.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+    - port: {{ .Values.service.port }}
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    {{- include "oru-app.selectorLabels" . | nindent 4 }}
diff --git a/scriptversion/helm/oru-app/values.yaml b/scriptversion/helm/oru-app/values.yaml
new file mode 100644 (file)
index 0000000..0029873
--- /dev/null
@@ -0,0 +1,73 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+# Default values for oru-app.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+  repository: oru-app
+  pullPolicy: IfNotPresent
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: "latest"
+
+messagerouter:
+  host: http://dmaap-mr
+  port: 3904
+
+sdnr:
+  host: http://sdnr-simulator
+  port: 9990
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+podAnnotations: {}
+
+podSecurityContext: {}
+  # fsGroup: 2000
+
+securityContext: {}
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 80
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/scriptversion/helm/sdnr-simulator/.helmignore b/scriptversion/helm/sdnr-simulator/.helmignore
new file mode 100644 (file)
index 0000000..0e8a0eb
--- /dev/null
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/scriptversion/helm/sdnr-simulator/Chart.yaml b/scriptversion/helm/sdnr-simulator/Chart.yaml
new file mode 100644 (file)
index 0000000..0e31143
--- /dev/null
@@ -0,0 +1,39 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: v1
+name: sdnr-simulator
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/scriptversion/helm/sdnr-simulator/templates/_helpers.tpl b/scriptversion/helm/sdnr-simulator/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..ddea543
--- /dev/null
@@ -0,0 +1,79 @@
+{{/*
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+*/}}
+
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "sdnr-simulator.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "sdnr-simulator.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "sdnr-simulator.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "sdnr-simulator.labels" -}}
+helm.sh/chart: {{ include "sdnr-simulator.chart" . }}
+{{ include "sdnr-simulator.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "sdnr-simulator.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "sdnr-simulator.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "sdnr-simulator.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "sdnr-simulator.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/scriptversion/helm/sdnr-simulator/templates/deployment.yaml b/scriptversion/helm/sdnr-simulator/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..8b77612
--- /dev/null
@@ -0,0 +1,78 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "sdnr-simulator.fullname" . }}
+  labels:
+    {{- include "sdnr-simulator.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "sdnr-simulator.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "sdnr-simulator.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          env:
+          - name: MR-HOST
+            value: "{{ .Values.messagerouter.host }}"
+          - name: MR-PORT
+            value: "{{ .Values.messagerouter.port }}"
+          ports:
+            - name: http
+              containerPort: 9990
+              protocol: TCP
+          livenessProbe:
+            httpGet:
+              path: /
+              port: http
+          readinessProbe:
+            httpGet:
+              path: /
+              port: http
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/scriptversion/helm/sdnr-simulator/templates/service.yaml b/scriptversion/helm/sdnr-simulator/templates/service.yaml
new file mode 100644 (file)
index 0000000..6a8a39e
--- /dev/null
@@ -0,0 +1,30 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "sdnr-simulator.fullname" . }}
+  labels:
+    {{- include "sdnr-simulator.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+    - port: {{ .Values.service.port }}
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    {{- include "sdnr-simulator.selectorLabels" . | nindent 4 }}
diff --git a/scriptversion/helm/sdnr-simulator/values.yaml b/scriptversion/helm/sdnr-simulator/values.yaml
new file mode 100644 (file)
index 0000000..cacad47
--- /dev/null
@@ -0,0 +1,69 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+
+# Default values for sdnr-simulator.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+  repository: sdnr-simulator
+  pullPolicy: IfNotPresent
+  # Overrides the image tag whose default is the chart appVersion.
+  tag: "latest"
+
+messagerouter:
+  host: http://dmaap-mr
+  port: 3904
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+podAnnotations: {}
+
+podSecurityContext: {}
+  # fsGroup: 2000
+
+securityContext: {}
+  # capabilities:
+  #   drop:
+  #   - ALL
+  # readOnlyRootFilesystem: true
+  # runAsNonRoot: true
+  # runAsUser: 1000
+
+service:
+  type: ClusterIP
+  port: 9990
+
+resources: {}
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  # limits:
+  #   cpu: 100m
+  #   memory: 128Mi
+  # requests:
+  #   cpu: 100m
+  #   memory: 128Mi
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
diff --git a/scriptversion/helm/start.sh b/scriptversion/helm/start.sh
new file mode 100644 (file)
index 0000000..46365c6
--- /dev/null
@@ -0,0 +1,58 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
+cd ${SHELL_FOLDER}
+helm uninstall dmaap-mr message-generator oru-app sdnr-simulator -n nonrtric
+
+# be careful if other stopped containers are on the same system
+docker stop $(docker ps -aq)
+docker system prune -f
+
+# build o-ru application image
+cd ${SHELL_FOLDER}/../app/
+docker build -t oru-app .
+
+# build simulator image of sdnr
+cd ${SHELL_FOLDER}/../simulators/
+docker build -f Dockerfile-sdnr-sim -t sdnr-simulator .
+
+# build message generator image
+docker build -f Dockerfile-message-generator -t message-generator .
+
+# build dmaap-mr sim
+cd ${SHELL_FOLDER}/../../../../mrstub/
+docker build -t mrstub .
+
+# build dmapp-mr helm chart & install chart
+cd ${SHELL_FOLDER}/dmaap-mr/
+helm package .
+helm install dmaap-mr dmaap-mr-0.1.0.tgz --namespace nonrtric --create-namespace --wait
+
+# build dmapp-mr helm chart & install chart
+cd ${SHELL_FOLDER}/message-generator/
+helm package .
+helm install message-generator message-generator-0.1.0.tgz --namespace nonrtric --create-namespace --wait
+
+# build dmapp-mr helm chart & install chart
+cd ${SHELL_FOLDER}/oru-app/
+helm package .
+helm install oru-app oru-app-0.1.0.tgz --namespace nonrtric --create-namespace --wait
+
+# build dmapp-mr helm chart & install chart
+cd ${SHELL_FOLDER}/sdnr-simulator/
+helm package .
+helm install sdnr-simulator sdnr-simulator-0.1.0.tgz --namespace nonrtric --create-namespace --wait
\ No newline at end of file
diff --git a/scriptversion/k8s/README.md b/scriptversion/k8s/README.md
new file mode 100644 (file)
index 0000000..0282b7c
--- /dev/null
@@ -0,0 +1,24 @@
+## Run script
+
+`bash start.sh`
+
+This scripts will build images and start up four components in k8s enviroment by applying k8s yaml file:
+- dmaap-mr
+- oru-app
+- sdnr-simulator
+- message-generator
+
+## License
+
+Copyright (C) 2021 Nordix Foundation.
+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/scriptversion/k8s/linkfailure.yml b/scriptversion/k8s/linkfailure.yml
new file mode 100644 (file)
index 0000000..ede8602
--- /dev/null
@@ -0,0 +1,200 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: nonrtric
+---
+apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
+kind: Deployment
+metadata:
+  name: dmaap-mr
+  namespace: nonrtric
+  labels:
+    app: dmaap-mr
+spec:
+  selector:
+    matchLabels:
+      app: dmaap-mr
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: dmaap-mr
+    spec:
+      containers:
+      - name: dmaap-mr
+        image: mrstub
+        imagePullPolicy: IfNotPresent
+        ports:
+        - name: http
+          containerPort: 3904
+        - name: https
+          containerPort: 3905
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: dmaap-mr
+  namespace: nonrtric
+  labels:
+    app: dmaap-mr
+spec:
+  type: ClusterIP
+  ports:
+    - name: http
+      protocol: TCP
+      port: 3904
+    - name: https
+      protocol: TCP
+      port: 3905
+  selector:
+    app: dmaap-mr
+---
+apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
+kind: Deployment
+metadata:
+  name: message-generator
+  namespace: nonrtric
+  labels:
+    app: message-generator
+spec:
+  selector:
+    matchLabels:
+      app: message-generator
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: message-generator
+    spec:
+      containers:
+      - name: message-generator
+        image: message-generator
+        imagePullPolicy: IfNotPresent
+        env:
+        - name: MR-HOST
+          value: http://dmaap-mr
+        - name: MR-PORT
+          value: "3904"
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: message-generator
+  namespace: nonrtric
+  labels:
+    app: message-generator
+spec:
+  # type: ClusterIP
+  ports:
+    - protocol: TCP
+      port: 80
+  selector:
+    app: message-generator
+---
+apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
+kind: Deployment
+metadata:
+  name: sdnr-simulator
+  namespace: nonrtric
+  labels:
+    app: sdnr-simulator
+spec:
+  selector:
+    matchLabels:
+      app: sdnr-simulator
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: sdnr-simulator
+    spec:
+      containers:
+      - name: sdnr-simulator
+        image: sdnr-simulator
+        imagePullPolicy: IfNotPresent
+        ports:
+        - name: tcp
+          containerPort: 9990
+        env:
+        - name: MR-HOST
+          value: http://dmaap-mr
+        - name: MR-PORT
+          value: "3904"
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: sdnr-simulator
+  namespace: nonrtric
+  labels:
+    app: sdnr-simulator
+spec:
+  type: ClusterIP
+  ports:
+    - protocol: TCP
+      port: 9990
+  selector:
+    app: sdnr-simulator
+---
+apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
+kind: Deployment
+metadata:
+  name: oru-app
+  namespace: nonrtric
+  labels:
+    app: oru-app
+spec:
+  selector:
+    matchLabels:
+      app: oru-app
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: oru-app
+    spec:
+      containers:
+      - name: oru-app
+        image: oru-app
+        imagePullPolicy: IfNotPresent
+        env:
+        - name: MR-HOST
+          value: http://dmaap-mr
+        - name: MR-PORT
+          value: "3904"
+        - name: SDNR-HOST
+          value: http://sdnr-simulator
+        - name: SDNR-PORT
+          value: "9990"
+        - name: VERBOSE
+          value: "on"
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: oru-app
+  namespace: nonrtric
+  labels:
+    app: oru-app
+spec:
+  # type: ClusterIP
+  ports:
+    - protocol: TCP
+      port: 80
+  selector:
+    app: oru-app
\ No newline at end of file
diff --git a/scriptversion/k8s/start.sh b/scriptversion/k8s/start.sh
new file mode 100644 (file)
index 0000000..0bedbd9
--- /dev/null
@@ -0,0 +1,42 @@
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
+cd ${SHELL_FOLDER}
+kubectl delete -f linkfailure.yml
+
+# be careful if other stopped containers are on the same system
+docker stop $(docker ps -aq)
+docker system prune -f
+
+# build o-ru application image
+cd ${SHELL_FOLDER}/../app/
+docker build -t oru-app .
+
+# build simulator image of sdnr
+cd ${SHELL_FOLDER}/../simulators/
+docker build -f Dockerfile-sdnr-sim -t sdnr-simulator .
+
+# build message generator image
+docker build -f Dockerfile-message-generator -t message-generator .
+
+# build dmaap-mr sim
+cd ${SHELL_FOLDER}/../../../../mrstub/
+docker build -t mrstub .
+
+# apply k8s yaml file
+cd ${SHELL_FOLDER}
+kubectl apply -f linkfailure.yml
\ No newline at end of file
diff --git a/scriptversion/simulators/Dockerfile-message-generator b/scriptversion/simulators/Dockerfile-message-generator
new file mode 100644 (file)
index 0000000..841cf7f
--- /dev/null
@@ -0,0 +1,32 @@
+#  ============LICENSE_START===============================================
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+
+FROM python:3.8-slim-buster
+
+COPY . /usr/src/app/
+
+WORKDIR /usr/src/app
+
+## install curl & ping to help debug
+RUN apt update
+RUN apt install curl -y
+RUN apt-get install iputils-ping -y
+
+RUN pip install -r requirements.txt
+
+CMD [ "python3", "-u", "message_generator.py" ]
diff --git a/scriptversion/simulators/Dockerfile-sdnr-sim b/scriptversion/simulators/Dockerfile-sdnr-sim
new file mode 100644 (file)
index 0000000..4275b17
--- /dev/null
@@ -0,0 +1,32 @@
+#  ============LICENSE_START===============================================
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+
+FROM python:3.8-slim-buster
+
+COPY . /usr/src/app/
+
+WORKDIR /usr/src/app
+
+## install curl & ping to help debug
+RUN apt update
+RUN apt install curl -y
+RUN apt-get install iputils-ping -y
+
+RUN pip install -r requirements.txt
+
+CMD [ "python3", "-u", "sdnr_simulator.py" ]
diff --git a/scriptversion/simulators/message_generator.py b/scriptversion/simulators/message_generator.py
new file mode 100644 (file)
index 0000000..8550133
--- /dev/null
@@ -0,0 +1,127 @@
+
+#  ============LICENSE_START===============================================
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+import json
+import os
+import random
+import requests
+import time
+
+# Randomly, between 0 and 10 seconds sends a "CUS Link Failure" alarm event to the Message Router. The ID of the O-RU is also
+# randomly generated between 0 and 9.
+# When the modulo of the ID is 1, a "heartbeat" message will also be sent to MR.
+
+mr_host = "http://localhost"
+mr_port = "3904"
+MR_PATH = "/events/unauthenticated.SEC_FAULT_OUTPUT"
+FAULT_ID = "28"
+
+linkFailureMessage = {
+    "event": {
+        "commonEventHeader": {
+            "domain": "fault",
+            "eventId": "nt:network-topology/nt:topology/nt:node/nt:node-id",
+            "eventName": "fault_O-RAN-RU-Fault_Alarms_CUS_Link_Failure",
+            "eventType": "O-RAN-RU-Fault",
+            "sequence": 0,
+            "priority": "Normal",
+            "reportingEntityId": "SDNR",
+            "reportingEntityName": "@controllerName@",
+            "sourceId": "",
+            "sourceName": "O-RU-ID",
+            "startEpochMicrosec": "@timestamp@",
+            "lastEpochMicrosec": "@timestamp@",
+            "nfNamingCode": "",
+            "nfVendorName": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-name",
+            "timeZoneOffset": "+00:00",
+            "version": "4.1",
+            "vesEventListenerVersion": "7.2.1"
+        },
+        "faultFields": {
+            "faultFieldsVersion": "4.0",
+            "alarmCondition": FAULT_ID,
+            "alarmInterfaceA": "o-ran-fm:alarm-notif/fault-source",
+            "eventSourceType": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-model or \"O-RU\"",
+            "specificProblem": "",
+            "eventSeverity": "CRITICAL",
+            "vfStatus": "Active",
+            "alarmAdditionalInformation": {
+                "eventTime": "@eventTime@",
+                "equipType": "@type@",
+                "vendor": "@vendor@",
+                "model": "@model@"
+            }
+        }
+    }
+}
+
+heartBeatMessage = {
+   "event": {
+     "commonEventHeader": {
+       "version": 3.0,
+       "domain": "heartbeat",
+       "eventName": "Heartbeat\_vIsbcMmc",
+       "eventId": "ab305d54-85b4-a31b-7db2fb6b9e546015",
+       "sequence": 0,
+       "priority": "Normal",
+       "reportingEntityId": "cc305d54-75b4-431badb2eb6b9e541234",
+       "reportingEntityName": "EricssonOamVf",
+       "sourceId": "de305d54-75b4-431b-adb2-eb6b9e546014",
+       "sourceName": "ibcx0001vm002ssc001",
+       "nfNamingCode": "ibcx",
+       "nfcNamingCode": "ssc",
+       "startEpochMicrosec": 1413378172000000,
+       "lastEpochMicrosec": 1413378172000000
+      }
+   }
+ }
+
+
+def sendPostRequest(url, msg):
+    try:
+        requests.post(url, json=msg)
+    except Exception as e:
+        print(type(e))
+        print(e.args)
+        print(e)
+
+
+if __name__ == "__main__":
+    if os.getenv("MR-HOST") is not None:
+        mr_host = os.getenv("MR-HOST")
+        print("Using MR Host from os: " + mr_host)
+    if os.getenv("MR-PORT") is not None:
+        mr_port = os.getenv("MR-PORT")
+        print("Using MR Port from os: " + mr_port)
+
+    mr_url = mr_host + ":" + mr_port + MR_PATH
+    print(mr_url)
+    while True:
+        random_time = int(10 * random.random())
+        if (random_time % 3 == 1):
+            print("Sent heart beat")
+            sendPostRequest(mr_url, heartBeatMessage)
+
+        o_ru_id = "ERICSSON-O-RU-1122" + str(random_time)
+        print("Sent link failure for O-RAN-RU: " + o_ru_id)
+        msg_as_json = json.loads(json.dumps(linkFailureMessage))
+        msg_as_json["event"]["commonEventHeader"]["sourceName"] = o_ru_id
+        sendPostRequest(mr_url, msg_as_json)
+
+        time.sleep(random_time)
+
diff --git a/scriptversion/simulators/requirements.txt b/scriptversion/simulators/requirements.txt
new file mode 100644 (file)
index 0000000..589d97a
--- /dev/null
@@ -0,0 +1,12 @@
+certifi==2020.12.5
+chardet==4.0.0
+click==7.1.2
+Flask==1.1.2
+Flask-HTTPAuth==4.4.0
+idna==2.10
+itsdangerous==1.1.0
+Jinja2==2.11.3
+MarkupSafe==1.1.1
+requests==2.25.1
+urllib3==1.26.4
+Werkzeug==1.0.1
\ No newline at end of file
diff --git a/scriptversion/simulators/sdnr_simulator.py b/scriptversion/simulators/sdnr_simulator.py
new file mode 100644 (file)
index 0000000..a44c073
--- /dev/null
@@ -0,0 +1,138 @@
+
+#  ============LICENSE_START===============================================
+#  Copyright (C) 2021 Nordix Foundation. All rights reserved.
+#  ========================================================================
+#  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.
+#  ============LICENSE_END=================================================
+#
+
+from flask import Flask
+from flask import Response
+from flask_httpauth import HTTPBasicAuth
+import json
+import os
+import random
+import requests
+import threading
+import time
+
+# Provides an endpoint for the "UNLOCK" configuration change for an O-DU.
+# Stores the ID of the O-DU and randomly, after between 0 and 10 seconds, sends an Alarm Notification that clears the
+# "CUS Link Failure" alarm event to MR.
+app = Flask(__name__)
+auth = HTTPBasicAuth()
+
+mr_host = "http://localhost"
+mr_port = "3904"
+MR_PATH = "/events/unauthenticated.SEC_FAULT_OUTPUT"
+
+# Server info
+HOST_IP = "::"
+HOST_PORT = 9990
+APP_URL = "/rests/data/network-topology:network-topology/topology=topology-netconf/node=<string:o_du_id>/yang-ext:mount/o-ran-sc-du-hello-world:network-function/distributed-unit-functions=<string:o_du_id2>/radio-resource-management-policy-ratio=rrm-pol-1"
+
+USERNAME = "admin"
+PASSWORD = "Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U"
+
+FAULT_ID = "28"
+
+linkFailureMessage = {
+    "event": {
+        "commonEventHeader": {
+            "domain": "fault",
+            "eventId": "nt:network-topology/nt:topology/nt:node/nt:node-id",
+            "eventName": "fault_O-RAN-RU-Fault_Alarms_CUS_Link_Failure",
+            "eventType": "O-RAN-RU-Fault_Alarms",
+            "sequence": 0,
+            "priority": "High",
+            "reportingEntityId": "SDNR",
+            "reportingEntityName": "",
+            "sourceId": "",
+            "sourceName": "oru1",
+            "startEpochMicrosec": "@timestamp@",
+            "lastEpochMicrosec": "@timestamp@",
+            "nfNamingCode": "",
+            "nfVendorName": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-name",
+            "timeZoneOffset": "+00:00",
+            "version": "4.1",
+            "vesEventListenerVersion": "7.2.1"
+        },
+        "faultFields": {
+            "faultFieldsVersion": "4.0",
+            "alarmCondition": FAULT_ID,
+            "alarmInterfaceA": "o-ran-fm:alarm-notif/fault-source",
+            "eventSourceType": "ietf-hardware (RFC8348) /hardware/component[not(parent)][1]/mfg-model or \"O-RU\"",
+            "specificProblem": "",
+            "eventSeverity": "NORMAL",
+            "vfStatus": "Active",
+            "alarmAdditionalInformation": {
+                "eventTime": "@eventTime@",
+                "equipType": "@type@",
+                "vendor": "@vendor@",
+                "model": "@model@"
+            }
+        }
+    }
+}
+
+
+class AlarmClearThread (threading.Thread):
+
+    def __init__(self, sleep_time, o_du_id):
+        threading.Thread.__init__(self)
+        self.sleep_time = sleep_time
+        self.o_du_id = o_du_id
+
+    def run(self):
+        print(f'Sleeping: {self.sleep_time} before clearing O-DU: {self.o_du_id}')
+        time.sleep(self.sleep_time)
+        msg_as_json = json.loads(json.dumps(linkFailureMessage))
+        msg_as_json["event"]["commonEventHeader"]["sourceName"] = self.o_du_id
+        print("Sedning alarm clear for O-DU: " + self.o_du_id)
+        requests.post(mr_host + ":" + mr_port + MR_PATH, json=msg_as_json);
+
+
+# I'm alive function
+@app.route('/',
+    methods=['GET'])
+def index():
+    return 'OK', 200
+
+
+@auth.verify_password
+def verify_password(username, password):
+    if username == USERNAME and password == PASSWORD:
+        return username
+
+
+@app.route(APP_URL,
+    methods=['PUT'])
+@auth.login_required
+def sendrequest(o_du_id, o_du_id2):
+    print("Got request with O-DU ID: " + o_du_id)
+    random_time = int(10 * random.random())
+    alarm_clear_thread = AlarmClearThread(random_time, o_du_id)
+    alarm_clear_thread.start()
+
+    return Response(status=200)
+
+
+if __name__ == "__main__":
+    if os.getenv("MR-HOST") is not None:
+        mr_host = os.getenv("MR-HOST")
+        print("Using MR Host from os: " + mr_host)
+    if os.getenv("MR-PORT") is not None:
+        mr_port = os.getenv("MR-PORT")
+        print("Using MR Port from os: " + mr_port)
+
+    app.run(port=HOST_PORT, host=HOST_IP)