added new vths(smo,a1-mediator,dmaap)
authorjv246a.oran <jv246a@att.com>
Tue, 5 May 2020 19:37:02 +0000 (15:37 -0400)
committerChen, Jackie <jv246a@att.com>
Wed, 6 May 2020 16:31:05 +0000 (12:31 -0400)
updated smo_vth name to o1_vth and updated it's files to reflect the change

Change-Id: Iaa130354b6149d830897ae56de7c34eef67e09da
Signed-off-by: Chen, Jackie <jv246a@att.com>
38 files changed:
a1-mediator-vth/Dockerfile [new file with mode: 0644]
a1-mediator-vth/Jenkinsfile [new file with mode: 0644]
a1-mediator-vth/a1-mediator-vth.py [new file with mode: 0644]
a1-mediator-vth/a1_mock_server/index.js [new file with mode: 0644]
a1-mediator-vth/a1_mock_server/package-lock.json [new file with mode: 0644]
a1-mediator-vth/a1_mock_server/package.json [new file with mode: 0644]
a1-mediator-vth/config.json [new file with mode: 0644]
a1-mediator-vth/doc/a1-documentation.docx [new file with mode: 0644]
a1-mediator-vth/helm/a1-mediator-vth/.helmignore [new file with mode: 0644]
a1-mediator-vth/helm/a1-mediator-vth/Chart.yaml [new file with mode: 0644]
a1-mediator-vth/helm/a1-mediator-vth/templates/deployment.yaml [new file with mode: 0644]
a1-mediator-vth/helm/a1-mediator-vth/templates/service.yaml [new file with mode: 0644]
a1-mediator-vth/helm/a1-mediator-vth/values.yaml [new file with mode: 0644]
a1-mediator-vth/pip-requirements.txt [new file with mode: 0644]
dmaap-vth/Dockerfile [new file with mode: 0644]
dmaap-vth/Jenkinsfile [new file with mode: 0644]
dmaap-vth/config.ini [new file with mode: 0644]
dmaap-vth/dmaap_vth.py [new file with mode: 0644]
dmaap-vth/doc/dmaap-documentation.docx [new file with mode: 0644]
dmaap-vth/helm/dmaap-vth/.helmignore [new file with mode: 0644]
dmaap-vth/helm/dmaap-vth/Chart.yaml [new file with mode: 0644]
dmaap-vth/helm/dmaap-vth/templates/deployment.yaml [new file with mode: 0644]
dmaap-vth/helm/dmaap-vth/templates/secret.yaml [new file with mode: 0644]
dmaap-vth/helm/dmaap-vth/templates/service.yaml [new file with mode: 0644]
dmaap-vth/helm/dmaap-vth/values.yaml [new file with mode: 0644]
dmaap-vth/pip-requirements.txt [new file with mode: 0644]
o1-vth/Doc/o1-documentation.docx [new file with mode: 0644]
o1-vth/Dockerfile [new file with mode: 0644]
o1-vth/Jenkinsfile [new file with mode: 0644]
o1-vth/config.ini [new file with mode: 0644]
o1-vth/helm/o1-vth/.helmignore [new file with mode: 0644]
o1-vth/helm/o1-vth/Chart.yaml [new file with mode: 0644]
o1-vth/helm/o1-vth/templates/deployment.yaml [new file with mode: 0644]
o1-vth/helm/o1-vth/templates/secret.yaml [new file with mode: 0644]
o1-vth/helm/o1-vth/templates/service.yaml [new file with mode: 0644]
o1-vth/helm/o1-vth/values.yaml [new file with mode: 0644]
o1-vth/o1_vth.py [new file with mode: 0644]
o1-vth/pip-requirements.txt [new file with mode: 0644]

diff --git a/a1-mediator-vth/Dockerfile b/a1-mediator-vth/Dockerfile
new file mode 100644 (file)
index 0000000..e708483
--- /dev/null
@@ -0,0 +1,13 @@
+FROM python:3.7.4\r
+\r
+RUN python --version\r
+\r
+ADD pip-requirements.txt pip-requirements.txt\r
+ADD a1-mediator-vth.py a1-mediator-vth.py\r
+ADD config.json config.json\r
+\r
+RUN mkdir -p /otf/logs\r
+\r
+RUN python -m pip install --proxy -r pip-requirements.txt\r
+\r
+ENTRYPOINT ["python", "a1-mediator-vth.py"]\r
diff --git a/a1-mediator-vth/Jenkinsfile b/a1-mediator-vth/Jenkinsfile
new file mode 100644 (file)
index 0000000..a58148c
--- /dev/null
@@ -0,0 +1,156 @@
+#!/usr/bin/env groovy\r
+\r
+/*  Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+##############################################################################*/\r
+\r
+properties([[$class: 'ParametersDefinitionProperty', parameterDefinitions: [\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'PHASE', defaultValue: "BUILD"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'ENV', defaultValue: "dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'MECHID', defaultValue: "id_otf_dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'KUBE_CONFIG', defaultValue: "kubeConfig-dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'TILLER_NAMESPACE', defaultValue: "registry.hub.docker.io"]\r
+]]])\r
+\r
+\r
+echo "Build branch: ${env.BRANCH_NAME}"\r
+\r
+node("docker"){\r
+       stage 'Checkout'\r
+       checkout scm\r
+       PHASES=PHASE.tokenize( '_' );\r
+       echo "PHASES : " + PHASES\r
+\r
+\r
+       ARTIFACT_ID="a1-mediator-vth";\r
+       VERSION="0.0.1-SNAPSHOT";\r
+       NAMESPACE="org-oran-otf"\r
+       DOCKER_REGISTRY="registry.hub.docker.io"\r
+\r
+  if( ENV.equalsIgnoreCase("dev") ){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".dev" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+  if( ENV.equalsIgnoreCase("prod") || ENV.equalsIgnoreCase("prod-dr")){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".prod" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+\r
+  if( ENV.equalsIgnoreCase("st") ){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".st" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+\r
+       echo "Artifact: " + IMAGE_NAME\r
+\r
+       withEnv(["PATH=${env.PATH}:${env.WORKSPACE}/linux-amd64", "HELM_HOME=${env.WORKSPACE}"]) {\r
+\r
+               echo "PATH=${env.PATH}"\r
+               echo "HELM_HOME=${env.HELM_HOME}"\r
+\r
+               if (PHASES.contains("BUILD")){\r
+\r
+                       stage 'Publish Artifact'\r
+\r
+                               withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {\r
+                                       dir("smo-vth") {\r
+                                               echo "Artifact: " + IMAGE_NAME\r
+\r
+                                               sh """\r
+                                                       docker login $DOCKER_REGISTRY --username $USERNAME --password $PASSWORD\r
+                                                       docker build -t $IMAGE_NAME .\r
+                                                       docker push $IMAGE_NAME\r
+                                               """\r
+                                       }\r
+                               }\r
+\r
+               }\r
+\r
+               if (PHASES.contains("DEPLOY") || PHASES.contains("UNDEPLOY")) {\r
+\r
+                       stage 'Init Helm'\r
+\r
+                       //check if helm exists if not install\r
+                       if(fileExists('linux-amd64/helm')){\r
+                               sh """\r
+                                       echo "helm is already installed"\r
+                               """\r
+                       }\r
+                       else{\r
+                       //download helm\r
+                               sh """\r
+                                       echo "installing helm"\r
+                                       wget  https://storage.googleapis.com/kubernetes-helm/helm-v2.14.3-linux-amd64.tar.gz\r
+                                       tar -xf helm-v2.14.3-linux-amd64.tar.gz\r
+                                       rm helm-v2.14.3-linux-amd64.tar.gz\r
+                               """\r
+                       }\r
+\r
+                       withCredentials([file(credentialsId: KUBE_CONFIG, variable: 'KUBECONFIG')]) {\r
+\r
+                               dir('a1-mediator-vth/helm'){\r
+                               //check if charts are valid, and then perform dry run, if successful then upgrade/install charts\r
+\r
+                                       if (PHASES.contains("UNDEPLOY") ) {\r
+                                               stage 'Undeploy'\r
+\r
+                                               sh """\r
+                                                       helm delete --tiller-namespace=$TILLER_NAMESPACE --purge $ARTIFACT_ID\r
+                                               """\r
+                                       }\r
+\r
+                               //NOTE Double quotes are used below to access groovy variables like artifact_id and tiller_namespace\r
+                       if (PHASES.contains("DEPLOY") ){\r
+                               stage 'Deploy'\r
+                                                       withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {\r
+\r
+                                                               sh """\r
+                                                                   helm version\r
+                                                                       echo "Validate Yaml"\r
+                                                                       helm lint $ARTIFACT_ID\r
+\r
+                                                                       echo "View Helm Templates"\r
+                                                                       helm template $ARTIFACT_ID --set appName=$ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION  \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE\r
+\r
+                                                                       echo "Perform Dry Run Of Install"\r
+                                                                       helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install --dry-run $ARTIFACT_ID $ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE\r
+\r
+                                                                       echo "Helm Install/Upgrade"\r
+                                                               helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install $ARTIFACT_ID $ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE\r
+\r
+                                                               """\r
+                                                       }\r
+                       }\r
+\r
+                               }\r
+                       }\r
+       }\r
+\r
+       }\r
+}\r
diff --git a/a1-mediator-vth/a1-mediator-vth.py b/a1-mediator-vth/a1-mediator-vth.py
new file mode 100644 (file)
index 0000000..e0269b1
--- /dev/null
@@ -0,0 +1,198 @@
+#   Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+################################################################################\r
+# File name: a1-mediator-vth.py                                                         #\r
+# Description: vth for a1-mediator-vth service                                              #\r
+# Date created: 08/22/2019                                                     #\r
+# Last modified: 04/02/2020                                                    #\r
+# Python Version: 3.7.4                                                        #\r
+# Author: Jackie Chen (jv246a)                                                 #\r
+# Email: jv246a@att.com                                                        #\r
+################################################################################\r
+import datetime\r
+import json\r
+import logging\r
+from logging import FileHandler\r
+import os\r
+\r
+import requests\r
+from flask import Flask, request, jsonify\r
+\r
+# redirect http to https\r
+app = Flask(__name__)\r
+\r
+# Prevents print statement every time an endpoint is triggered.\r
+logging.getLogger("werkzeug").setLevel(logging.WARNING)\r
+\r
+\r
+def sendCallback(url, data):\r
+    try:\r
+        if type(data) is not dict:\r
+            data = {"msg": data}\r
+        app.logger.info("sending callback")\r
+        requests.post(url, json=data)\r
+    except Exception as e:\r
+        app.logger.info(e)\r
+    return\r
+\r
+def unix_time_millis(dt):\r
+    epoch = datetime.datetime.utcfromtimestamp(0)\r
+    return (dt - epoch).total_seconds() * 1000.0\r
+\r
+\r
+@app.route("/otf/vth/oran/a1/v1/health", methods=['GET'])\r
+def getHealth():\r
+    return "UP"\r
+\r
+\r
+@app.route("/otf/vth/oran/a1/v1", methods=['POST'])\r
+def executeRicRequest():\r
+    response_data = {\r
+        'vthResponse': {\r
+            'testDuration': '',\r
+            'dateTimeUTC': str(datetime.datetime.now()),\r
+            'abstractMessage': '',\r
+            'resultData': {}\r
+        }\r
+    }\r
+\r
+    startTime = unix_time_millis(datetime.datetime.now())\r
+    ret_url = request.args.get('retURL')\r
+    try:\r
+        if not request.is_json:\r
+            raise ValueError("request must be json")\r
+\r
+        requestData = request.get_json()\r
+\r
+        app.logger.info("A1 requestData:" + str(requestData))\r
+\r
+        action = requestData['action'].lower()\r
+        _check_incoming_request(requestData)\r
+\r
+        os.environ['NO_PROXY'] = '127.0.0.1'  # TODO testing purpose w/ mock server. Needs to remove on final version\r
+        with open('config.json') as configFile:\r
+            config = json.load(configFile)\r
+\r
+        baseAddress = config['base_address']\r
+        if action == 'health_check' or action == 'list_policy':\r
+            res = requests.get(baseAddress + config['actions_path'][action])\r
+            response_data['vthResponse']['resultData']['statusCode'] = res.status_code\r
+            if action == 'health_check':\r
+                response_data['vthResponse']['resultData']['resultOutput'] = res.text\r
+            else:\r
+                response_data['vthResponse']['resultData']['resultOutput'] = res.json()\r
+        elif action == 'list_policy_instance':\r
+            res = requests.get(baseAddress + config['actions_path'][action]\r
+                               .format(policy_type_id=requestData['policy_type_id']))\r
+            response_data['vthResponse']['resultData']['statusCode'] = res.status_code\r
+            response_data['vthResponse']['resultData']['resultOutput'] = res.json()\r
+        elif action == 'get_policy_instance_status':\r
+            res = requests.get(baseAddress + config['actions_path'][action]\r
+                               .format(policy_type_id=requestData['policy_type_id'],\r
+                                       policy_instance_id=requestData['policy_instance_id']))\r
+            response_data['vthResponse']['resultData']['statusCode'] = res.status_code\r
+            response_data['vthResponse']['resultData']['resultOutput'] = res.json()\r
+        elif action == 'edit_policy':\r
+            res = _send_edit_request(requestData, config)\r
+            response_data['vthResponse']['resultData']['statusCode'] = res.status_code\r
+            if requestData['request_type'].lower() == 'get' and res.status_code == 200:\r
+                response_data['vthResponse']['resultData']['resultOutput'] = res.json()\r
+            else:\r
+                response_data['vthResponse']['resultData']['resultOutput'] = res.text\r
+        elif action == 'edit_policy_instance':\r
+            res = _send_edit_request(requestData, config)\r
+            response_data['vthResponse']['resultData']['statusCode'] = res.status_code\r
+            if requestData['request_type'].lower() == 'get' and res.status_code == 200:\r
+                response_data['vthResponse']['resultData']['resultOutput'] = res.json()\r
+            else:\r
+                response_data['vthResponse']['resultData']['resultOutput'] = res.text\r
+\r
+    except Exception as ex:\r
+        endTime = unix_time_millis(datetime.datetime.now())\r
+        totalTime = endTime - startTime\r
+        response_data['vthResponse']['testDuration'] = totalTime\r
+        response_data['vthResponse']['abstractMessage'] = str(ex)\r
+        return jsonify(response_data)\r
+\r
+    endTime = unix_time_millis(datetime.datetime.now())\r
+    totalTime = endTime - startTime\r
+\r
+    response_data['vthResponse']['testDuration'] = totalTime\r
+\r
+    if ret_url is not None:\r
+        sendCallback(ret_url, response_data)\r
+        return '', 200\r
+\r
+    return jsonify(response_data), 200\r
+\r
+\r
+def _send_edit_request(request_data, config):\r
+    baseAddress = config['base_address']\r
+    path = ''\r
+    action = request_data['action']\r
+    policy_type_id = request_data['policy_type_id']\r
+    request_type = request_data['request_type']\r
+    if action == "edit_policy":\r
+        path = baseAddress + config['actions_path'][action].format(policy_type_id=policy_type_id)\r
+    if action == 'edit_policy_instance':\r
+        instance_id = request_data['policy_instance_id']\r
+        path = baseAddress + config['actions_path'][action].format(policy_type_id=policy_type_id,\r
+                                                                   policy_instance_id=instance_id)\r
+    if request_type == 'get':\r
+        return requests.get(path)\r
+    if request_type == 'put':\r
+        payload = request_data['payload']\r
+        return requests.put(path, payload)\r
+    if request_type == 'delete':\r
+        return requests.delete(path)\r
+\r
+\r
+def _check_incoming_request(requestData):  # check if the request is valid\r
+    if 'action' not in requestData:\r
+        raise KeyError('no action was specify')\r
+\r
+    action = requestData['action'].lower()\r
+    edit_actions = ['edit_policy', 'edit_policy_instance']\r
+    requires_policy_id = ['edit_policy', 'list_policy_instance'\r
+        , 'edit_policy_instance', 'get_policy_instance_status']\r
+    requires_policy_instance_id = ['edit_policy_instance', 'get_policy_instance_status']\r
+    possible_actions = ['health_check', 'list_policy', 'edit_policy', 'list_policy_instance'\r
+        , 'edit_policy_instance', 'get_policy_instance_status']\r
+    possible_request_type = ['get', 'put', 'delete']\r
+\r
+    if action not in possible_actions:\r
+        raise KeyError("invalid action")\r
+    if action in edit_actions:  # request type is required\r
+        if 'request_type' not in requestData:\r
+            raise KeyError('this action: ' + action + ' requires a request type')\r
+        if requestData['request_type'] not in possible_request_type:\r
+            raise KeyError('this request_type: ' + requestData['request_type'] + ' is not valid')\r
+        if requestData['request_type'] == 'put' and 'payload' not in requestData:\r
+            raise KeyError('put request requires a payload')\r
+    if action in requires_policy_id:\r
+        if 'policy_type_id' not in requestData:\r
+            raise KeyError('this action: ' + action + ' requires a policy_type_id')\r
+    if action in requires_policy_instance_id:\r
+        if 'policy_instance_id' not in requestData:\r
+            raise KeyError('this action: ' + action + ' requires a policy_instance_id')\r
+\r
+\r
+if __name__ == '__main__':\r
+    logHandler = FileHandler('a1-mediator-vth.log', mode='a')\r
+    logHandler.setLevel(logging.INFO)\r
+    app.logger.setLevel(logging.INFO)\r
+    app.logger.addHandler(logHandler)\r
+    # context = ('opt/cert/otf.pem', 'opt/cert/privateKey.pem')\r
+    # app.run(debug = False, host = '0.0.0.0', port = 5000, ssl_context = context)\r
+    app.run(debug=False, host='0.0.0.0', port=5000)\r
diff --git a/a1-mediator-vth/a1_mock_server/index.js b/a1-mediator-vth/a1_mock_server/index.js
new file mode 100644 (file)
index 0000000..5830d11
--- /dev/null
@@ -0,0 +1,80 @@
+const express = require('express')\r
+const app = express()\r
+const port = 3000\r
+\r
+app.use(express.json())\r
+\r
+app.get('/', (req, res) => res.send('Hello World!'))\r
+\r
+app.get('/a1-p/healthcheck',function(req,res){\r
+    console.log("health checking")\r
+    res.sendStatus(200)\r
+})\r
+\r
+app.get('/a1-p/policytypes',function(req,res){\r
+    res.status=(200)\r
+    res.send([20000, 20020])\r
+})\r
+\r
+app.get('/a1-p/policytypes/:policy_type_id',function(req,res){\r
+    res.status=(200)\r
+    policy_type_id = req.params['policy_type_id']\r
+    res.send({"name": "example policy instance","description":"fake description","policy_type_id": policy_type_id,"create_schema":"{name:sample object}"})\r
+})\r
+app.delete('/a1-p/policytypes/:policy_type_id',function(req,res){\r
+    res.sendStatus(204)\r
+})\r
+\r
+app.put('/a1-p/policytypes/:policy_type_id',function(req,res){\r
+    console.log(req.body)\r
+    res.sendStatus(201)\r
+})\r
+\r
+app.get('/a1-p/policytypes/:policy_type_id/policies',function(req,res){\r
+    console.log('listing policies')\r
+    res.status=(200)\r
+    res.send(["3d2157af-6a8f-4a7c-810f-38c2f824bf12", "06911bfc-c127-444a-8eb1-1bffad27cc3d"])\r
+})\r
+\r
+app.get('/a1-p/policytypes/:policy_type_id/policies/:policy_instance_id',function(req,res){\r
+    res.status=(200)\r
+    policy_type_id = req.params['policy_type_id']\r
+    policy_instance_id = req.params['policy_instance_id']\r
+    res.send({"name": "example policy instance","description":"fake description","policy_type_id": policy_type_id,"create_schema":"{name:sample object}"})\r
+})\r
+app.delete('/a1-p/policytypes/:policy_type_id/policies/:policy_instance_id',function(req,res){\r
+    res.sendStatus(202)\r
+})\r
+\r
+app.put('/a1-p/policytypes/:policy_type_id/policies/:policy_instance_id',function(req,res){\r
+    console.log(req.body)\r
+    res.sendStatus(202)\r
+})\r
+\r
+app.get('/a1-p/policytypes/:policy_type_id/policies/:policy_instance_id/status',function(req,res){\r
+    res.status(200)\r
+    res.send({"properties":{"instance_status": "fake status","enum": "IN EFFECT"}})\r
+})\r
+\r
+\r
+\r
+\r
+\r
+\r
+app.get('/appmgr/ric/v1/xapps',function(req,res){\r
+    res.status(200)\r
+    res.send([{"name":"admin-xapp","status":"deployed","version":"1.0","instances":null},{"name":"mcxapp","status":"deployed","version":"1.0","instances":[{"name":"mcxapp-649d7494-h5tjb","status":"running","ip":"service-ricxapp-mcxapp-rmr.ricxapp","port":4560,"txMessages":null,"rxMessages":["RIC_SUB_RESP","RIC_SUB_FAILURE","RIC_SUB_DEL_RESP","RIC_SUB_DEL_FAILURE","RIC_INDICATION"]}]},{"name":"ueec","status":"deployed","version":"1.0","instances":[{"name":"ueec-6675694b75-jtnz6","status":"running","ip":"service-ricxapp-ueec-rmr.ricxapp","port":4560,"txMessages":["RIC_SUB_REQ","RIC_SUB_DEL_REQ"],"rxMessages":["RIC_SUB_RESP","RIC_SUB_FAILURE","RIC_SUB_DEL_RESP","RIC_SUB_DEL_FAILURE","RIC_INDICATION"]}]}])\r
+})\r
+\r
+app.post('/appmgr/ric/v1/xapps', function(req,res){\r
+    res.statusMessage = 'Created'\r
+    res.status(201)\r
+    res.send({"result_output":{"name":"anr","status":"deployed","version":"1.0","instances":[{"name":"anr-7d4c47b4bb-jlslm","status":"running","ip":"service-ricxapp-anr-rmr.ricxapp","port":4560,"txMessages":null,"rxMessages":["RIC_SGNB_ADDITION_REQ","RIC_RRC_TRANSFER"]}]}})\r
+})\r
+\r
+app.delete('/appmgr/ric/v1/xapps/:name',function(req,res){\r
+    res.sendStatus(204)\r
+})\r
+\r
+app.listen(port, () => console.log(`Example app listening on port ${port}!`))\r
+\r
diff --git a/a1-mediator-vth/a1_mock_server/package-lock.json b/a1-mediator-vth/a1_mock_server/package-lock.json
new file mode 100644 (file)
index 0000000..3877b38
--- /dev/null
@@ -0,0 +1,374 @@
+{
+  "name": "a1_mock_server",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "accepts": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+      "requires": {
+        "mime-types": "~2.1.24",
+        "negotiator": "0.6.2"
+      }
+    },
+    "array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+    },
+    "body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+      "requires": {
+        "bytes": "3.1.0",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "on-finished": "~2.3.0",
+        "qs": "6.7.0",
+        "raw-body": "2.4.0",
+        "type-is": "~1.6.17"
+      }
+    },
+    "bytes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+      "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+    },
+    "content-disposition": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+      "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+    },
+    "cookie": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+    },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+    },
+    "express": {
+      "version": "4.17.1",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+      "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+      "requires": {
+        "accepts": "~1.3.7",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.19.0",
+        "content-disposition": "0.5.3",
+        "content-type": "~1.0.4",
+        "cookie": "0.4.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "~1.1.2",
+        "fresh": "0.5.2",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.5",
+        "qs": "6.7.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.1.2",
+        "send": "0.17.1",
+        "serve-static": "1.14.1",
+        "setprototypeof": "1.1.1",
+        "statuses": "~1.5.0",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      }
+    },
+    "finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "statuses": "~1.5.0",
+        "unpipe": "~1.0.0"
+      }
+    },
+    "forwarded": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+    },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+    },
+    "http-errors": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+      "requires": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.1",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.0"
+      }
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+    },
+    "ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+    },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+    },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+    },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+    },
+    "mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+    },
+    "mime-db": {
+      "version": "1.43.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
+      "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
+    },
+    "mime-types": {
+      "version": "2.1.26",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
+      "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
+      "requires": {
+        "mime-db": "1.43.0"
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+    },
+    "negotiator": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+    },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+    },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+    },
+    "proxy-addr": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+      "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+      "requires": {
+        "forwarded": "~0.1.2",
+        "ipaddr.js": "1.9.1"
+      }
+    },
+    "qs": {
+      "version": "6.7.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+      "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+    },
+    "range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+    },
+    "raw-body": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+      "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+      "requires": {
+        "bytes": "3.1.0",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "send": {
+      "version": "0.17.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "destroy": "~1.0.4",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "~1.7.2",
+        "mime": "1.6.0",
+        "ms": "2.1.1",
+        "on-finished": "~2.3.0",
+        "range-parser": "~1.2.1",
+        "statuses": "~1.5.0"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+        }
+      }
+    },
+    "serve-static": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+      "requires": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.17.1"
+      }
+    },
+    "setprototypeof": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+    },
+    "statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+    },
+    "toidentifier": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+    },
+    "type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      }
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+    },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+    },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+    }
+  }
+}
diff --git a/a1-mediator-vth/a1_mock_server/package.json b/a1-mediator-vth/a1_mock_server/package.json
new file mode 100644 (file)
index 0000000..8d910e3
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "name": "a1_mock_server",
+  "version": "1.0.0",
+  "description": "mock for a1 ",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "jackie chen (jv246a)",
+  "license": "ISC",
+  "dependencies": {
+    "express": "^4.17.1"
+  }
+}
diff --git a/a1-mediator-vth/config.json b/a1-mediator-vth/config.json
new file mode 100644 (file)
index 0000000..79d9855
--- /dev/null
@@ -0,0 +1,11 @@
+{\r
+  "base_address": "127.0.0.1:3000",\r
+  "actions_path": {\r
+    "health_check": "/a1-p/healthcheck",\r
+    "list_policy": "/a1-p/policytypes",\r
+    "edit_policy": "/a1-p/policytypes/{policy_type_id}",\r
+    "list_policy_instance": "/a1-p/policytypes/{policy_type_id}/policies",\r
+    "edit_policy_instance": "/a1-p/policytypes/{policy_type_id}/policies/{policy_instance_id}",\r
+    "get_policy_instance_status": "/a1-p/policytypes/{policy_type_id}/policies/{policy_instance_id}/status"\r
+   }\r
+}
\ No newline at end of file
diff --git a/a1-mediator-vth/doc/a1-documentation.docx b/a1-mediator-vth/doc/a1-documentation.docx
new file mode 100644 (file)
index 0000000..820dbab
Binary files /dev/null and b/a1-mediator-vth/doc/a1-documentation.docx differ
diff --git a/a1-mediator-vth/helm/a1-mediator-vth/.helmignore b/a1-mediator-vth/helm/a1-mediator-vth/.helmignore
new file mode 100644 (file)
index 0000000..daebc7d
--- /dev/null
@@ -0,0 +1,21 @@
+# Patterns to ignore when building packages.\r
+# This supports shell glob matching, relative path matching, and\r
+# negation (prefixed with !). Only one pattern per line.\r
+.DS_Store\r
+# Common VCS dirs\r
+.git/\r
+.gitignore\r
+.bzr/\r
+.bzrignore\r
+.hg/\r
+.hgignore\r
+.svn/\r
+# Common backup files\r
+*.swp\r
+*.bak\r
+*.tmp\r
+*~\r
+# Various IDEs\r
+.project\r
+.idea/\r
+*.tmproj\r
diff --git a/a1-mediator-vth/helm/a1-mediator-vth/Chart.yaml b/a1-mediator-vth/helm/a1-mediator-vth/Chart.yaml
new file mode 100644 (file)
index 0000000..a16372a
--- /dev/null
@@ -0,0 +1,5 @@
+apiVersion: v1\r
+appVersion: "1.0"\r
+description: A Helm chart for the a1 mediator Virtual Test Head\r
+name: a1-mediator-vth\r
+version: 0.0.1\r
diff --git a/a1-mediator-vth/helm/a1-mediator-vth/templates/deployment.yaml b/a1-mediator-vth/helm/a1-mediator-vth/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..afb1dec
--- /dev/null
@@ -0,0 +1,113 @@
+apiVersion: extensions/v1beta1\r
+kind: Deployment\r
+metadata:\r
+  name: {{ .Values.appName}}\r
+  namespace: {{.Values.namespace}}\r
+  labels:\r
+    app: {{ .Values.appName}}\r
+    version: {{.Values.version}}\r
+spec:\r
+  revisionHistoryLimit: 1\r
+  minReadySeconds: 10\r
+  strategy:\r
+  # indicate which strategy we want for rolling update\r
+    type: RollingUpdate\r
+    rollingUpdate:\r
+      maxSurge: 0\r
+      maxUnavailable: 1\r
+  replicas: {{ .Values.replicas}}\r
+  selector:\r
+    matchLabels:\r
+      app: {{ .Values.appName}}\r
+      version: {{.Values.version}}\r
+  template:\r
+    metadata:\r
+      labels:\r
+        app: {{ .Values.appName}}\r
+        version: {{.Values.version}}\r
+    spec:\r
+      serviceAccount: default\r
+      volumes:\r
+      - name: {{ .Values.appName}}-cert-volume\r
+        secret:\r
+          secretName: {{.Values.sharedCert}}\r
+          optional: true\r
+          items:\r
+          - key: PEM_CERT\r
+            path: otf.pem\r
+          - key: PEM_KEY\r
+            path: privateKey.pem\r
+#      {{ if or (eq .Values.env "st") (eq .Values.env "prod-dr")}} TODO UNCOMMENT WHEN PUSHING TO ORAN\r
+#      {{else}}\r
+#      - name: logging-pvc\r
+#        persistentVolumeClaim:\r
+#          {{if eq .Values.env "prod"}}\r
+#          claimName: {{ .Values.pvc.prod | quote }}\r
+#          {{ else }}\r
+#          claimName: {{ .Values.pvc.dev | quote }}\r
+#          {{ end }}\r
+#      {{end}}\r
+      containers:\r
+      - name: {{ .Values.appName}}\r
+        image: {{ .Values.image}}\r
+        imagePullPolicy: Always\r
+        ports:\r
+        - name: http\r
+          containerPort: 5000\r
+          nodePort: {{.Values.nodePort}}\r
+          protocol: TCP\r
+#        {{ if eq .Values.env "st"}} TODO UNCOMMENT FOR ORAN?\r
+#        resources:\r
+#          limits:\r
+#            memory: "512Mi"\r
+#            cpu: "500m"\r
+#          requests:\r
+#            memory: "256Mi"\r
+#            cpu: "100m"\r
+#        {{else}}\r
+#        resources:\r
+#          limits:\r
+#            memory: "1Gi"\r
+#            cpu: "1"\r
+#          requests:\r
+#            memory: "1Gi"\r
+#            cpu: "1"\r
+#        {{end}}\r
+        env:\r
+        - name: NAMESPACE\r
+          value: {{.Values.namespace}}\r
+        - name: APP_NAME\r
+          value: {{ .Values.appName}}\r
+        - name: APP_VERSION\r
+          value: {{.Values.version}}\r
+        volumeMounts:\r
+        - name: {{.Values.appName}}-cert-volume\r
+          mountPath: /opt/cert\r
+#        {{ if or (eq .Values.env "st") (eq .Values.env "prod-dr")}}\r
+#        {{else}}\r
+#        - name: logging-pvc\r
+#          mountPath: "/otf/logs"\r
+#        {{end}}\r
+        livenessProbe:\r
+          httpGet:\r
+            path: {{.Values.health}}\r
+            port: http\r
+            scheme: HTTP\r
+            httpHeaders:\r
+              - name: X-Custom-Header\r
+                value: Alive\r
+          initialDelaySeconds: 30\r
+          timeoutSeconds: 30\r
+          periodSeconds: 30\r
+        readinessProbe:\r
+          httpGet:\r
+            path: {{.Values.health}}\r
+            port: http\r
+            scheme: HTTP\r
+            httpHeaders:\r
+              - name: X-Custom-Header\r
+                value: Ready\r
+          initialDelaySeconds: 30\r
+          timeoutSeconds: 30\r
+          periodSeconds: 30\r
+      restartPolicy: Always\r
diff --git a/a1-mediator-vth/helm/a1-mediator-vth/templates/service.yaml b/a1-mediator-vth/helm/a1-mediator-vth/templates/service.yaml
new file mode 100644 (file)
index 0000000..f3bcfab
--- /dev/null
@@ -0,0 +1,18 @@
+apiVersion: v1\r
+kind: Service\r
+metadata:\r
+  name: {{ .Values.appName }}\r
+  namespace: {{ .Values.namespace}}\r
+  labels:\r
+    app: {{ .Values.appName }}\r
+    version: {{ .Values.version}}\r
+spec:\r
+  type: NodePort\r
+  ports:\r
+  - name: http\r
+    port: 5000\r
+    protocol: TCP\r
+    nodePort: {{ .Values.nodePort}}\r
+  selector:\r
+    app: {{ .Values.appName }}\r
+    version: {{ .Values.version}}\r
diff --git a/a1-mediator-vth/helm/a1-mediator-vth/values.yaml b/a1-mediator-vth/helm/a1-mediator-vth/values.yaml
new file mode 100644 (file)
index 0000000..81d2226
--- /dev/null
@@ -0,0 +1,12 @@
+appName: a1-mediator-vth\r
+env: dev\r
+version: 0.0.1-SNAPSHOT\r
+image: a1-mediator-vth:0.0.1-SNAPSHOT\r
+namespace: org-oran-otf\r
+nodePort: 32324\r
+replicas: 1\r
+health : /otf/vth/oran/a1/v1/health\r
+sharedCert: otf-cert-secret-builder\r
+pvc:\r
+  dev: org-oran-otf-dev-logs-pv\r
+  prod: org-oran-otf-prod-logs-pv\r
diff --git a/a1-mediator-vth/pip-requirements.txt b/a1-mediator-vth/pip-requirements.txt
new file mode 100644 (file)
index 0000000..863a045
--- /dev/null
@@ -0,0 +1,5 @@
+flask\r
+flask-cors\r
+FLASK\r
+FLASK-CORS\r
+requests
\ No newline at end of file
diff --git a/dmaap-vth/Dockerfile b/dmaap-vth/Dockerfile
new file mode 100644 (file)
index 0000000..bc5b296
--- /dev/null
@@ -0,0 +1,27 @@
+#   Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+################################################################################\r
+\r
+FROM python:3.7.4\r
+\r
+RUN python --version\r
+\r
+ADD pip-requirements.txt pip-requirements.txt\r
+ADD dmaap_vth.py dmaap_vth.py\r
+ADD config.ini config.ini\r
+\r
+RUN mkdir -p /otf/logs\r
+\r
+RUN python -m pip install -r pip-requirements.txt\r
+ENTRYPOINT ["python", "dmaap_vth.py"]\r
diff --git a/dmaap-vth/Jenkinsfile b/dmaap-vth/Jenkinsfile
new file mode 100644 (file)
index 0000000..dfb3067
--- /dev/null
@@ -0,0 +1,162 @@
+#!/usr/bin/env groovy\r
+\r
+/*  Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+##############################################################################*/\r
+\r
+properties([[$class: 'ParametersDefinitionProperty', parameterDefinitions: [\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'PHASE', defaultValue: "BUILD"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'ENV', defaultValue: "dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'MECHID', defaultValue: "id_otf_dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'KUBE_CONFIG', defaultValue: "kubeConfig-dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'TILLER_NAMESPACE', defaultValue: "org-oran-otf"]\r
+]]])\r
+\r
+\r
+echo "Build branch: ${env.BRANCH_NAME}"\r
+\r
+node("docker"){\r
+       stage 'Checkout'\r
+       checkout scm\r
+       PHASES=PHASE.tokenize( '_' );\r
+       echo "PHASES : " + PHASES\r
+\r
+\r
+       ARTIFACT_ID="dmaap-vth";\r
+       VERSION="0.0.1-SNAPSHOT";\r
+       NAMESPACE="org-oran-otf"\r
+       DOCKER_REGISTRY="registry.hub.docker.io"\r
+\r
+  if( ENV.equalsIgnoreCase("dev") ){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".dev" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+  if( ENV.equalsIgnoreCase("prod") || ENV.equalsIgnoreCase("prod-dr")){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".prod" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+\r
+  if( ENV.equalsIgnoreCase("st") ){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".st" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+\r
+       echo "Artifact: " + IMAGE_NAME\r
+\r
+       withEnv(["PATH=${env.PATH}:${env.WORKSPACE}/linux-amd64", "HELM_HOME=${env.WORKSPACE}"]) {\r
+\r
+               echo "PATH=${env.PATH}"\r
+               echo "HELM_HOME=${env.HELM_HOME}"\r
+\r
+               if (PHASES.contains("BUILD")){\r
+\r
+                       stage 'Publish Artifact'\r
+\r
+                               withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {\r
+                                       dir("dmaap-vth")\r
+                                               echo "Artifact: " + IMAGE_NAME\r
+\r
+                                               sh """\r
+                                                       docker login $DOCKER_REGISTRY --username $USERNAME --password $PASSWORD\r
+                                                       docker build -t $IMAGE_NAME .\r
+                                                       docker push $IMAGE_NAME\r
+                                               """\r
+                               }\r
+\r
+               }\r
+\r
+               if (PHASES.contains("DEPLOY") || PHASES.contains("UNDEPLOY")) {\r
+\r
+                       stage 'Init Helm'\r
+\r
+                       //check if helm exists if not install\r
+                       if(fileExists('linux-amd64/helm')){\r
+                               sh """\r
+                                       echo "helm is already installed"\r
+                               """\r
+                       }\r
+                       else{\r
+                       //download helm\r
+                               sh """\r
+                                       echo "installing helm"\r
+                                       wget  https://storage.googleapis.com/kubernetes-helm/helm-v2.14.3-linux-amd64.tar.gz\r
+                                       tar -xf helm-v2.14.3-linux-amd64.tar.gz\r
+                                       rm helm-v2.14.3-linux-amd64.tar.gz\r
+                               """\r
+                       }\r
+\r
+                       withCredentials([file(credentialsId: KUBE_CONFIG, variable: 'KUBECONFIG')]) {\r
+\r
+                               dir('dmaap-vth/helm'){\r
+                               //check if charts are valid, and then perform dry run, if successful then upgrade/install charts\r
+\r
+                                       if (PHASES.contains("UNDEPLOY") ) {\r
+                                               stage 'Undeploy'\r
+\r
+                                               sh """\r
+                                                       helm delete --tiller-namespace=$TILLER_NAMESPACE --purge $ARTIFACT_ID\r
+                                               """\r
+                                       }\r
+\r
+                               //NOTE Double quotes are used below to access groovy variables like artifact_id and tiller_namespace\r
+                       if (PHASES.contains("DEPLOY") ){\r
+                               stage 'Deploy'\r
+                                                       withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {\r
+\r
+                                                               sh """\r
+                                                                   helm version\r
+                                                                       echo "Validate Yaml"\r
+                                                                       helm lint $ARTIFACT_ID\r
+\r
+                                                                       echo "View Helm Templates"\r
+                                                                       helm template $ARTIFACT_ID --set appName=$ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION  \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE \\r
+                                        --set credentials.username= $USERNAME \\r
+                                        --set credentials.password= $PASSWORD\r
+\r
+                                                                       echo "Perform Dry Run Of Install"\r
+                                                                       helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install --dry-run $ARTIFACT_ID $ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE \\r
+                                        --set credentials.username=$USERNAME \\r
+                                        --set credentials.password=$PASSWORD\r
+\r
+\r
+                                                                       echo "Helm Install/Upgrade"\r
+                                                               helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install $ARTIFACT_ID $ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE \\r
+                                        --set credentials.username=$USERNAME \\r
+                                        --set credentials.password=$PASSWORD\r
+\r
+                                                               """\r
+                                                       }\r
+                       }\r
+\r
+                               }\r
+                       }\r
+       }\r
+\r
+       }\r
+}\r
diff --git a/dmaap-vth/config.ini b/dmaap-vth/config.ini
new file mode 100644 (file)
index 0000000..9c5f7d4
--- /dev/null
@@ -0,0 +1,11 @@
+[auth]\r
+auth_enabled= true\r
+username = %(USER)s\r
+password = %(PW)s\r
+[resource]\r
+proxy_enabled = true\r
+https_proxy= %(HTTPS)s\r
+http_proxy= %(HTTP)s\r
+base_address = %(BASE_URL)s\r
+publish = /{topic_name}\r
+subscribe = /{topic_name}/{consumer_group}/{consumer_id}
\ No newline at end of file
diff --git a/dmaap-vth/dmaap_vth.py b/dmaap-vth/dmaap_vth.py
new file mode 100644 (file)
index 0000000..fce93fd
--- /dev/null
@@ -0,0 +1,238 @@
+#   Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+################################################################################\r
+# File name: dmaap-vth.py                                                      #\r
+# Description: vth that utilize dmaap  to subscribe and publish to topics      #\r
+# Date created: 02/21/2020                                                     #\r
+# Last modified: 04/02/2020                                                    #\r
+# Python Version: 3.7                                                          #\r
+# Author: Jackie Chen (jv246a)                                                 #\r
+# Email: jv246a@att.com                                                        #\r
+################################################################################\r
+\r
+import datetime\r
+from configparser import ConfigParser\r
+import os\r
+import logging\r
+from logging import FileHandler\r
+import requests\r
+from flask import Flask, request, jsonify\r
+\r
+# redirect http to https\r
+app = Flask(__name__)\r
+\r
+# Prevents print statement every time an endpoint is triggered.\r
+logging.getLogger("werkzeug").setLevel(logging.WARNING)\r
+\r
+\r
+def sendCallback(url, data):\r
+    try:\r
+        if type(data) is not dict:\r
+            data = {"msg": data}\r
+        app.logger.info("sending callback")\r
+        requests.post(url, json= data)\r
+    except Exception as e:\r
+        app.logger.info(e)\r
+    return\r
+\r
+def unix_time_millis(dt):\r
+    epoch = datetime.datetime.utcfromtimestamp(0)\r
+    return (dt - epoch).total_seconds() * 1000.0\r
+\r
+\r
+def _get_request_data():\r
+    if not request.is_json:\r
+        raise ValueError("request must be json")\r
+    requestData = request.get_json()\r
+    return requestData\r
+\r
+\r
+def _get_config(config_file_name):\r
+    config = ConfigParser(os.environ)\r
+    config.read(config_file_name)\r
+    return config\r
+\r
+def _validate_request(request_data, isPublish=True):\r
+    missing_params = []\r
+\r
+    if 'topic_name' not in request_data:\r
+        missing_params.append("topic_name")\r
+    if isPublish:\r
+        if 'data' not in request_data:\r
+            missing_params.append('data')\r
+    else:\r
+        if 'consumer_group' not in request_data:\r
+            missing_params.append('consumer_group')\r
+        if 'consumer_id' not in request_data:\r
+            missing_params.append('consumer_id')\r
+\r
+    if missing_params:\r
+        err_msg = '{} request requires the following: '.format('publish' if isPublish else 'subscribe')\r
+        err_msg += ','.join(missing_params)\r
+        raise KeyError(err_msg)\r
+\r
+\r
+def _build_url(config, request_data, is_publish=True):\r
+    if is_publish:\r
+        base_path = config['resource']['base_address'] + config['resource']['publish']\r
+        topic_name = request_data['topic_name']\r
+        publish_address = base_path.format(topic_name=topic_name)\r
+        return publish_address\r
+\r
+    base_path = config['resource']['base_address'] + config['resource']['subscribe']\r
+    topic_name = request_data['topic_name']\r
+    consumer_group = request_data['consumer_group']\r
+    consumer_id = request_data['consumer_id']\r
+    subscribe_address = base_path.format(topic_name=topic_name, consumer_group=consumer_group, consumer_id=consumer_id)\r
+    if ('timeout' in request_data):\r
+        subscribe_address = (subscribe_address + '?timeout={}').format(request_data['timeout'])\r
+    return subscribe_address\r
+\r
+\r
+def _send_request(url, config, is_subscribe_request=False, payload=None):\r
+    # setup default values\r
+    auth_enabled = config.getboolean('auth', 'auth_enabled')\r
+    proxy_enabled = config.getboolean('resource', 'proxy_enabled')\r
+    username = ''\r
+    password = ''\r
+    req_proxies = {\r
+        'http': None,\r
+        'https': None\r
+    }\r
+    # place proxy and authentication information\r
+    if auth_enabled:\r
+        username = config['auth']['username']\r
+        password = config['auth']['password']\r
+    if proxy_enabled:\r
+        req_proxies['http'] = config['resource']['http_proxy']\r
+        req_proxies['https'] = config['resource']['https_proxy']\r
+\r
+    # for subscribe request\r
+    if is_subscribe_request:\r
+        return requests.get(url,\r
+                            auth=(username, password) if auth_enabled else None,\r
+                            proxies=req_proxies if proxy_enabled else None)\r
+    # for publish request\r
+    req_headers = {'Content-type': 'application/json'}\r
+    return requests.post(url,\r
+                         json=payload,\r
+                         auth=(username, password) if auth_enabled else None,\r
+                         proxies=req_proxies if proxy_enabled else None,\r
+                         headers=req_headers)\r
+\r
+@app.route("/otf/vth/oran/dmaap/v1/health", methods=['GET'])\r
+def getHealth():\r
+    return 'UP'\r
+\r
+@app.route("/otf/vth/oran/dmaap/v1/subscribe", methods=["POST"])\r
+def subscribeRequest():\r
+    response_data = {\r
+        'vthResponse': {\r
+            'testDuration': '',\r
+            'dateTimeUTC': str(datetime.datetime.now()),\r
+            'abstractMessage': '',\r
+            'resultData': {}\r
+        }\r
+    }\r
+    ret_url = request.args.get('retURL')\r
+    startTime = unix_time_millis(datetime.datetime.now())\r
+    try:\r
+        # validate request\r
+        request_data = _get_request_data()\r
+        _validate_request(request_data, isPublish=False)\r
+        app.logger.info("incoming subscribe request w/ the following payload:" + str(request_data))\r
+\r
+        # setup phase\r
+        config = _get_config('config.ini')\r
+        subscribe_address = _build_url(config, request_data, is_publish=False)\r
+\r
+        # build response\r
+        app.logger.info('Sending GET to subscribe')\r
+        res = _send_request(subscribe_address, config, is_subscribe_request=True)\r
+        app.logger.info('Response received from subscribe: {}'.format(res.json()))\r
+        response_data['vthResponse']['abstractMessage'] = 'Result from subscribe request'\r
+        response_data['vthResponse']['resultData']['status_code'] = res.status_code\r
+        response_data['vthResponse']['resultData']['result_output'] = res.json()\r
+    except Exception as ex:\r
+        endTime = unix_time_millis(datetime.datetime.now())\r
+        totalTime = endTime - startTime\r
+        response_data['vthResponse']['testDuration'] = totalTime\r
+        response_data['vthResponse']['abstractMessage'] = 'error: ' + str(ex)\r
+        app.logger.error('ERROR:{}'.format(str(ex)))\r
+        return jsonify(response_data)\r
+\r
+    endTime = unix_time_millis(datetime.datetime.now())\r
+    totalTime = endTime - startTime\r
+    response_data['vthResponse']['testDuration'] = totalTime\r
+    if ret_url is not None:\r
+        sendCallback(ret_url,response_data)\r
+        return '',200\r
+    return jsonify(response_data), 200\r
+\r
+\r
+@app.route("/otf/vth/oran/dmaap/v1/publish", methods=['POST'])\r
+def publishRequest():\r
+    response_data = {\r
+        'vthResponse': {\r
+            'testDuration': '',\r
+            'dateTimeUTC': str(datetime.datetime.now()),\r
+            'abstractMessage': '',\r
+            'resultData': {}\r
+        }\r
+    }\r
+    startTime = unix_time_millis(datetime.datetime.now())\r
+    ret_url = request.args.get('retURL')\r
+\r
+    try:\r
+        # validate request\r
+        request_data = _get_request_data()\r
+        _validate_request(request_data)\r
+        app.logger.info("incoming publish request w/ the following payload:" + str(request_data))\r
+\r
+        # setup phase\r
+        config = _get_config('config.ini')\r
+        payload = request_data['data']\r
+        publish_address = _build_url(config, request_data)\r
+\r
+        # build response\r
+        app.logger.info("Sending POST to publish")\r
+        res = _send_request(url=publish_address, config=config, payload=payload)\r
+        app.logger.info("Response received from publish: {}".format(res.json()))\r
+        response_data['vthResponse']['abstractMessage'] = 'Result from publish request'\r
+        response_data['vthResponse']['resultData']['status_code'] = res.status_code\r
+        response_data['vthResponse']['resultData']['result_output'] = res.json()\r
+    except Exception as ex:\r
+        endTime = unix_time_millis(datetime.datetime.now())\r
+        totalTime = endTime - startTime\r
+        response_data['vthResponse']['testDuration'] = totalTime\r
+        response_data['vthResponse']['abstractMessage'] = 'error: ' + str(ex)\r
+        app.logger.error('ERROR:{}'.format(str(ex)))\r
+        return jsonify(response_data)\r
+\r
+    endTime = unix_time_millis(datetime.datetime.now())\r
+    totalTime = endTime - startTime\r
+    response_data['vthResponse']['testDuration'] = totalTime\r
+    if ret_url is not None:\r
+        sendCallback(ret_url,response_data)\r
+        return '',200\r
+    return jsonify(response_data), 200\r
+\r
+if __name__ == '__main__':\r
+    logHandler = FileHandler('dmaap-vth.log', mode='a')\r
+    logHandler.setLevel(logging.INFO)\r
+    app.logger.setLevel(logging.INFO)\r
+    app.logger.addHandler(logHandler)\r
+    # context = ('opt/cert/otf.pem', 'opt/cert/privateKey.pem')\r
+    # app.run(debug = False, host = '0.0.0.0', port = 5000, ssl_context = context)\r
+    app.run(debug=False, host='0.0.0.0', port=5000)\r
diff --git a/dmaap-vth/doc/dmaap-documentation.docx b/dmaap-vth/doc/dmaap-documentation.docx
new file mode 100644 (file)
index 0000000..7b72aba
Binary files /dev/null and b/dmaap-vth/doc/dmaap-documentation.docx differ
diff --git a/dmaap-vth/helm/dmaap-vth/.helmignore b/dmaap-vth/helm/dmaap-vth/.helmignore
new file mode 100644 (file)
index 0000000..daebc7d
--- /dev/null
@@ -0,0 +1,21 @@
+# Patterns to ignore when building packages.\r
+# This supports shell glob matching, relative path matching, and\r
+# negation (prefixed with !). Only one pattern per line.\r
+.DS_Store\r
+# Common VCS dirs\r
+.git/\r
+.gitignore\r
+.bzr/\r
+.bzrignore\r
+.hg/\r
+.hgignore\r
+.svn/\r
+# Common backup files\r
+*.swp\r
+*.bak\r
+*.tmp\r
+*~\r
+# Various IDEs\r
+.project\r
+.idea/\r
+*.tmproj\r
diff --git a/dmaap-vth/helm/dmaap-vth/Chart.yaml b/dmaap-vth/helm/dmaap-vth/Chart.yaml
new file mode 100644 (file)
index 0000000..f219144
--- /dev/null
@@ -0,0 +1,5 @@
+apiVersion: v1\r
+appVersion: "1.0"\r
+description: A Helm chart for the dmaap Virtual Test Head\r
+name: dmaap-vth\r
+version: 0.0.1\r
diff --git a/dmaap-vth/helm/dmaap-vth/templates/deployment.yaml b/dmaap-vth/helm/dmaap-vth/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..f78b5c8
--- /dev/null
@@ -0,0 +1,97 @@
+apiVersion: extensions/v1beta1\r
+kind: Deployment\r
+metadata:\r
+  name: {{ .Values.appName}}\r
+  namespace: {{.Values.namespace}}\r
+  labels:\r
+    app: {{ .Values.appName}}\r
+    version: {{.Values.version}}\r
+spec:\r
+  revisionHistoryLimit: 1\r
+  minReadySeconds: 10\r
+  strategy:\r
+  # indicate which strategy we want for rolling update\r
+    type: RollingUpdate\r
+    rollingUpdate:\r
+      maxSurge: 0\r
+      maxUnavailable: 1\r
+  replicas: {{ .Values.replicas}}\r
+  selector:\r
+    matchLabels:\r
+      app: {{ .Values.appName}}\r
+      version: {{.Values.version}}\r
+  template:\r
+    metadata:\r
+      labels:\r
+        app: {{ .Values.appName}}\r
+        version: {{.Values.version}}\r
+    spec:\r
+      serviceAccount: default\r
+      volumes:\r
+      - name: {{ .Values.appName}}-cert-volume\r
+        secret:\r
+          secretName: {{.Values.sharedCert}}\r
+          optional: true\r
+          items:\r
+          - key: PEM_CERT\r
+            path: otf.pem\r
+          - key: PEM_KEY\r
+            path: privateKey.pem\r
+      containers:\r
+      - name: {{ .Values.appName}}\r
+        image: {{ .Values.image}}\r
+        imagePullPolicy: Always\r
+        ports:\r
+        - name: http\r
+          containerPort: 5000\r
+          nodePort: {{.Values.nodePort}}\r
+          protocol: TCP\r
+        env:\r
+        - name: NAMESPACE\r
+          value: {{.Values.namespace}}\r
+        - name: APP_NAME\r
+          value: {{ .Values.appName}}\r
+        - name: APP_VERSION\r
+          value: {{.Values.version}}\r
+        - name: HTTP\r
+          value: {{ .Values.HTTP}}\r
+        - name: HTTPS\r
+          value: {{ .Values.HTTPS}}\r
+        - name: BASE_URL\r
+          value: {{ .Values.BASE_URL}}\r
+        - name: USER\r
+          valueFrom:\r
+            secretKeyRef:\r
+              name: {{ .Values.appName}}\r
+              key: username\r
+        - name: PW\r
+          valueFrom:\r
+            secretKeyRef:\r
+              name: {{ .Values.appName}}\r
+              key: password\r
+        volumeMounts:\r
+        - name: {{.Values.appName}}-cert-volume\r
+          mountPath: /opt/cert\r
+        livenessProbe:\r
+          httpGet:\r
+            path: {{.Values.health}}\r
+            port: http\r
+            scheme: HTTP\r
+            httpHeaders:\r
+              - name: X-Custom-Header\r
+                value: Alive\r
+          initialDelaySeconds: 30\r
+          timeoutSeconds: 30\r
+          periodSeconds: 30\r
+        readinessProbe:\r
+          httpGet:\r
+            path: {{.Values.health}}\r
+            port: http\r
+            scheme: HTTP\r
+            httpHeaders:\r
+              - name: X-Custom-Header\r
+                value: Ready\r
+          initialDelaySeconds: 30\r
+          timeoutSeconds: 30\r
+          periodSeconds: 30\r
+      restartPolicy: Always\r
diff --git a/dmaap-vth/helm/dmaap-vth/templates/secret.yaml b/dmaap-vth/helm/dmaap-vth/templates/secret.yaml
new file mode 100644 (file)
index 0000000..b5c04dd
--- /dev/null
@@ -0,0 +1,8 @@
+apiVersion: v1\r
+kind: Secret\r
+metadata:\r
+  name: {{ .Values.appName}}\r
+type: Opaque\r
+data:\r
+  username: {{ .Values.credentials.username | b64enc}}\r
+  password: {{ .Values.credentials.password | b64enc}}
\ No newline at end of file
diff --git a/dmaap-vth/helm/dmaap-vth/templates/service.yaml b/dmaap-vth/helm/dmaap-vth/templates/service.yaml
new file mode 100644 (file)
index 0000000..f3bcfab
--- /dev/null
@@ -0,0 +1,18 @@
+apiVersion: v1\r
+kind: Service\r
+metadata:\r
+  name: {{ .Values.appName }}\r
+  namespace: {{ .Values.namespace}}\r
+  labels:\r
+    app: {{ .Values.appName }}\r
+    version: {{ .Values.version}}\r
+spec:\r
+  type: NodePort\r
+  ports:\r
+  - name: http\r
+    port: 5000\r
+    protocol: TCP\r
+    nodePort: {{ .Values.nodePort}}\r
+  selector:\r
+    app: {{ .Values.appName }}\r
+    version: {{ .Values.version}}\r
diff --git a/dmaap-vth/helm/dmaap-vth/values.yaml b/dmaap-vth/helm/dmaap-vth/values.yaml
new file mode 100644 (file)
index 0000000..73c63aa
--- /dev/null
@@ -0,0 +1,18 @@
+appName: dmaap-vth\r
+env: dev\r
+version: 0.0.1-SNAPSHOT\r
+image: dmaap-vth:0.0.1-SNAPSHOT\r
+namespace: org-oran-otf\r
+nodePort: 32324\r
+replicas: 1\r
+health : /otf/vth/oran/dmaap/v1/health\r
+sharedCert: otf-cert-secret-builder\r
+pvc:\r
+  dev: org-oran-otf-dev-logs-pv\r
+  prod: org-oran-otf-prod-logs-pv\r
+HTTP: "proxy address here if there is"\r
+HTTPS: "proxy address here if there is"\r
+BASE_URL: "base dmaap address here"\r
+credentials:\r
+  username: "!"\r
+  password: "!"\r
diff --git a/dmaap-vth/pip-requirements.txt b/dmaap-vth/pip-requirements.txt
new file mode 100644 (file)
index 0000000..1a9cd87
--- /dev/null
@@ -0,0 +1,6 @@
+flask\r
+flask-cors\r
+FLASK\r
+FLASK-CORS\r
+requests\r
+configparser
\ No newline at end of file
diff --git a/o1-vth/Doc/o1-documentation.docx b/o1-vth/Doc/o1-documentation.docx
new file mode 100644 (file)
index 0000000..003e35c
Binary files /dev/null and b/o1-vth/Doc/o1-documentation.docx differ
diff --git a/o1-vth/Dockerfile b/o1-vth/Dockerfile
new file mode 100644 (file)
index 0000000..01ff38f
--- /dev/null
@@ -0,0 +1,27 @@
+#   Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+################################################################################\r
+\r
+FROM python:3.7.4\r
+\r
+RUN python --version\r
+\r
+ADD pip-requirements.txt pip-requirements.txt\r
+ADD o1_vth.py o1_vth.py\r
+ADD config.ini config.ini\r
+\r
+RUN mkdir -p /otf/logs\r
+\r
+RUN python -m pip install -r pip-requirements.txt\r
+ENTRYPOINT ["python", "o1_vth.py"]\r
diff --git a/o1-vth/Jenkinsfile b/o1-vth/Jenkinsfile
new file mode 100644 (file)
index 0000000..8da4b07
--- /dev/null
@@ -0,0 +1,164 @@
+#!/usr/bin/env groovy\r
+\r
+/*  Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+##############################################################################*/\r
+\r
+properties([[$class: 'ParametersDefinitionProperty', parameterDefinitions: [\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'PHASE', defaultValue: "BUILD"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'ENV', defaultValue: "dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'MECHID', defaultValue: "id_otf_dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'KUBE_CONFIG', defaultValue: "kubeConfig-dev"],\r
+        [$class: 'hudson.model.StringParameterDefinition', name: 'TILLER_NAMESPACE', defaultValue: "registry.hub.docker.io"]\r
+]]])\r
+\r
+\r
+echo "Build branch: ${env.BRANCH_NAME}"\r
+\r
+node("docker"){\r
+       stage 'Checkout'\r
+       checkout scm\r
+       PHASES=PHASE.tokenize( '_' );\r
+       echo "PHASES : " + PHASES\r
+\r
+\r
+       ARTIFACT_ID="o1-vth";\r
+       VERSION="0.0.1-SNAPSHOT";\r
+       NAMESPACE="org-oran-otf"\r
+       DOCKER_REGISTRY="registry.hub.docker.io"\r
+\r
+  if( ENV.equalsIgnoreCase("dev") ){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".dev" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+  if( ENV.equalsIgnoreCase("prod") || ENV.equalsIgnoreCase("prod-dr")){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".prod" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+\r
+  if( ENV.equalsIgnoreCase("st") ){\r
+    IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".st" + "/" + ARTIFACT_ID +  ":" + VERSION\r
+\r
+  }\r
+\r
+       echo "Artifact: " + IMAGE_NAME\r
+\r
+       withEnv(["PATH=${env.PATH}:${env.WORKSPACE}/linux-amd64", "HELM_HOME=${env.WORKSPACE}"]) {\r
+\r
+               echo "PATH=${env.PATH}"\r
+               echo "HELM_HOME=${env.HELM_HOME}"\r
+\r
+               if (PHASES.contains("BUILD")){\r
+\r
+                       stage 'Publish Artifact'\r
+\r
+                               withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {\r
+\r
+                    dir("o1-vth"){\r
+                        echo "Artifact: " + IMAGE_NAME\r
+\r
+                        sh """\r
+                            docker login $DOCKER_REGISTRY --username $USERNAME --password $PASSWORD\r
+                            docker build -t $IMAGE_NAME .\r
+                            docker push $IMAGE_NAME\r
+                        """\r
+                    }\r
+                               }\r
+\r
+               }\r
+\r
+               if (PHASES.contains("DEPLOY") || PHASES.contains("UNDEPLOY")) {\r
+\r
+                       stage 'Init Helm'\r
+\r
+                       //check if helm exists if not install\r
+                       if(fileExists('linux-amd64/helm')){\r
+                               sh """\r
+                                       echo "helm is already installed"\r
+                               """\r
+                       }\r
+                       else{\r
+                       //download helm\r
+                               sh """\r
+                                       echo "installing helm"\r
+                                       wget  https://storage.googleapis.com/kubernetes-helm/helm-v2.14.3-linux-amd64.tar.gz\r
+                                       tar -xf helm-v2.14.3-linux-amd64.tar.gz\r
+                                       rm helm-v2.14.3-linux-amd64.tar.gz\r
+                               """\r
+                       }\r
+\r
+                       withCredentials([file(credentialsId: KUBE_CONFIG, variable: 'KUBECONFIG')]) {\r
+\r
+                               dir('o1-vth/helm'){\r
+                               //check if charts are valid, and then perform dry run, if successful then upgrade/install charts\r
+\r
+                                       if (PHASES.contains("UNDEPLOY") ) {\r
+                                               stage 'Undeploy'\r
+\r
+                                               sh """\r
+                                                       helm delete --tiller-namespace=$TILLER_NAMESPACE --purge $ARTIFACT_ID\r
+                                               """\r
+                                       }\r
+\r
+                               //NOTE Double quotes are used below to access groovy variables like artifact_id and tiller_namespace\r
+                       if (PHASES.contains("DEPLOY") ){\r
+                               stage 'Deploy'\r
+                                                       withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {\r
+\r
+                                                               sh """\r
+                                                                   helm version\r
+                                                                       echo "Validate Yaml"\r
+                                                                       helm lint $ARTIFACT_ID\r
+\r
+                                                                       echo "View Helm Templates"\r
+                                                                       helm template $ARTIFACT_ID --set appName=$ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION  \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE \\r
+                                        --set credentials.username= $USERNAME \\r
+                                        --set credentials.password= $PASSWORD\r
+\r
+                                                                       echo "Perform Dry Run Of Install"\r
+                                                                       helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install --dry-run $ARTIFACT_ID $ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE \\r
+                                        --set credentials.username=$USERNAME \\r
+                                        --set credentials.password=$PASSWORD\r
+\r
+\r
+                                                                       echo "Helm Install/Upgrade"\r
+                                                               helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install $ARTIFACT_ID $ARTIFACT_ID \\r
+                                        --set appName=$ARTIFACT_ID \\r
+                                        --set version=$VERSION \\r
+                                        --set env=$ENV \\r
+                                        --set image=$IMAGE_NAME \\r
+                                        --set namespace=$TILLER_NAMESPACE \\r
+                                        --set credentials.username=$USERNAME \\r
+                                        --set credentials.password=$PASSWORD\r
+\r
+                                                               """\r
+                                                       }\r
+                       }\r
+\r
+                               }\r
+                       }\r
+       }\r
+\r
+       }\r
+}\r
diff --git a/o1-vth/config.ini b/o1-vth/config.ini
new file mode 100644 (file)
index 0000000..16ec93c
--- /dev/null
@@ -0,0 +1,10 @@
+[auth]\r
+auth_enabled = true\r
+username = %(USER)s\r
+password = %(PW)s\r
+[resource]\r
+proxy_enabled = true\r
+https_proxy = %(HTTPS)s\r
+http_proxy = %(HTTP)s\r
+base_address = %(BASE_URL)s\r
+get_config_alarms_list = /restconf/config/network-topology:network-topology/topology/topology-netconf/node/o-ran-ru-1/yang-ext:mount/ietf-alarms:alarms/alarm-list
\ No newline at end of file
diff --git a/o1-vth/helm/o1-vth/.helmignore b/o1-vth/helm/o1-vth/.helmignore
new file mode 100644 (file)
index 0000000..daebc7d
--- /dev/null
@@ -0,0 +1,21 @@
+# Patterns to ignore when building packages.\r
+# This supports shell glob matching, relative path matching, and\r
+# negation (prefixed with !). Only one pattern per line.\r
+.DS_Store\r
+# Common VCS dirs\r
+.git/\r
+.gitignore\r
+.bzr/\r
+.bzrignore\r
+.hg/\r
+.hgignore\r
+.svn/\r
+# Common backup files\r
+*.swp\r
+*.bak\r
+*.tmp\r
+*~\r
+# Various IDEs\r
+.project\r
+.idea/\r
+*.tmproj\r
diff --git a/o1-vth/helm/o1-vth/Chart.yaml b/o1-vth/helm/o1-vth/Chart.yaml
new file mode 100644 (file)
index 0000000..35abef6
--- /dev/null
@@ -0,0 +1,5 @@
+apiVersion: v1\r
+appVersion: "1.0"\r
+description: A Helm chart for the o1 Virtual Test Head\r
+name: o1-vth\r
+version: 0.0.1\r
diff --git a/o1-vth/helm/o1-vth/templates/deployment.yaml b/o1-vth/helm/o1-vth/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..f78b5c8
--- /dev/null
@@ -0,0 +1,97 @@
+apiVersion: extensions/v1beta1\r
+kind: Deployment\r
+metadata:\r
+  name: {{ .Values.appName}}\r
+  namespace: {{.Values.namespace}}\r
+  labels:\r
+    app: {{ .Values.appName}}\r
+    version: {{.Values.version}}\r
+spec:\r
+  revisionHistoryLimit: 1\r
+  minReadySeconds: 10\r
+  strategy:\r
+  # indicate which strategy we want for rolling update\r
+    type: RollingUpdate\r
+    rollingUpdate:\r
+      maxSurge: 0\r
+      maxUnavailable: 1\r
+  replicas: {{ .Values.replicas}}\r
+  selector:\r
+    matchLabels:\r
+      app: {{ .Values.appName}}\r
+      version: {{.Values.version}}\r
+  template:\r
+    metadata:\r
+      labels:\r
+        app: {{ .Values.appName}}\r
+        version: {{.Values.version}}\r
+    spec:\r
+      serviceAccount: default\r
+      volumes:\r
+      - name: {{ .Values.appName}}-cert-volume\r
+        secret:\r
+          secretName: {{.Values.sharedCert}}\r
+          optional: true\r
+          items:\r
+          - key: PEM_CERT\r
+            path: otf.pem\r
+          - key: PEM_KEY\r
+            path: privateKey.pem\r
+      containers:\r
+      - name: {{ .Values.appName}}\r
+        image: {{ .Values.image}}\r
+        imagePullPolicy: Always\r
+        ports:\r
+        - name: http\r
+          containerPort: 5000\r
+          nodePort: {{.Values.nodePort}}\r
+          protocol: TCP\r
+        env:\r
+        - name: NAMESPACE\r
+          value: {{.Values.namespace}}\r
+        - name: APP_NAME\r
+          value: {{ .Values.appName}}\r
+        - name: APP_VERSION\r
+          value: {{.Values.version}}\r
+        - name: HTTP\r
+          value: {{ .Values.HTTP}}\r
+        - name: HTTPS\r
+          value: {{ .Values.HTTPS}}\r
+        - name: BASE_URL\r
+          value: {{ .Values.BASE_URL}}\r
+        - name: USER\r
+          valueFrom:\r
+            secretKeyRef:\r
+              name: {{ .Values.appName}}\r
+              key: username\r
+        - name: PW\r
+          valueFrom:\r
+            secretKeyRef:\r
+              name: {{ .Values.appName}}\r
+              key: password\r
+        volumeMounts:\r
+        - name: {{.Values.appName}}-cert-volume\r
+          mountPath: /opt/cert\r
+        livenessProbe:\r
+          httpGet:\r
+            path: {{.Values.health}}\r
+            port: http\r
+            scheme: HTTP\r
+            httpHeaders:\r
+              - name: X-Custom-Header\r
+                value: Alive\r
+          initialDelaySeconds: 30\r
+          timeoutSeconds: 30\r
+          periodSeconds: 30\r
+        readinessProbe:\r
+          httpGet:\r
+            path: {{.Values.health}}\r
+            port: http\r
+            scheme: HTTP\r
+            httpHeaders:\r
+              - name: X-Custom-Header\r
+                value: Ready\r
+          initialDelaySeconds: 30\r
+          timeoutSeconds: 30\r
+          periodSeconds: 30\r
+      restartPolicy: Always\r
diff --git a/o1-vth/helm/o1-vth/templates/secret.yaml b/o1-vth/helm/o1-vth/templates/secret.yaml
new file mode 100644 (file)
index 0000000..b5c04dd
--- /dev/null
@@ -0,0 +1,8 @@
+apiVersion: v1\r
+kind: Secret\r
+metadata:\r
+  name: {{ .Values.appName}}\r
+type: Opaque\r
+data:\r
+  username: {{ .Values.credentials.username | b64enc}}\r
+  password: {{ .Values.credentials.password | b64enc}}
\ No newline at end of file
diff --git a/o1-vth/helm/o1-vth/templates/service.yaml b/o1-vth/helm/o1-vth/templates/service.yaml
new file mode 100644 (file)
index 0000000..f3bcfab
--- /dev/null
@@ -0,0 +1,18 @@
+apiVersion: v1\r
+kind: Service\r
+metadata:\r
+  name: {{ .Values.appName }}\r
+  namespace: {{ .Values.namespace}}\r
+  labels:\r
+    app: {{ .Values.appName }}\r
+    version: {{ .Values.version}}\r
+spec:\r
+  type: NodePort\r
+  ports:\r
+  - name: http\r
+    port: 5000\r
+    protocol: TCP\r
+    nodePort: {{ .Values.nodePort}}\r
+  selector:\r
+    app: {{ .Values.appName }}\r
+    version: {{ .Values.version}}\r
diff --git a/o1-vth/helm/o1-vth/values.yaml b/o1-vth/helm/o1-vth/values.yaml
new file mode 100644 (file)
index 0000000..66a2c9c
--- /dev/null
@@ -0,0 +1,18 @@
+appName: o1-vth\r
+env: dev\r
+version: 0.0.1-SNAPSHOT\r
+image: o1-vth:0.0.1-SNAPSHOT\r
+namespace: org-oran-otf\r
+nodePort: 32130\r
+replicas: 1\r
+health : /otf/vth/oran/smo/v1/health\r
+sharedCert: otf-cert-secret-builder\r
+pvc:\r
+  dev: org-oran-otf-dev-logs-pv\r
+  prod: org-oran-otf-prod-logs-pv\r
+HTTP: "[Your HTTP PROXY HERE]"\r
+HTTPS: "[Your HTTPS PROXY HERE]"\r
+BASE_URL: http://sdn-r-dev.open5g-test.com\r
+credentials:\r
+  username: "!"\r
+  password: "!"\r
diff --git a/o1-vth/o1_vth.py b/o1-vth/o1_vth.py
new file mode 100644 (file)
index 0000000..3732d75
--- /dev/null
@@ -0,0 +1,145 @@
+#   Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+################################################################################\r
+# File name: o1-vth.py                                                        #\r
+# Description: Mainly used to get alarm list                                   #\r
+# Date created: 04/14/2020                                                     #\r
+# Python Version: 3.7                                                          #\r
+# Author: Jackie Chen (jv246a)                                                 #\r
+# Email: jv246a@att.com                                                        #\r
+################################################################################\r
+\r
+import datetime\r
+from configparser import ConfigParser\r
+import os\r
+import logging\r
+from logging import FileHandler\r
+import requests\r
+from flask import Flask, request, jsonify\r
+\r
+# redirect http to https\r
+app = Flask(__name__)\r
+\r
+# Prevents print statement every time an endpoint is triggered.\r
+logging.getLogger("werkzeug").setLevel(logging.WARNING)\r
+\r
+\r
+def sendCallback(url, data):\r
+    try:\r
+        if type(data) is not dict:\r
+            data = {"msg": data}\r
+        app.logger.info("sending callback")\r
+        requests.post(url, json= data)\r
+    except Exception as e:\r
+        app.logger.info(e)\r
+    return\r
+\r
+def unix_time_millis(dt):\r
+    epoch = datetime.datetime.utcfromtimestamp(0)\r
+    return (dt - epoch).total_seconds() * 1000.0\r
+\r
+\r
+def _get_config(config_file_name):\r
+    config = ConfigParser(os.environ)\r
+    config.read(config_file_name)\r
+    return config\r
+\r
+\r
+def _build_url(config):\r
+    return config['resource']['base_address'] + config['resource']['get_config_alarms_list']\r
+\r
+\r
+def _send_request(url, config):\r
+    # setup default values\r
+    proxy_enabled = config.getboolean('resource', 'proxy_enabled')\r
+    auth_enabled = config.getboolean('auth', 'auth_enabled')\r
+    username = ''\r
+    password = ''\r
+\r
+    req_proxies = {\r
+        'http': None,\r
+        'https': None\r
+    }\r
+    # place proxy information\r
+    if proxy_enabled:\r
+        req_proxies['http'] = config['resource']['http_proxy']\r
+        req_proxies['https'] = config['resource']['https_proxy']\r
+    if auth_enabled:\r
+        username = config['auth']['username']\r
+        password = config['auth']['password']\r
+    # get call for alarm list\r
+    return requests.get(url,\r
+                        auth=(username, password) if auth_enabled else None,\r
+                        proxies=req_proxies if proxy_enabled else None)\r
+\r
+def _parse_resposne(response):\r
+    try:\r
+        return response.json()\r
+    except ValueError:\r
+        return response.text\r
+\r
+@app.route('/otf/vth/oran/smo/v1/alarm-list' , methods=['POST'])\r
+def get_alarm_list():\r
+    response_data = {\r
+        'vthResponse': {\r
+            'testDuration': '',\r
+            'dateTimeUTC': str(datetime.datetime.now()),\r
+            'abstractMessage': '',\r
+            'resultData': {}\r
+        }\r
+    }\r
+    ret_url = request.args.get('retURL')\r
+    startTime = unix_time_millis(datetime.datetime.now())\r
+    try:\r
+        # setup phase\r
+        config = _get_config('config.ini')\r
+        alarm_list_url = _build_url(config)\r
+\r
+        # build initial response\r
+        app.logger.info('Sending GET for alarm list')\r
+        res = _send_request(alarm_list_url, config)\r
+        app.logger.info('Status code from GET: {}'.format(res.status_code))\r
+        app.logger.info('Response received from GET alarm-list: {}'.format(res.content))\r
+        response_data['vthResponse']['abstractMessage'] = 'Result from GET alarm list request'\r
+        response_data['vthResponse']['resultData']['status_code'] = res.status_code\r
+        response_data['vthResponse']['resultData']['result_output'] = _parse_resposne(res)\r
+    except Exception as ex:\r
+        endTime = unix_time_millis(datetime.datetime.now())\r
+        totalTime = endTime - startTime\r
+        response_data['vthResponse']['testDuration'] = totalTime\r
+        response_data['vthResponse']['abstractMessage'] = 'error: ' + str(ex)\r
+        app.logger.error('ERROR:{}'.format(str(ex)))\r
+        return jsonify(response_data)\r
+\r
+    #finish up building response\r
+    endTime = unix_time_millis(datetime.datetime.now())\r
+    totalTime = endTime - startTime\r
+    response_data['vthResponse']['testDuration'] = totalTime\r
+    if ret_url is not None:\r
+        sendCallback(ret_url, response_data)\r
+        return '', 200\r
+    return jsonify(response_data), 200\r
+\r
+@app.route("/otf/vth/oran/smo/v1/health", methods=['GET'])\r
+def getHealth():\r
+    return 'UP'\r
+\r
+if __name__ == '__main__':\r
+    logHandler = FileHandler('o1-vth.log', mode='a')\r
+    logHandler.setLevel(logging.INFO)\r
+    app.logger.setLevel(logging.INFO)\r
+    app.logger.addHandler(logHandler)\r
+    # context = ('opt/cert/otf.pem', 'opt/cert/privateKey.pem')\r
+    # app.run(debug = False, host = '0.0.0.0', port = 5000, ssl_context = context)\r
+    app.run(debug=False, host='0.0.0.0', port=5000)\r
diff --git a/o1-vth/pip-requirements.txt b/o1-vth/pip-requirements.txt
new file mode 100644 (file)
index 0000000..1a9cd87
--- /dev/null
@@ -0,0 +1,6 @@
+flask\r
+flask-cors\r
+FLASK\r
+FLASK-CORS\r
+requests\r
+configparser
\ No newline at end of file