From e3ba96506390ab3ad630d2dfc4967fd49527615d Mon Sep 17 00:00:00 2001 From: "jv246a.oran" Date: Tue, 5 May 2020 15:37:02 -0400 Subject: [PATCH] added new vths(smo,a1-mediator,dmaap) updated smo_vth name to o1_vth and updated it's files to reflect the change Change-Id: Iaa130354b6149d830897ae56de7c34eef67e09da Signed-off-by: Chen, Jackie --- a1-mediator-vth/Dockerfile | 13 + a1-mediator-vth/Jenkinsfile | 156 +++++++++ a1-mediator-vth/a1-mediator-vth.py | 198 +++++++++++ a1-mediator-vth/a1_mock_server/index.js | 80 +++++ a1-mediator-vth/a1_mock_server/package-lock.json | 374 +++++++++++++++++++++ a1-mediator-vth/a1_mock_server/package.json | 14 + a1-mediator-vth/config.json | 11 + a1-mediator-vth/doc/a1-documentation.docx | Bin 0 -> 30899 bytes a1-mediator-vth/helm/a1-mediator-vth/.helmignore | 21 ++ a1-mediator-vth/helm/a1-mediator-vth/Chart.yaml | 5 + .../helm/a1-mediator-vth/templates/deployment.yaml | 113 +++++++ .../helm/a1-mediator-vth/templates/service.yaml | 18 + a1-mediator-vth/helm/a1-mediator-vth/values.yaml | 12 + a1-mediator-vth/pip-requirements.txt | 5 + dmaap-vth/Dockerfile | 27 ++ dmaap-vth/Jenkinsfile | 162 +++++++++ dmaap-vth/config.ini | 11 + dmaap-vth/dmaap_vth.py | 238 +++++++++++++ dmaap-vth/doc/dmaap-documentation.docx | Bin 0 -> 60098 bytes dmaap-vth/helm/dmaap-vth/.helmignore | 21 ++ dmaap-vth/helm/dmaap-vth/Chart.yaml | 5 + dmaap-vth/helm/dmaap-vth/templates/deployment.yaml | 97 ++++++ dmaap-vth/helm/dmaap-vth/templates/secret.yaml | 8 + dmaap-vth/helm/dmaap-vth/templates/service.yaml | 18 + dmaap-vth/helm/dmaap-vth/values.yaml | 18 + dmaap-vth/pip-requirements.txt | 6 + o1-vth/Doc/o1-documentation.docx | Bin 0 -> 19043 bytes o1-vth/Dockerfile | 27 ++ o1-vth/Jenkinsfile | 164 +++++++++ o1-vth/config.ini | 10 + o1-vth/helm/o1-vth/.helmignore | 21 ++ o1-vth/helm/o1-vth/Chart.yaml | 5 + o1-vth/helm/o1-vth/templates/deployment.yaml | 97 ++++++ o1-vth/helm/o1-vth/templates/secret.yaml | 8 + o1-vth/helm/o1-vth/templates/service.yaml | 18 + o1-vth/helm/o1-vth/values.yaml | 18 + o1-vth/o1_vth.py | 145 ++++++++ o1-vth/pip-requirements.txt | 6 + 38 files changed, 2150 insertions(+) create mode 100644 a1-mediator-vth/Dockerfile create mode 100644 a1-mediator-vth/Jenkinsfile create mode 100644 a1-mediator-vth/a1-mediator-vth.py create mode 100644 a1-mediator-vth/a1_mock_server/index.js create mode 100644 a1-mediator-vth/a1_mock_server/package-lock.json create mode 100644 a1-mediator-vth/a1_mock_server/package.json create mode 100644 a1-mediator-vth/config.json create mode 100644 a1-mediator-vth/doc/a1-documentation.docx create mode 100644 a1-mediator-vth/helm/a1-mediator-vth/.helmignore create mode 100644 a1-mediator-vth/helm/a1-mediator-vth/Chart.yaml create mode 100644 a1-mediator-vth/helm/a1-mediator-vth/templates/deployment.yaml create mode 100644 a1-mediator-vth/helm/a1-mediator-vth/templates/service.yaml create mode 100644 a1-mediator-vth/helm/a1-mediator-vth/values.yaml create mode 100644 a1-mediator-vth/pip-requirements.txt create mode 100644 dmaap-vth/Dockerfile create mode 100644 dmaap-vth/Jenkinsfile create mode 100644 dmaap-vth/config.ini create mode 100644 dmaap-vth/dmaap_vth.py create mode 100644 dmaap-vth/doc/dmaap-documentation.docx create mode 100644 dmaap-vth/helm/dmaap-vth/.helmignore create mode 100644 dmaap-vth/helm/dmaap-vth/Chart.yaml create mode 100644 dmaap-vth/helm/dmaap-vth/templates/deployment.yaml create mode 100644 dmaap-vth/helm/dmaap-vth/templates/secret.yaml create mode 100644 dmaap-vth/helm/dmaap-vth/templates/service.yaml create mode 100644 dmaap-vth/helm/dmaap-vth/values.yaml create mode 100644 dmaap-vth/pip-requirements.txt create mode 100644 o1-vth/Doc/o1-documentation.docx create mode 100644 o1-vth/Dockerfile create mode 100644 o1-vth/Jenkinsfile create mode 100644 o1-vth/config.ini create mode 100644 o1-vth/helm/o1-vth/.helmignore create mode 100644 o1-vth/helm/o1-vth/Chart.yaml create mode 100644 o1-vth/helm/o1-vth/templates/deployment.yaml create mode 100644 o1-vth/helm/o1-vth/templates/secret.yaml create mode 100644 o1-vth/helm/o1-vth/templates/service.yaml create mode 100644 o1-vth/helm/o1-vth/values.yaml create mode 100644 o1-vth/o1_vth.py create mode 100644 o1-vth/pip-requirements.txt diff --git a/a1-mediator-vth/Dockerfile b/a1-mediator-vth/Dockerfile new file mode 100644 index 0000000..e708483 --- /dev/null +++ b/a1-mediator-vth/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.7.4 + +RUN python --version + +ADD pip-requirements.txt pip-requirements.txt +ADD a1-mediator-vth.py a1-mediator-vth.py +ADD config.json config.json + +RUN mkdir -p /otf/logs + +RUN python -m pip install --proxy -r pip-requirements.txt + +ENTRYPOINT ["python", "a1-mediator-vth.py"] diff --git a/a1-mediator-vth/Jenkinsfile b/a1-mediator-vth/Jenkinsfile new file mode 100644 index 0000000..a58148c --- /dev/null +++ b/a1-mediator-vth/Jenkinsfile @@ -0,0 +1,156 @@ +#!/usr/bin/env groovy + +/* Copyright (c) 2019 AT&T Intellectual Property. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +##############################################################################*/ + +properties([[$class: 'ParametersDefinitionProperty', parameterDefinitions: [ + [$class: 'hudson.model.StringParameterDefinition', name: 'PHASE', defaultValue: "BUILD"], + [$class: 'hudson.model.StringParameterDefinition', name: 'ENV', defaultValue: "dev"], + [$class: 'hudson.model.StringParameterDefinition', name: 'MECHID', defaultValue: "id_otf_dev"], + [$class: 'hudson.model.StringParameterDefinition', name: 'KUBE_CONFIG', defaultValue: "kubeConfig-dev"], + [$class: 'hudson.model.StringParameterDefinition', name: 'TILLER_NAMESPACE', defaultValue: "registry.hub.docker.io"] +]]]) + + +echo "Build branch: ${env.BRANCH_NAME}" + +node("docker"){ + stage 'Checkout' + checkout scm + PHASES=PHASE.tokenize( '_' ); + echo "PHASES : " + PHASES + + + ARTIFACT_ID="a1-mediator-vth"; + VERSION="0.0.1-SNAPSHOT"; + NAMESPACE="org-oran-otf" + DOCKER_REGISTRY="registry.hub.docker.io" + + if( ENV.equalsIgnoreCase("dev") ){ + IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".dev" + "/" + ARTIFACT_ID + ":" + VERSION + + } + if( ENV.equalsIgnoreCase("prod") || ENV.equalsIgnoreCase("prod-dr")){ + IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".prod" + "/" + ARTIFACT_ID + ":" + VERSION + + } + + if( ENV.equalsIgnoreCase("st") ){ + IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".st" + "/" + ARTIFACT_ID + ":" + VERSION + + } + + echo "Artifact: " + IMAGE_NAME + + withEnv(["PATH=${env.PATH}:${env.WORKSPACE}/linux-amd64", "HELM_HOME=${env.WORKSPACE}"]) { + + echo "PATH=${env.PATH}" + echo "HELM_HOME=${env.HELM_HOME}" + + if (PHASES.contains("BUILD")){ + + stage 'Publish Artifact' + + withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) { + dir("smo-vth") { + echo "Artifact: " + IMAGE_NAME + + sh """ + docker login $DOCKER_REGISTRY --username $USERNAME --password $PASSWORD + docker build -t $IMAGE_NAME . + docker push $IMAGE_NAME + """ + } + } + + } + + if (PHASES.contains("DEPLOY") || PHASES.contains("UNDEPLOY")) { + + stage 'Init Helm' + + //check if helm exists if not install + if(fileExists('linux-amd64/helm')){ + sh """ + echo "helm is already installed" + """ + } + else{ + //download helm + sh """ + echo "installing helm" + wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.3-linux-amd64.tar.gz + tar -xf helm-v2.14.3-linux-amd64.tar.gz + rm helm-v2.14.3-linux-amd64.tar.gz + """ + } + + withCredentials([file(credentialsId: KUBE_CONFIG, variable: 'KUBECONFIG')]) { + + dir('a1-mediator-vth/helm'){ + //check if charts are valid, and then perform dry run, if successful then upgrade/install charts + + if (PHASES.contains("UNDEPLOY") ) { + stage 'Undeploy' + + sh """ + helm delete --tiller-namespace=$TILLER_NAMESPACE --purge $ARTIFACT_ID + """ + } + + //NOTE Double quotes are used below to access groovy variables like artifact_id and tiller_namespace + if (PHASES.contains("DEPLOY") ){ + stage 'Deploy' + withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) { + + sh """ + helm version + echo "Validate Yaml" + helm lint $ARTIFACT_ID + + echo "View Helm Templates" + helm template $ARTIFACT_ID --set appName=$ARTIFACT_ID \ + --set appName=$ARTIFACT_ID \ + --set version=$VERSION \ + --set env=$ENV \ + --set image=$IMAGE_NAME \ + --set namespace=$TILLER_NAMESPACE + + echo "Perform Dry Run Of Install" + helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install --dry-run $ARTIFACT_ID $ARTIFACT_ID \ + --set appName=$ARTIFACT_ID \ + --set version=$VERSION \ + --set env=$ENV \ + --set image=$IMAGE_NAME \ + --set namespace=$TILLER_NAMESPACE + + echo "Helm Install/Upgrade" + helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install $ARTIFACT_ID $ARTIFACT_ID \ + --set appName=$ARTIFACT_ID \ + --set version=$VERSION \ + --set env=$ENV \ + --set image=$IMAGE_NAME \ + --set namespace=$TILLER_NAMESPACE + + """ + } + } + + } + } + } + + } +} diff --git a/a1-mediator-vth/a1-mediator-vth.py b/a1-mediator-vth/a1-mediator-vth.py new file mode 100644 index 0000000..e0269b1 --- /dev/null +++ b/a1-mediator-vth/a1-mediator-vth.py @@ -0,0 +1,198 @@ +# Copyright (c) 2019 AT&T Intellectual Property. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +################################################################################ +# File name: a1-mediator-vth.py # +# Description: vth for a1-mediator-vth service # +# Date created: 08/22/2019 # +# Last modified: 04/02/2020 # +# Python Version: 3.7.4 # +# Author: Jackie Chen (jv246a) # +# Email: jv246a@att.com # +################################################################################ +import datetime +import json +import logging +from logging import FileHandler +import os + +import requests +from flask import Flask, request, jsonify + +# redirect http to https +app = Flask(__name__) + +# Prevents print statement every time an endpoint is triggered. +logging.getLogger("werkzeug").setLevel(logging.WARNING) + + +def sendCallback(url, data): + try: + if type(data) is not dict: + data = {"msg": data} + app.logger.info("sending callback") + requests.post(url, json=data) + except Exception as e: + app.logger.info(e) + return + +def unix_time_millis(dt): + epoch = datetime.datetime.utcfromtimestamp(0) + return (dt - epoch).total_seconds() * 1000.0 + + +@app.route("/otf/vth/oran/a1/v1/health", methods=['GET']) +def getHealth(): + return "UP" + + +@app.route("/otf/vth/oran/a1/v1", methods=['POST']) +def executeRicRequest(): + response_data = { + 'vthResponse': { + 'testDuration': '', + 'dateTimeUTC': str(datetime.datetime.now()), + 'abstractMessage': '', + 'resultData': {} + } + } + + startTime = unix_time_millis(datetime.datetime.now()) + ret_url = request.args.get('retURL') + try: + if not request.is_json: + raise ValueError("request must be json") + + requestData = request.get_json() + + app.logger.info("A1 requestData:" + str(requestData)) + + action = requestData['action'].lower() + _check_incoming_request(requestData) + + os.environ['NO_PROXY'] = '127.0.0.1' # TODO testing purpose w/ mock server. Needs to remove on final version + with open('config.json') as configFile: + config = json.load(configFile) + + baseAddress = config['base_address'] + if action == 'health_check' or action == 'list_policy': + res = requests.get(baseAddress + config['actions_path'][action]) + response_data['vthResponse']['resultData']['statusCode'] = res.status_code + if action == 'health_check': + response_data['vthResponse']['resultData']['resultOutput'] = res.text + else: + response_data['vthResponse']['resultData']['resultOutput'] = res.json() + elif action == 'list_policy_instance': + res = requests.get(baseAddress + config['actions_path'][action] + .format(policy_type_id=requestData['policy_type_id'])) + response_data['vthResponse']['resultData']['statusCode'] = res.status_code + response_data['vthResponse']['resultData']['resultOutput'] = res.json() + elif action == 'get_policy_instance_status': + res = requests.get(baseAddress + config['actions_path'][action] + .format(policy_type_id=requestData['policy_type_id'], + policy_instance_id=requestData['policy_instance_id'])) + response_data['vthResponse']['resultData']['statusCode'] = res.status_code + response_data['vthResponse']['resultData']['resultOutput'] = res.json() + elif action == 'edit_policy': + res = _send_edit_request(requestData, config) + response_data['vthResponse']['resultData']['statusCode'] = res.status_code + if requestData['request_type'].lower() == 'get' and res.status_code == 200: + response_data['vthResponse']['resultData']['resultOutput'] = res.json() + else: + response_data['vthResponse']['resultData']['resultOutput'] = res.text + elif action == 'edit_policy_instance': + res = _send_edit_request(requestData, config) + response_data['vthResponse']['resultData']['statusCode'] = res.status_code + if requestData['request_type'].lower() == 'get' and res.status_code == 200: + response_data['vthResponse']['resultData']['resultOutput'] = res.json() + else: + response_data['vthResponse']['resultData']['resultOutput'] = res.text + + except Exception as ex: + endTime = unix_time_millis(datetime.datetime.now()) + totalTime = endTime - startTime + response_data['vthResponse']['testDuration'] = totalTime + response_data['vthResponse']['abstractMessage'] = str(ex) + return jsonify(response_data) + + endTime = unix_time_millis(datetime.datetime.now()) + totalTime = endTime - startTime + + response_data['vthResponse']['testDuration'] = totalTime + + if ret_url is not None: + sendCallback(ret_url, response_data) + return '', 200 + + return jsonify(response_data), 200 + + +def _send_edit_request(request_data, config): + baseAddress = config['base_address'] + path = '' + action = request_data['action'] + policy_type_id = request_data['policy_type_id'] + request_type = request_data['request_type'] + if action == "edit_policy": + path = baseAddress + config['actions_path'][action].format(policy_type_id=policy_type_id) + if action == 'edit_policy_instance': + instance_id = request_data['policy_instance_id'] + path = baseAddress + config['actions_path'][action].format(policy_type_id=policy_type_id, + policy_instance_id=instance_id) + if request_type == 'get': + return requests.get(path) + if request_type == 'put': + payload = request_data['payload'] + return requests.put(path, payload) + if request_type == 'delete': + return requests.delete(path) + + +def _check_incoming_request(requestData): # check if the request is valid + if 'action' not in requestData: + raise KeyError('no action was specify') + + action = requestData['action'].lower() + edit_actions = ['edit_policy', 'edit_policy_instance'] + requires_policy_id = ['edit_policy', 'list_policy_instance' + , 'edit_policy_instance', 'get_policy_instance_status'] + requires_policy_instance_id = ['edit_policy_instance', 'get_policy_instance_status'] + possible_actions = ['health_check', 'list_policy', 'edit_policy', 'list_policy_instance' + , 'edit_policy_instance', 'get_policy_instance_status'] + possible_request_type = ['get', 'put', 'delete'] + + if action not in possible_actions: + raise KeyError("invalid action") + if action in edit_actions: # request type is required + if 'request_type' not in requestData: + raise KeyError('this action: ' + action + ' requires a request type') + if requestData['request_type'] not in possible_request_type: + raise KeyError('this request_type: ' + requestData['request_type'] + ' is not valid') + if requestData['request_type'] == 'put' and 'payload' not in requestData: + raise KeyError('put request requires a payload') + if action in requires_policy_id: + if 'policy_type_id' not in requestData: + raise KeyError('this action: ' + action + ' requires a policy_type_id') + if action in requires_policy_instance_id: + if 'policy_instance_id' not in requestData: + raise KeyError('this action: ' + action + ' requires a policy_instance_id') + + +if __name__ == '__main__': + logHandler = FileHandler('a1-mediator-vth.log', mode='a') + logHandler.setLevel(logging.INFO) + app.logger.setLevel(logging.INFO) + app.logger.addHandler(logHandler) + # context = ('opt/cert/otf.pem', 'opt/cert/privateKey.pem') + # app.run(debug = False, host = '0.0.0.0', port = 5000, ssl_context = context) + app.run(debug=False, host='0.0.0.0', port=5000) diff --git a/a1-mediator-vth/a1_mock_server/index.js b/a1-mediator-vth/a1_mock_server/index.js new file mode 100644 index 0000000..5830d11 --- /dev/null +++ b/a1-mediator-vth/a1_mock_server/index.js @@ -0,0 +1,80 @@ +const express = require('express') +const app = express() +const port = 3000 + +app.use(express.json()) + +app.get('/', (req, res) => res.send('Hello World!')) + +app.get('/a1-p/healthcheck',function(req,res){ + console.log("health checking") + res.sendStatus(200) +}) + +app.get('/a1-p/policytypes',function(req,res){ + res.status=(200) + res.send([20000, 20020]) +}) + +app.get('/a1-p/policytypes/:policy_type_id',function(req,res){ + res.status=(200) + policy_type_id = req.params['policy_type_id'] + res.send({"name": "example policy instance","description":"fake description","policy_type_id": policy_type_id,"create_schema":"{name:sample object}"}) +}) +app.delete('/a1-p/policytypes/:policy_type_id',function(req,res){ + res.sendStatus(204) +}) + +app.put('/a1-p/policytypes/:policy_type_id',function(req,res){ + console.log(req.body) + res.sendStatus(201) +}) + +app.get('/a1-p/policytypes/:policy_type_id/policies',function(req,res){ + console.log('listing policies') + res.status=(200) + res.send(["3d2157af-6a8f-4a7c-810f-38c2f824bf12", "06911bfc-c127-444a-8eb1-1bffad27cc3d"]) +}) + +app.get('/a1-p/policytypes/:policy_type_id/policies/:policy_instance_id',function(req,res){ + res.status=(200) + policy_type_id = req.params['policy_type_id'] + policy_instance_id = req.params['policy_instance_id'] + res.send({"name": "example policy instance","description":"fake description","policy_type_id": policy_type_id,"create_schema":"{name:sample object}"}) +}) +app.delete('/a1-p/policytypes/:policy_type_id/policies/:policy_instance_id',function(req,res){ + res.sendStatus(202) +}) + +app.put('/a1-p/policytypes/:policy_type_id/policies/:policy_instance_id',function(req,res){ + console.log(req.body) + res.sendStatus(202) +}) + +app.get('/a1-p/policytypes/:policy_type_id/policies/:policy_instance_id/status',function(req,res){ + res.status(200) + res.send({"properties":{"instance_status": "fake status","enum": "IN EFFECT"}}) +}) + + + + + + +app.get('/appmgr/ric/v1/xapps',function(req,res){ + res.status(200) + 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"]}]}]) +}) + +app.post('/appmgr/ric/v1/xapps', function(req,res){ + res.statusMessage = 'Created' + res.status(201) + 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"]}]}}) +}) + +app.delete('/appmgr/ric/v1/xapps/:name',function(req,res){ + res.sendStatus(204) +}) + +app.listen(port, () => console.log(`Example app listening on port ${port}!`)) + 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 index 0000000..3877b38 --- /dev/null +++ b/a1-mediator-vth/a1_mock_server/package-lock.json @@ -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 index 0000000..8d910e3 --- /dev/null +++ b/a1-mediator-vth/a1_mock_server/package.json @@ -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 index 0000000..79d9855 --- /dev/null +++ b/a1-mediator-vth/config.json @@ -0,0 +1,11 @@ +{ + "base_address": "127.0.0.1:3000", + "actions_path": { + "health_check": "/a1-p/healthcheck", + "list_policy": "/a1-p/policytypes", + "edit_policy": "/a1-p/policytypes/{policy_type_id}", + "list_policy_instance": "/a1-p/policytypes/{policy_type_id}/policies", + "edit_policy_instance": "/a1-p/policytypes/{policy_type_id}/policies/{policy_instance_id}", + "get_policy_instance_status": "/a1-p/policytypes/{policy_type_id}/policies/{policy_instance_id}/status" + } +} \ 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 index 0000000000000000000000000000000000000000..820dbab41441146356206b97152880cfb36ce816 GIT binary patch literal 30899 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

u0( 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 z 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 Hc=dk(+witS literal 0 HcmV?d00001 diff --git a/dmaap-vth/helm/dmaap-vth/.helmignore b/dmaap-vth/helm/dmaap-vth/.helmignore new file mode 100644 index 0000000..daebc7d --- /dev/null +++ b/dmaap-vth/helm/dmaap-vth/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/dmaap-vth/helm/dmaap-vth/Chart.yaml b/dmaap-vth/helm/dmaap-vth/Chart.yaml new file mode 100644 index 0000000..f219144 --- /dev/null +++ b/dmaap-vth/helm/dmaap-vth/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for the dmaap Virtual Test Head +name: dmaap-vth +version: 0.0.1 diff --git a/dmaap-vth/helm/dmaap-vth/templates/deployment.yaml b/dmaap-vth/helm/dmaap-vth/templates/deployment.yaml new file mode 100644 index 0000000..f78b5c8 --- /dev/null +++ b/dmaap-vth/helm/dmaap-vth/templates/deployment.yaml @@ -0,0 +1,97 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: {{ .Values.appName}} + namespace: {{.Values.namespace}} + labels: + app: {{ .Values.appName}} + version: {{.Values.version}} +spec: + revisionHistoryLimit: 1 + minReadySeconds: 10 + strategy: + # indicate which strategy we want for rolling update + type: RollingUpdate + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + replicas: {{ .Values.replicas}} + selector: + matchLabels: + app: {{ .Values.appName}} + version: {{.Values.version}} + template: + metadata: + labels: + app: {{ .Values.appName}} + version: {{.Values.version}} + spec: + serviceAccount: default + volumes: + - name: {{ .Values.appName}}-cert-volume + secret: + secretName: {{.Values.sharedCert}} + optional: true + items: + - key: PEM_CERT + path: otf.pem + - key: PEM_KEY + path: privateKey.pem + containers: + - name: {{ .Values.appName}} + image: {{ .Values.image}} + imagePullPolicy: Always + ports: + - name: http + containerPort: 5000 + nodePort: {{.Values.nodePort}} + protocol: TCP + env: + - name: NAMESPACE + value: {{.Values.namespace}} + - name: APP_NAME + value: {{ .Values.appName}} + - name: APP_VERSION + value: {{.Values.version}} + - name: HTTP + value: {{ .Values.HTTP}} + - name: HTTPS + value: {{ .Values.HTTPS}} + - name: BASE_URL + value: {{ .Values.BASE_URL}} + - name: USER + valueFrom: + secretKeyRef: + name: {{ .Values.appName}} + key: username + - name: PW + valueFrom: + secretKeyRef: + name: {{ .Values.appName}} + key: password + volumeMounts: + - name: {{.Values.appName}}-cert-volume + mountPath: /opt/cert + livenessProbe: + httpGet: + path: {{.Values.health}} + port: http + scheme: HTTP + httpHeaders: + - name: X-Custom-Header + value: Alive + initialDelaySeconds: 30 + timeoutSeconds: 30 + periodSeconds: 30 + readinessProbe: + httpGet: + path: {{.Values.health}} + port: http + scheme: HTTP + httpHeaders: + - name: X-Custom-Header + value: Ready + initialDelaySeconds: 30 + timeoutSeconds: 30 + periodSeconds: 30 + restartPolicy: Always diff --git a/dmaap-vth/helm/dmaap-vth/templates/secret.yaml b/dmaap-vth/helm/dmaap-vth/templates/secret.yaml new file mode 100644 index 0000000..b5c04dd --- /dev/null +++ b/dmaap-vth/helm/dmaap-vth/templates/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.appName}} +type: Opaque +data: + username: {{ .Values.credentials.username | b64enc}} + 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 index 0000000..f3bcfab --- /dev/null +++ b/dmaap-vth/helm/dmaap-vth/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.appName }} + namespace: {{ .Values.namespace}} + labels: + app: {{ .Values.appName }} + version: {{ .Values.version}} +spec: + type: NodePort + ports: + - name: http + port: 5000 + protocol: TCP + nodePort: {{ .Values.nodePort}} + selector: + app: {{ .Values.appName }} + version: {{ .Values.version}} diff --git a/dmaap-vth/helm/dmaap-vth/values.yaml b/dmaap-vth/helm/dmaap-vth/values.yaml new file mode 100644 index 0000000..73c63aa --- /dev/null +++ b/dmaap-vth/helm/dmaap-vth/values.yaml @@ -0,0 +1,18 @@ +appName: dmaap-vth +env: dev +version: 0.0.1-SNAPSHOT +image: dmaap-vth:0.0.1-SNAPSHOT +namespace: org-oran-otf +nodePort: 32324 +replicas: 1 +health : /otf/vth/oran/dmaap/v1/health +sharedCert: otf-cert-secret-builder +pvc: + dev: org-oran-otf-dev-logs-pv + prod: org-oran-otf-prod-logs-pv +HTTP: "proxy address here if there is" +HTTPS: "proxy address here if there is" +BASE_URL: "base dmaap address here" +credentials: + username: "!" + password: "!" diff --git a/dmaap-vth/pip-requirements.txt b/dmaap-vth/pip-requirements.txt new file mode 100644 index 0000000..1a9cd87 --- /dev/null +++ b/dmaap-vth/pip-requirements.txt @@ -0,0 +1,6 @@ +flask +flask-cors +FLASK +FLASK-CORS +requests +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 index 0000000000000000000000000000000000000000..003e35ccc83adc696672b411eb296215f1980ac0 GIT binary patch literal 19043 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 literal 0 HcmV?d00001 diff --git a/o1-vth/Dockerfile b/o1-vth/Dockerfile new file mode 100644 index 0000000..01ff38f --- /dev/null +++ b/o1-vth/Dockerfile @@ -0,0 +1,27 @@ +# Copyright (c) 2019 AT&T Intellectual Property. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +################################################################################ + +FROM python:3.7.4 + +RUN python --version + +ADD pip-requirements.txt pip-requirements.txt +ADD o1_vth.py o1_vth.py +ADD config.ini config.ini + +RUN mkdir -p /otf/logs + +RUN python -m pip install -r pip-requirements.txt +ENTRYPOINT ["python", "o1_vth.py"] diff --git a/o1-vth/Jenkinsfile b/o1-vth/Jenkinsfile new file mode 100644 index 0000000..8da4b07 --- /dev/null +++ b/o1-vth/Jenkinsfile @@ -0,0 +1,164 @@ +#!/usr/bin/env groovy + +/* Copyright (c) 2019 AT&T Intellectual Property. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +##############################################################################*/ + +properties([[$class: 'ParametersDefinitionProperty', parameterDefinitions: [ + [$class: 'hudson.model.StringParameterDefinition', name: 'PHASE', defaultValue: "BUILD"], + [$class: 'hudson.model.StringParameterDefinition', name: 'ENV', defaultValue: "dev"], + [$class: 'hudson.model.StringParameterDefinition', name: 'MECHID', defaultValue: "id_otf_dev"], + [$class: 'hudson.model.StringParameterDefinition', name: 'KUBE_CONFIG', defaultValue: "kubeConfig-dev"], + [$class: 'hudson.model.StringParameterDefinition', name: 'TILLER_NAMESPACE', defaultValue: "registry.hub.docker.io"] +]]]) + + +echo "Build branch: ${env.BRANCH_NAME}" + +node("docker"){ + stage 'Checkout' + checkout scm + PHASES=PHASE.tokenize( '_' ); + echo "PHASES : " + PHASES + + + ARTIFACT_ID="o1-vth"; + VERSION="0.0.1-SNAPSHOT"; + NAMESPACE="org-oran-otf" + DOCKER_REGISTRY="registry.hub.docker.io" + + if( ENV.equalsIgnoreCase("dev") ){ + IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".dev" + "/" + ARTIFACT_ID + ":" + VERSION + + } + if( ENV.equalsIgnoreCase("prod") || ENV.equalsIgnoreCase("prod-dr")){ + IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".prod" + "/" + ARTIFACT_ID + ":" + VERSION + + } + + if( ENV.equalsIgnoreCase("st") ){ + IMAGE_NAME=DOCKER_REGISTRY + "/" + NAMESPACE + ".st" + "/" + ARTIFACT_ID + ":" + VERSION + + } + + echo "Artifact: " + IMAGE_NAME + + withEnv(["PATH=${env.PATH}:${env.WORKSPACE}/linux-amd64", "HELM_HOME=${env.WORKSPACE}"]) { + + echo "PATH=${env.PATH}" + echo "HELM_HOME=${env.HELM_HOME}" + + if (PHASES.contains("BUILD")){ + + stage 'Publish Artifact' + + withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) { + + dir("o1-vth"){ + echo "Artifact: " + IMAGE_NAME + + sh """ + docker login $DOCKER_REGISTRY --username $USERNAME --password $PASSWORD + docker build -t $IMAGE_NAME . + docker push $IMAGE_NAME + """ + } + } + + } + + if (PHASES.contains("DEPLOY") || PHASES.contains("UNDEPLOY")) { + + stage 'Init Helm' + + //check if helm exists if not install + if(fileExists('linux-amd64/helm')){ + sh """ + echo "helm is already installed" + """ + } + else{ + //download helm + sh """ + echo "installing helm" + wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.3-linux-amd64.tar.gz + tar -xf helm-v2.14.3-linux-amd64.tar.gz + rm helm-v2.14.3-linux-amd64.tar.gz + """ + } + + withCredentials([file(credentialsId: KUBE_CONFIG, variable: 'KUBECONFIG')]) { + + dir('o1-vth/helm'){ + //check if charts are valid, and then perform dry run, if successful then upgrade/install charts + + if (PHASES.contains("UNDEPLOY") ) { + stage 'Undeploy' + + sh """ + helm delete --tiller-namespace=$TILLER_NAMESPACE --purge $ARTIFACT_ID + """ + } + + //NOTE Double quotes are used below to access groovy variables like artifact_id and tiller_namespace + if (PHASES.contains("DEPLOY") ){ + stage 'Deploy' + withCredentials([usernamePassword(credentialsId: MECHID, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) { + + sh """ + helm version + echo "Validate Yaml" + helm lint $ARTIFACT_ID + + echo "View Helm Templates" + helm template $ARTIFACT_ID --set appName=$ARTIFACT_ID \ + --set appName=$ARTIFACT_ID \ + --set version=$VERSION \ + --set env=$ENV \ + --set image=$IMAGE_NAME \ + --set namespace=$TILLER_NAMESPACE \ + --set credentials.username= $USERNAME \ + --set credentials.password= $PASSWORD + + echo "Perform Dry Run Of Install" + helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install --dry-run $ARTIFACT_ID $ARTIFACT_ID \ + --set appName=$ARTIFACT_ID \ + --set version=$VERSION \ + --set env=$ENV \ + --set image=$IMAGE_NAME \ + --set namespace=$TILLER_NAMESPACE \ + --set credentials.username=$USERNAME \ + --set credentials.password=$PASSWORD + + + echo "Helm Install/Upgrade" + helm upgrade --tiller-namespace=$TILLER_NAMESPACE --install $ARTIFACT_ID $ARTIFACT_ID \ + --set appName=$ARTIFACT_ID \ + --set version=$VERSION \ + --set env=$ENV \ + --set image=$IMAGE_NAME \ + --set namespace=$TILLER_NAMESPACE \ + --set credentials.username=$USERNAME \ + --set credentials.password=$PASSWORD + + """ + } + } + + } + } + } + + } +} diff --git a/o1-vth/config.ini b/o1-vth/config.ini new file mode 100644 index 0000000..16ec93c --- /dev/null +++ b/o1-vth/config.ini @@ -0,0 +1,10 @@ +[auth] +auth_enabled = true +username = %(USER)s +password = %(PW)s +[resource] +proxy_enabled = true +https_proxy = %(HTTPS)s +http_proxy = %(HTTP)s +base_address = %(BASE_URL)s +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 index 0000000..daebc7d --- /dev/null +++ b/o1-vth/helm/o1-vth/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/o1-vth/helm/o1-vth/Chart.yaml b/o1-vth/helm/o1-vth/Chart.yaml new file mode 100644 index 0000000..35abef6 --- /dev/null +++ b/o1-vth/helm/o1-vth/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for the o1 Virtual Test Head +name: o1-vth +version: 0.0.1 diff --git a/o1-vth/helm/o1-vth/templates/deployment.yaml b/o1-vth/helm/o1-vth/templates/deployment.yaml new file mode 100644 index 0000000..f78b5c8 --- /dev/null +++ b/o1-vth/helm/o1-vth/templates/deployment.yaml @@ -0,0 +1,97 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: {{ .Values.appName}} + namespace: {{.Values.namespace}} + labels: + app: {{ .Values.appName}} + version: {{.Values.version}} +spec: + revisionHistoryLimit: 1 + minReadySeconds: 10 + strategy: + # indicate which strategy we want for rolling update + type: RollingUpdate + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + replicas: {{ .Values.replicas}} + selector: + matchLabels: + app: {{ .Values.appName}} + version: {{.Values.version}} + template: + metadata: + labels: + app: {{ .Values.appName}} + version: {{.Values.version}} + spec: + serviceAccount: default + volumes: + - name: {{ .Values.appName}}-cert-volume + secret: + secretName: {{.Values.sharedCert}} + optional: true + items: + - key: PEM_CERT + path: otf.pem + - key: PEM_KEY + path: privateKey.pem + containers: + - name: {{ .Values.appName}} + image: {{ .Values.image}} + imagePullPolicy: Always + ports: + - name: http + containerPort: 5000 + nodePort: {{.Values.nodePort}} + protocol: TCP + env: + - name: NAMESPACE + value: {{.Values.namespace}} + - name: APP_NAME + value: {{ .Values.appName}} + - name: APP_VERSION + value: {{.Values.version}} + - name: HTTP + value: {{ .Values.HTTP}} + - name: HTTPS + value: {{ .Values.HTTPS}} + - name: BASE_URL + value: {{ .Values.BASE_URL}} + - name: USER + valueFrom: + secretKeyRef: + name: {{ .Values.appName}} + key: username + - name: PW + valueFrom: + secretKeyRef: + name: {{ .Values.appName}} + key: password + volumeMounts: + - name: {{.Values.appName}}-cert-volume + mountPath: /opt/cert + livenessProbe: + httpGet: + path: {{.Values.health}} + port: http + scheme: HTTP + httpHeaders: + - name: X-Custom-Header + value: Alive + initialDelaySeconds: 30 + timeoutSeconds: 30 + periodSeconds: 30 + readinessProbe: + httpGet: + path: {{.Values.health}} + port: http + scheme: HTTP + httpHeaders: + - name: X-Custom-Header + value: Ready + initialDelaySeconds: 30 + timeoutSeconds: 30 + periodSeconds: 30 + restartPolicy: Always diff --git a/o1-vth/helm/o1-vth/templates/secret.yaml b/o1-vth/helm/o1-vth/templates/secret.yaml new file mode 100644 index 0000000..b5c04dd --- /dev/null +++ b/o1-vth/helm/o1-vth/templates/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.appName}} +type: Opaque +data: + username: {{ .Values.credentials.username | b64enc}} + 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 index 0000000..f3bcfab --- /dev/null +++ b/o1-vth/helm/o1-vth/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.appName }} + namespace: {{ .Values.namespace}} + labels: + app: {{ .Values.appName }} + version: {{ .Values.version}} +spec: + type: NodePort + ports: + - name: http + port: 5000 + protocol: TCP + nodePort: {{ .Values.nodePort}} + selector: + app: {{ .Values.appName }} + version: {{ .Values.version}} diff --git a/o1-vth/helm/o1-vth/values.yaml b/o1-vth/helm/o1-vth/values.yaml new file mode 100644 index 0000000..66a2c9c --- /dev/null +++ b/o1-vth/helm/o1-vth/values.yaml @@ -0,0 +1,18 @@ +appName: o1-vth +env: dev +version: 0.0.1-SNAPSHOT +image: o1-vth:0.0.1-SNAPSHOT +namespace: org-oran-otf +nodePort: 32130 +replicas: 1 +health : /otf/vth/oran/smo/v1/health +sharedCert: otf-cert-secret-builder +pvc: + dev: org-oran-otf-dev-logs-pv + prod: org-oran-otf-prod-logs-pv +HTTP: "[Your HTTP PROXY HERE]" +HTTPS: "[Your HTTPS PROXY HERE]" +BASE_URL: http://sdn-r-dev.open5g-test.com +credentials: + username: "!" + password: "!" diff --git a/o1-vth/o1_vth.py b/o1-vth/o1_vth.py new file mode 100644 index 0000000..3732d75 --- /dev/null +++ b/o1-vth/o1_vth.py @@ -0,0 +1,145 @@ +# Copyright (c) 2019 AT&T Intellectual Property. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +################################################################################ +# File name: o1-vth.py # +# Description: Mainly used to get alarm list # +# Date created: 04/14/2020 # +# Python Version: 3.7 # +# Author: Jackie Chen (jv246a) # +# Email: jv246a@att.com # +################################################################################ + +import datetime +from configparser import ConfigParser +import os +import logging +from logging import FileHandler +import requests +from flask import Flask, request, jsonify + +# redirect http to https +app = Flask(__name__) + +# Prevents print statement every time an endpoint is triggered. +logging.getLogger("werkzeug").setLevel(logging.WARNING) + + +def sendCallback(url, data): + try: + if type(data) is not dict: + data = {"msg": data} + app.logger.info("sending callback") + requests.post(url, json= data) + except Exception as e: + app.logger.info(e) + return + +def unix_time_millis(dt): + epoch = datetime.datetime.utcfromtimestamp(0) + return (dt - epoch).total_seconds() * 1000.0 + + +def _get_config(config_file_name): + config = ConfigParser(os.environ) + config.read(config_file_name) + return config + + +def _build_url(config): + return config['resource']['base_address'] + config['resource']['get_config_alarms_list'] + + +def _send_request(url, config): + # setup default values + proxy_enabled = config.getboolean('resource', 'proxy_enabled') + auth_enabled = config.getboolean('auth', 'auth_enabled') + username = '' + password = '' + + req_proxies = { + 'http': None, + 'https': None + } + # place proxy information + if proxy_enabled: + req_proxies['http'] = config['resource']['http_proxy'] + req_proxies['https'] = config['resource']['https_proxy'] + if auth_enabled: + username = config['auth']['username'] + password = config['auth']['password'] + # get call for alarm list + return requests.get(url, + auth=(username, password) if auth_enabled else None, + proxies=req_proxies if proxy_enabled else None) + +def _parse_resposne(response): + try: + return response.json() + except ValueError: + return response.text + +@app.route('/otf/vth/oran/smo/v1/alarm-list' , methods=['POST']) +def get_alarm_list(): + response_data = { + 'vthResponse': { + 'testDuration': '', + 'dateTimeUTC': str(datetime.datetime.now()), + 'abstractMessage': '', + 'resultData': {} + } + } + ret_url = request.args.get('retURL') + startTime = unix_time_millis(datetime.datetime.now()) + try: + # setup phase + config = _get_config('config.ini') + alarm_list_url = _build_url(config) + + # build initial response + app.logger.info('Sending GET for alarm list') + res = _send_request(alarm_list_url, config) + app.logger.info('Status code from GET: {}'.format(res.status_code)) + app.logger.info('Response received from GET alarm-list: {}'.format(res.content)) + response_data['vthResponse']['abstractMessage'] = 'Result from GET alarm list request' + response_data['vthResponse']['resultData']['status_code'] = res.status_code + response_data['vthResponse']['resultData']['result_output'] = _parse_resposne(res) + except Exception as ex: + endTime = unix_time_millis(datetime.datetime.now()) + totalTime = endTime - startTime + response_data['vthResponse']['testDuration'] = totalTime + response_data['vthResponse']['abstractMessage'] = 'error: ' + str(ex) + app.logger.error('ERROR:{}'.format(str(ex))) + return jsonify(response_data) + + #finish up building response + endTime = unix_time_millis(datetime.datetime.now()) + totalTime = endTime - startTime + response_data['vthResponse']['testDuration'] = totalTime + if ret_url is not None: + sendCallback(ret_url, response_data) + return '', 200 + return jsonify(response_data), 200 + +@app.route("/otf/vth/oran/smo/v1/health", methods=['GET']) +def getHealth(): + return 'UP' + +if __name__ == '__main__': + logHandler = FileHandler('o1-vth.log', mode='a') + logHandler.setLevel(logging.INFO) + app.logger.setLevel(logging.INFO) + app.logger.addHandler(logHandler) + # context = ('opt/cert/otf.pem', 'opt/cert/privateKey.pem') + # app.run(debug = False, host = '0.0.0.0', port = 5000, ssl_context = context) + app.run(debug=False, host='0.0.0.0', port=5000) diff --git a/o1-vth/pip-requirements.txt b/o1-vth/pip-requirements.txt new file mode 100644 index 0000000..1a9cd87 --- /dev/null +++ b/o1-vth/pip-requirements.txt @@ -0,0 +1,6 @@ +flask +flask-cors +FLASK +FLASK-CORS +requests +configparser \ No newline at end of file -- 2.16.6