diff options
author | rajendrajaiswal <rajendra.jaiswal@ericsson.com> | 2019-12-16 14:24:02 +0000 |
---|---|---|
committer | Morgan Richomme <morgan.richomme@orange.com> | 2020-01-21 14:34:09 +0000 |
commit | 6a61ad84e1df33bec201df43dc0b217d892f91b9 (patch) | |
tree | 0c340af84099a65e49ec44b8c53d51b13f79aa3e /test | |
parent | f2ec458f12c470552462a75f26ef7e1704482a72 (diff) |
PNF Simulator to support Control Loop subscription model
Change-Id: I9919edb32f3f68f86fad28c908f808fcee3fc548
Issue-ID: INT-1312
Signed-off-by: rajendrajaiswal <rajendra.jaiswal@ericsson.com>
Diffstat (limited to 'test')
9 files changed, 333 insertions, 0 deletions
diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/FileReadyEvent.json b/test/mocks/pmsh-pnf-sim/docker-compose/FileReadyEvent.json new file mode 100644 index 000000000..0f8df3dc0 --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/FileReadyEvent.json @@ -0,0 +1 @@ +{"event":{"commonEventHeader":{"version":"4.0.1","vesEventListenerVersion":"7.0.1","domain":"notification","eventName":"Noti_RnNode-Ericsson_FileReady","eventId":"FileReady_1797490e-10ae-4d48-9ea7-3d7d790b25e1","lastEpochMicrosec":8745745764578,"priority":"Normal","reportingEntityName":"otenb5309","sequence":0,"sourceName":"oteNB5309","startEpochMicrosec":8745745764578,"timeZoneOffset":"UTC+05.30"},"notificationFields":{"changeIdentifier":"PM_MEAS_FILES","changeType":"FileReady","notificationFieldsVersion":"2.0","arrayOfNamedHashMap":[{"name":"Apmfilename.xml.gz","hashMap":{"location":"sftp://bulkpm:bulkpm@sftpserver:22/upload/Apmfilename.xml.gz","compression":"gzip","fileFormatType":"org.3GPP.32.435#measCollec","fileFormatVersion":"V10"}}]}}}
\ No newline at end of file diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/docker-compose.yml b/test/mocks/pmsh-pnf-sim/docker-compose/docker-compose.yml new file mode 100644 index 000000000..419e54bb2 --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/docker-compose.yml @@ -0,0 +1,20 @@ +version: '3' + +services: + netopeer2: + image: registry.gitlab.com/blue-onap/docker/sysrepo-netopeer2:v0.7-r2-5 + container_name: netopeer2 + restart: always + ports: + - "830:830" + - "6513:6513" + volumes: + - ./:/config/models/pnf-subscriptions + sftp: + container_name: sftpserver + image: atmoz/sftp + ports: + - "2222:22" + volumes: + - /host/upload:/home/admin + command: admin:admin:1001
\ No newline at end of file diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/pnf-subscriptions.yang b/test/mocks/pmsh-pnf-sim/docker-compose/pnf-subscriptions.yang new file mode 100644 index 000000000..6adce57cc --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/pnf-subscriptions.yang @@ -0,0 +1,47 @@ +module pnf-subscriptions { + namespace "http://onap.org/pnf-subscriptions"; + prefix subscriptions; + + revision "2019-11-22" { + description + "initial version"; + } + container subscriptions { + list configuration{ + key "subscriptionName"; + leaf subscriptionName { + type string; + } + leaf administrativeState { + type string; + } + leaf fileBasedGP { + type int16; + } + leaf fileLocation { + type string; + } + list measurementGroups { + key "id"; + leaf id{ + type int16; + } + container measurementGroup { + list measurementTypes { + key "measurementType"; + leaf measurementType { + type string; + } + } + list managedObjectDNsBasic { + key "DN"; + leaf DN { + type string; + } + } + } + + } + } + } +}
\ No newline at end of file diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/pnf.py b/test/mocks/pmsh-pnf-sim/docker-compose/pnf.py new file mode 100644 index 000000000..05b09ba17 --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/pnf.py @@ -0,0 +1,103 @@ +import gzip +import json +import os +import shutil +import time +import xml.etree.ElementTree as ET +from random import randint +import requests +import pnfconfig + + +class PNF: + """ Handle update on xml and send file ready event to ves collector """ + def __init__(self): + pass + + @staticmethod + def create_job_id(jobid, change_list): + """ + create new measinfo tag and add new sub element in existing xml. + :param jobid: create unique job id within xml sub element. + :param change_list: list to create sub elements itmes. + """ + try: + measurement_type = [] + meas_object_dn = [] + for items in range(len(change_list)): + if "/measurementType =" in change_list[items]: + measurement_type.append(((change_list[items].rsplit('/', 1))[1].rsplit('=', 1))[1].strip()) + if "/DN =" in change_list[items]: + meas_object_dn.append(((change_list[items].rsplit('/', 1))[1].rsplit('=', 1))[1].strip()) + script_dir = os.path.dirname(__file__) + pm_rel_file_path = "sftp/" + pm_location = os.path.join(script_dir, pm_rel_file_path) + ET.register_namespace('', "http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec") + tree = ET.parse(pm_location + "pm.xml") + root = tree.getroot() + attrib = {} + measinfo = ET.SubElement(root[1], 'measInfo', attrib) + attrib = {'jobId': jobid} + ET.SubElement(measinfo, 'job', attrib) + ET.SubElement(measinfo, 'granPeriod', {'duration': 'PT900S', 'endTime': '2000-03-01T14:14:30+02:00'}) + ET.SubElement(measinfo, 'repPeriod', {'duration': 'PT1800S'}) + for items in range(len(measurement_type)): + meastype = ET.SubElement(measinfo, 'measType', {'p': (items + 1).__str__()}) + meastype.text = measurement_type[items] + for items in range(len(meas_object_dn)): + measvalue = ET.SubElement(measinfo, 'measValue', {'measObjLdn': meas_object_dn[items]}) + for item in range(len(measurement_type)): + value = ET.SubElement(measvalue, 'r', {'p': (item + 1).__str__()}) + value.text = randint(100, 900).__str__() + tree.write(pm_location + "pm.xml", encoding="utf-8", xml_declaration=True) + except Exception as error: + print(error) + + @staticmethod + def delete_job_id(jobid): + """ + delete measinfo tag from existing xml pm file based on jobid. + :param jobid: element within measinfo tag. + """ + try: + script_dir = os.path.dirname(__file__) + pm_rel_file_path = "sftp/" + pm_location = os.path.join(script_dir, pm_rel_file_path) + ET.register_namespace('', "http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec") + tree = ET.parse(pm_location + "pm.xml") + root = tree.getroot() + for measinfo in root[1].findall( + '{http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec}measInfo'): + xml_id = measinfo.find('{http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec}job').attrib + if xml_id["jobId"] == jobid: + root[1].remove(measinfo) + tree.write(pm_location + "pm.xml", encoding="utf-8", xml_declaration=True) + except Exception as error: + print(error) + + @staticmethod + def pm_job(): + """ + create timestemp based gunzip xml file and send file ready event to ves collector. + """ + try: + script_dir = os.path.dirname(__file__) + timestemp = time.time() + pm_rel_file_path = "sftp/" + pm_location = os.path.join(script_dir, pm_rel_file_path) + shutil.copy(pm_location + "pm.xml", pm_location + "A{}.xml".format(timestemp)) + with open(pm_location + "A{}.xml".format(timestemp), 'rb') as f_in: + with gzip.open(pm_location + "A{}.xml.gz".format(timestemp), 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + os.remove(pm_location + "A{}.xml".format(timestemp)) + rel_path = "FileReadyEvent.json" + file_ready_event_path = os.path.join(script_dir, rel_path) + with open(file_ready_event_path) as json_file: + data = json_file.read().replace("pmfilename", str(timestemp)) + eventdata = json.loads(data) + url = "http://{}:{}/eventListener/v7".format(pnfconfig.VES_IP, pnfconfig.VES_PORT) + print("Sending File Ready Event to VES Collector " + url + " -- data @" + data) + headers = {'content-type': 'application/json'} + requests.post(url, json=eventdata, headers=headers) + except Exception as error: + print(error) diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/pnfconfig.py b/test/mocks/pmsh-pnf-sim/docker-compose/pnfconfig.py new file mode 100644 index 000000000..ca58cea7e --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/pnfconfig.py @@ -0,0 +1,3 @@ +VES_IP = "10.209.57.227" +VES_PORT = "30235" +ROP = 300 # in seconds diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/schedulepmjob.py b/test/mocks/pmsh-pnf-sim/docker-compose/schedulepmjob.py new file mode 100644 index 000000000..ecbd74417 --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/schedulepmjob.py @@ -0,0 +1,14 @@ +import time +import schedule +from pnf import PNF +import pnfconfig + +if __name__ == "__main__": + try: + pnf = PNF() + schedule.every(pnfconfig.rop).seconds.do(lambda: pnf.pm_job(pnfconfig.VES_IP, pnfconfig.VES_PORT)) + while True: + schedule.run_pending() + time.sleep(1) + except Exception as error: + print(error) diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/sftp/pm.xml b/test/mocks/pmsh-pnf-sim/docker-compose/sftp/pm.xml new file mode 100644 index 000000000..375bbbda0 --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/sftp/pm.xml @@ -0,0 +1,41 @@ +<?xml version='1.0' encoding='utf-8'?> +<measCollecFile xmlns="http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec"> + <fileHeader fileFormatVersion="32.435 V7.0" vendorName="Company NN" dnPrefix="DC=a1.companyNN.com,SubNetwork=1,IRPAgent=1"> + <fileSender localDn="SubNetwork=CountryNN,MeContext=MEC-Gbg-1,ManagedElement=RNC-Gbg-1" elementType="RNC" /> + <measCollec beginTime="2000-03-01T14:00:00+02:00" /> + </fileHeader> + <measData> + <managedElement localDn="SubNetwork=CountryNN,MeContext=MEC-Gbg-1,ManagedElement=RNC-Gbg-1" userLabel="RNC Telecomville" /> + <measInfo> + <job jobId="sub0" /> + <granPeriod duration="PT900S" endTime="2000-03-01T14:14:30+02:00" /> + <repPeriod duration="PT1800S" /> + <measType p="1">attTCHSeizures</measType> + <measType p="2">succTCHSeizures</measType> + <measType p="3">attImmediateAssignProcs</measType> + <measType p="4">succImmediateAssignProcs</measType> + <measValue measObjLdn="RncFunction=RF-1,UtranCell=Gbg-997"> + <r p="1">234</r> + <r p="2">345</r> + <r p="3">567</r> + <r p="4">789</r> + </measValue> + <measValue measObjLdn="RncFunction=RF-1,UtranCell=Gbg-998"> + <r p="1">890</r> + <r p="2">901</r> + <r p="3">123</r> + <r p="4">234</r> + </measValue> + <measValue measObjLdn="RncFunction=RF-1,UtranCell=Gbg-999"> + <r p="1">456</r> + <r p="2">567</r> + <r p="3">678</r> + <r p="4">789</r> + <suspect>true</suspect> + </measValue> + </measInfo> + </measData> + <fileFooter> + <measCollec endTime="2000-03-01T14:15:00+02:00" /> + </fileFooter> +</measCollecFile>
\ No newline at end of file diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/startup.xml b/test/mocks/pmsh-pnf-sim/docker-compose/startup.xml new file mode 100644 index 000000000..7bd895093 --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/startup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<subscriptions xmlns="http://onap.org/pnf-subscriptions"> + <configuration> + <subscriptionName>sub0</subscriptionName> + <administrativeState>UNLOCKED</administrativeState> + <fileBasedGP>15</fileBasedGP> + <fileLocation>c://PM</fileLocation> + <measurementGroups> + <id>1</id> + <measurementGroup> + <measurementTypes> + <measurementType>EutranCellRelation.pmCounter1</measurementType> + </measurementTypes> + <measurementTypes> + <measurementType>EutranCellRelation.pmCounter2</measurementType> + </measurementTypes> + <managedObjectDNsBasic> + <DN>ManagedElement=1,ENodeBFunction=1,EUtranCell=CityCenter1</DN> + </managedObjectDNsBasic> + <managedObjectDNsBasic> + <DN>ManagedElement=1,ENodeBFunction=1,EUtranCell=CityCenter1, EUtranCellRelation=CityCenter2</DN> + </managedObjectDNsBasic> + </measurementGroup> + </measurementGroups> + </configuration> +</subscriptions>
\ No newline at end of file diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/subscriber.py b/test/mocks/pmsh-pnf-sim/docker-compose/subscriber.py new file mode 100644 index 000000000..44109a12d --- /dev/null +++ b/test/mocks/pmsh-pnf-sim/docker-compose/subscriber.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +import re +import sysrepo as sr +from pnf import PNF + + +def module_change_cb(sess, module_name, event, private_ctx): + """ Handle event change based on yang operation. """ + try: + change_path = "/" + module_name + ":*" + iterate = sess.get_changes_iter(change_path) + change = sess.get_change_next(iterate) + changelist = [] + operation = change.oper() + pnf = PNF() + if event == sr.SR_EV_APPLY: + print("------------------> Start Handle Change <------------------") + if operation == sr.SR_OP_CREATED: + while True: + change = sess.get_change_next(iterate) + if change is None: + break + changelist.append(change.new_val().to_string()) + result = re.findall(r'\'(.*?)\'', changelist[0]) + jobid = result[0] + print("Subscription Created : " + changelist[0]) + pnf.create_job_id(jobid, changelist) + pnf.pm_job() + elif operation == sr.SR_OP_DELETED: + changelist.append(change.old_val().to_string()) + result = re.findall(r'\'(.*?)\'', changelist[0]) + jobid = result[0] + print("Subscription Deleted : " + changelist[0]) + pnf.delete_job_id(jobid) + pnf.pm_job() + elif operation == sr.SR_OP_MODIFIED: + changelist.append(change.new_val().to_string()) + element = changelist[0] + print("Subscription Modified :" + element) + result = re.findall(r'\'(.*?)\'', changelist[0]) + jobid = result[0] + administrative_state = ((element.rsplit('/', 1)[1]).split('=', 1))[1].strip() + if administrative_state == "LOCKED": + pnf.delete_job_id(jobid) + pnf.pm_job() + elif administrative_state == "UNLOCKED": + select_xpath = "/" + module_name + ":*//*" + values = sess.get_items(select_xpath) + if values is not None: + for i in range(values.val_cnt()): + if jobid in values.val(i).to_string(): + changelist.append(values.val(i).to_string()) + pnf.create_job_id(jobid, changelist) + pnf.pm_job() + else: + print("Unknown Operation") + print("------------------> End Handle Change <------------------") + except Exception as error: + print(error) + return sr.SR_ERR_OK + + +def start(): + """ main function to create connection based on moudule name. """ + try: + module_name = "pnf-subscriptions" + conn = sr.Connection(module_name) + sess = sr.Session(conn) + subscribe = sr.Subscribe(sess) + subscribe.module_change_subscribe(module_name, module_change_cb) + sr.global_loop() + print("Application exit requested, exiting.") + except Exception as error: + print(error) + + +if __name__ == '__main__': + start() |