[PMSHSIM] Refactoring pmsh-pnf-sim 21/110121/4
authorefiacor <fiachra.corcoran@est.tech>
Fri, 10 Jul 2020 13:58:50 +0000 (14:58 +0100)
committerBartek Grzybowski <b.grzybowski@partner.samsung.com>
Mon, 20 Jul 2020 09:59:36 +0000 (09:59 +0000)
Signed-off-by: efiacor <fiachra.corcoran@est.tech>
Change-Id: I40834e906fcc5f33c6e70fb3d3da886a7ee0d521
Issue-ID: INT-1657

12 files changed:
test/mocks/pmsh-pnf-sim/docker-compose/app_config/logger_config.yaml [new file with mode: 0644]
test/mocks/pmsh-pnf-sim/docker-compose/app_config/pnfconfig.py [new file with mode: 0644]
test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/ca.pem [new file with mode: 0644]
test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/client_cert.pem [new file with mode: 0644]
test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/client_key.pem [new file with mode: 0644]
test/mocks/pmsh-pnf-sim/docker-compose/docker-compose.yml
test/mocks/pmsh-pnf-sim/docker-compose/pnf.py
test/mocks/pmsh-pnf-sim/docker-compose/pnfconfig.py [deleted file]
test/mocks/pmsh-pnf-sim/docker-compose/requirements.txt
test/mocks/pmsh-pnf-sim/docker-compose/schedulepmjob.py
test/mocks/pmsh-pnf-sim/docker-compose/sftp/pm.xml
test/mocks/pmsh-pnf-sim/docker-compose/subscriber.py

diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/app_config/logger_config.yaml b/test/mocks/pmsh-pnf-sim/docker-compose/app_config/logger_config.yaml
new file mode 100644 (file)
index 0000000..d1422dc
--- /dev/null
@@ -0,0 +1,27 @@
+version: 1
+
+disable_existing_loggers: false
+
+loggers:
+  dev:
+    level: DEBUG
+    handlers: [console, file_handler]
+    propagate: false
+
+handlers:
+  console:
+    class: logging.StreamHandler
+    formatter: simple
+  file_handler:
+    class: logging.handlers.RotatingFileHandler
+    filename: config/modules/pnf-subscriptions/pmsh_sim.log
+    mode: a
+    maxBytes: 10000000
+    backupCount: 5
+    formatter: extended
+
+formatters:
+  simple:
+    format: "%(asctime)s %(name)s: %(message)s"
+  extended:
+    format: "%(asctime)s %(name)s %(levelname)s: %(message)s"
diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/app_config/pnfconfig.py b/test/mocks/pmsh-pnf-sim/docker-compose/app_config/pnfconfig.py
new file mode 100644 (file)
index 0000000..5a03489
--- /dev/null
@@ -0,0 +1,5 @@
+VES_IP = '10.10.10.47'
+VES_PORT = '30417'
+VES_USER = 'sample1'
+VES_PASS = 'sample1'
+ROP = 60  # in seconds
diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/ca.pem b/test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/ca.pem
new file mode 100644 (file)
index 0000000..62593ab
--- /dev/null
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID7TCCAtWgAwIBAgIJAMtE1NGAR5KoMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD
+VQQGEwJDWjEWMBQGA1UECAwNU291dGggTW9yYXZpYTENMAsGA1UEBwwEQnJubzEP
+MA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxEzARBgNVBAMMCmV4YW1wbGUg
+Q0ExIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVjYUBsb2NhbGhvc3QwHhcNMTQwNzI0
+MTQxOTAyWhcNMjQwNzIxMTQxOTAyWjCBjDELMAkGA1UEBhMCQ1oxFjAUBgNVBAgM
+DVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEM
+MAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJKoZIhvcNAQkB
+FhNleGFtcGxlY2FAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEArD3TDHPAMT2Z84orK4lMlarbgooIUCcRZyLe+QM+8KY8Hn+mGaxPEOTS
+L3ywszqefB/Utm2hPKLHX684iRC14ID9WDGHxPjvoPArhgFhfV+qnPfxKTgxZC12
+uOj4u1V9y+SkTCocFbRfXVBGpojrBuDHXkDMDEWNvr8/52YCv7bGaiBwUHolcLCU
+bmtKILCG0RNJyTaJpXQdAeq5Z1SJotpbfYFFtAXB32hVoLug1dzl2tjG9sb1wq3Q
+aDExcbC5w6P65qOkNoyym9ne6QlQagCqVDyFn3vcqkRaTjvZmxauCeUxXgJoXkyW
+cm0lM1KMHdoTArmchw2Dz0yHHSyDAQIDAQABo1AwTjAdBgNVHQ4EFgQUc1YQIqjZ
+sHVwlea0AB4N+ilNI2gwHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAI/1KH60qnw9Xs2RGfi0/
+IKf5EynXt4bQX8EIyVKwSkYKe04zZxYfLIl/Q2HOPYoFmm3daj5ddr0ZS1i4p4fT
+UhstjsYWvXs3W/HhVmFUslakkn3PrswhP77fCk6eEJLxdfyJ1C7Uudq2m1isZbKi
+h+XF0mG1LxJaDMocSz4eAya7M5brwjy8DoOmA1TnLQFCVcpn+sCr7VC4wE/JqxyV
+hBCk/MuGqqM3B1j90bGFZ112ZOecyE0EDSr6IbiRBtmeNbEwOFjKXhNLYdxpBZ9D
+8A/368OckZkCrVLGuJNxK9UwCVTe8IhotHUqU9EqFDmxdV8oIdU/OzUwwNPA/Bd/
+9g==
+-----END CERTIFICATE-----
diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/client_cert.pem b/test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/client_cert.pem
new file mode 100644 (file)
index 0000000..d129e46
--- /dev/null
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCQ1ox
+FjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoM
+BkNFU05FVDEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJ
+KoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MB4XDTE1MDczMDA3MjcxOFoX
+DTM1MDcyNTA3MjcxOFowgYUxCzAJBgNVBAYTAkNaMRYwFAYDVQQIDA1Tb3V0aCBN
+b3JhdmlhMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzEXMBUGA1UEAwwO
+ZXhhbXBsZSBjbGllbnQxJjAkBgkqhkiG9w0BCQEWF2V4YW1wbGVjbGllbnRAbG9j
+YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAueCQaNQWoNmF
+K6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68SfFNaY06zZl8QB9W02nr5kWeeMY0
+VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt6jAWZDzVfopwpJPAzRPxACDftIqF
+GagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4VDUHSNVbglc+u4UbEzNIFXMdEFsJ
+ZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuHQwAHdubuB07ObM2z01UhyEdDvEYG
+HwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UEFI1yTYw+xZ42HgFx3uGwApCImxhb
+j69GBYWFqwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVu
+U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUXGpLeLnh2cSDARAV
+A7KrBxGYpo8wHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gwDQYJKoZI
+hvcNAQELBQADggEBAJPV3RTXFRtNyOU4rjPpYeBAIAFp2aqGc4t2J1c7oPp/1n+l
+ZvjnwtlJpZHxMM783e2ryDQ6dkvXDf8kpwKlg3U3mkJ3xKkDdWrM4QwghXdCN519
+aa9qmu0zdFL+jUAaWlQ5tsceOrvbusCcbMqiFGk/QfpHqPv52SVWbYyUx7IX7DE+
+UjgsLHycfV/tlcx4ZE6soTzl9VdgSL/zmzG3rjsr58J80rXckLgBhvijgBlIAJvW
+fC7D0vaouvBInSFXymdPVoUDZ30cdGLf+hI/i/TfsEMOinLrXVdkSGNo6FXAHKSv
+XeB9oFKSzhQ7OPyRyqvEPycUSw/qD6FVr80oDDc=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/client_key.pem b/test/mocks/pmsh-pnf-sim/docker-compose/app_config/tls/client_key.pem
new file mode 100644 (file)
index 0000000..c85aa57
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEpAIBAAKCAQEAueCQaNQWoNmFK6LKu1p8U8ZWdWg/PvDdLsJyzfzl/Qw4UA68
+SfFNaY06zZl8QB9W02nr5kWeeMY0VA3adrPgOlvfx3oWlFbkETnMaN4OT3WTQ0Wt
+6jAWZDzVfopwpJPAzRPxACDftIqFGagYcF32hZlVNqqnVdbXh0S0EViweqp/dbG4
+VDUHSNVbglc+u4UbEzNIFXMdEFsJZpkynOmSiTsIATqIhb+2srkVgLwhfkC2qkuH
+QwAHdubuB07ObM2z01UhyEdDvEYGHwtYAGDBL2TAcsI0oGeVkRyuOkV0QY0UN7UE
+FI1yTYw+xZ42HgFx3uGwApCImxhbj69GBYWFqwIDAQABAoIBAQCZN9kR8DGu6V7y
+t0Ax68asL8O5B/OKaHWKQ9LqpVrXmikZJOxkbzoGldow/CIFoU+q+Zbwu9aDa65a
+0wiP7Hoa4Py3q5XNNUrOQDyU/OYC7cI0I83WS0lJ2zOJGYj8wKae5Z81IeQFKGHK
+4lsy1OGPAvPRGh7RjUUgRavA2MCwe07rWRuDb/OJFe4Oh56UMEjwMiNBtMNtncog
+j1vr/qgRJdf9tf0zlJmLvUJ9+HSFFV9I/97LJyFhb95gAfHkjdVroLVgT3Cho+4P
+WtZaKCIGD0OwfOG2nLV4leXvRUk62/LMlB8NI9+JF7Xm+HCKbaWHNWC7mvWSLV58
+Zl4AbUWRAoGBANyJ6SFHFRHSPDY026SsdMzXR0eUxBAK7G70oSBKKhY+O1j0ocLE
+jI2krHJBhHbLlnvJVyMUaCUOTS5m0uDw9hgSsAqeSL3hL38kxVZw+KNG9Ouno1Fl
+KnE/xXHlPQyeGs/P8nAMzHZxQtEsQdQayJEhK2XXHTsy7Q3MxDisfVJ1AoGBANfD
+34gB+OMx6pwj7zk3qWbYXSX8xjCZMR0ciko+h4xeMP2N8B0oyoqC+v1ABMAtJ3wG
+sGZd0hV9gwM7OUM3SEwkn6oeg1GemWLcn4rlSmTnZc4aeVwrEWlnSNFX3s4g9l4u
+k8Ugu4MVJYqH8HuDQ5Ggl6/QAwPzMSEdCW0O+jOfAoGAIBRbegC5+t6m7Yegz4Ja
+dxV1g98K6f58x+MDsQu4tYWV4mmrQgaPH2dtwizvlMwmdpkh+LNWNtWuumowkJHc
+akIFo3XExQIFg6wYnGtQb4e5xrGa2xMpKlIJaXjb+YLiCYqJDG2ALFZrTrvuU2kV
+9a5qfqTc1qigvNolTM0iaaUCgYApmrZWhnLUdEKV2wP813PNxfioI4afxlpHD8LG
+sCn48gymR6E+Lihn7vuwq5B+8fYEH1ISWxLwW+RQUjIneNhy/jjfV8TgjyFqg7or
+0Sy4KjpiNI6kLBXOakELRNNMkeSPopGR2E7v5rr3bGD9oAD+aqX1G7oJH/KgPPYd
+Vl7+ZwKBgQDcHyWYrimjyUgKaQD2GmoO9wdcJYQ59ke9K+OuGlp4ti5arsi7N1tP
+B4f09aeELM2ASIuk8Q/Mx0jQFnm8lzRFXdewgvdPoZW/7VufM9O7dGPOc41cm2Dh
+yrTcXx/VmUBb+/fnXVEgCv7gylp/wtdTGHQBQJHR81jFBz0lnLj+gg==
+-----END CERTIFICATE-----
\ No newline at end of file
index d32eae0..9133d58 100644 (file)
@@ -2,7 +2,7 @@ version: '3'
 
 services:
   netopeer2:
-    image: nexus3.onap.org:10001/onap/integration/simulators/netconf-pnp-simulator:2.8.2
+    image: nexus3.onap.org:10001/onap/integration/simulators/netconf-pnp-simulator:2.8.6
     container_name: netconf-pnp-pmsh
     restart: always
     ports:
@@ -10,6 +10,7 @@ services:
       - "6513:6513"
     volumes:
       - ./:/config/modules/pnf-subscriptions
+
   sftp:
     container_name: sftpserver
     image: atmoz/sftp
@@ -18,3 +19,15 @@ services:
     volumes:
       - /host/upload:/home/admin
     command: admin:admin:1001
+
+  opendaylight:
+    image: blueonap/opendaylight:v0.12.1-1
+    container_name: opendaylight
+    ports:
+      - "8101:8101"
+      - "8181:8181"
+      - "6666:6666"
+    environment:
+      - KARAF_FEATURES_BOOT=odl-restconf-all,odl-netconf-connector-all
+    volumes:
+      - ./app_config/tls:/config/tls
index 05b09ba..a187ff7 100644 (file)
@@ -1,12 +1,18 @@
 import gzip
 import json
+import logging
 import os
 import shutil
 import time
-import xml.etree.ElementTree as ET
+import xml.etree.ElementTree as ElementTree
 from random import randint
+
 import requests
-import pnfconfig
+from requests.auth import HTTPBasicAuth
+
+from app_config import pnfconfig
+
+logger = logging.getLogger('dev')
 
 
 class PNF:
@@ -32,26 +38,26 @@ class PNF:
             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")
+            ElementTree.register_namespace('', "http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec")
+            tree = ElementTree.parse(pm_location + "pm.xml")
             root = tree.getroot()
             attrib = {}
-            measinfo = ET.SubElement(root[1], 'measInfo', attrib)
+            measinfo = ElementTree.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'})
+            ElementTree.SubElement(measinfo, 'job', attrib)
+            ElementTree.SubElement(measinfo, 'granPeriod', {'duration': 'PT900S', 'endTime': '2000-03-01T14:14:30+02:00'})
+            ElementTree.SubElement(measinfo, 'repPeriod', {'duration': 'PT1800S'})
             for items in range(len(measurement_type)):
-                meastype = ET.SubElement(measinfo, 'measType', {'p': (items + 1).__str__()})
+                meastype = ElementTree.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]})
+                measvalue = ElementTree.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 = ElementTree.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)
+            logger.debug(error)
 
     @staticmethod
     def delete_job_id(jobid):
@@ -63,17 +69,19 @@ class PNF:
             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")
+            ElementTree.register_namespace(
+                '', "http://www.3gpp.org/ftp/specs/archive/32_series/32.435#measCollec")
+            tree = ElementTree.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
+                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)
+            logger.debug(error)
 
     @staticmethod
     def pm_job():
@@ -83,21 +91,23 @@ class PNF:
         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:
+            pm_location = os.path.join(script_dir, 'sftp/')
+            shutil.copy(pm_location + 'pm.xml', pm_location + f'A{timestemp}.xml')
+            with open(pm_location + f'A{timestemp}.xml', 'rb') as f_in:
+                with gzip.open(pm_location + f'A{timestemp}.xml.gz', '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:
+            os.remove(pm_location + f'A{timestemp}.xml')
+            with open(os.path.join(script_dir, 'FileReadyEvent.json')) 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)
+            session = requests.Session()
+            url = f'https://{pnfconfig.VES_IP}:{pnfconfig.VES_PORT}/eventListener/v7'
+            logger.debug(f'Sending File Ready Event to VES Collector {url} -- data @{data}')
+            headers = {'content-type': 'application/json',
+                       'x-transactionid': '123456'}
+            response = session.post(url, json=eventdata, headers=headers,
+                                    auth=HTTPBasicAuth(pnfconfig.VES_USER, pnfconfig.VES_PASS),
+                                    verify=False)
+            response.raise_for_status()
         except Exception as error:
-            print(error)
+            logger.debug(f'Exception caught {error}', exc_info=True)
diff --git a/test/mocks/pmsh-pnf-sim/docker-compose/pnfconfig.py b/test/mocks/pmsh-pnf-sim/docker-compose/pnfconfig.py
deleted file mode 100644 (file)
index ca58cea..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-VES_IP = "10.209.57.227"
-VES_PORT = "30235"
-ROP = 300   # in seconds
index 2c6c587..2e916de 100644 (file)
@@ -1,16 +1,28 @@
 #!/usr/bin/env python3
-
+import logging.config
+import os
+import sys
 import time
+
 import schedule
+import yaml
+
+from app_config import pnfconfig
 from pnf import PNF
-import pnfconfig
+
+log_file_path = os.path.join(os.path.dirname(__file__), 'app_config/logger_config.yaml')
+with open(log_file_path, 'r') as f:
+    log_cfg = yaml.safe_load(f.read())
+logging.config.dictConfig(log_cfg)
+logger = logging.getLogger('dev')
 
 if __name__ == "__main__":
     try:
-        pnf = PNF()
-        schedule.every(pnfconfig.ROP).seconds.do(pnf.pm_job)
+        schedule.every(pnfconfig.ROP).seconds.do(PNF.pm_job)
+        logger.info('Starting PM scheduling job')
         while True:
             schedule.run_pending()
             time.sleep(1)
     except Exception as error:
-        print(error)
+        logger.debug(error)
+        sys.exit(1)
index 375bbbd..41344f1 100644 (file)
@@ -1,7 +1,7 @@
 <?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" />
+    <fileHeader dnPrefix="DC=a1.companyNN.com,SubNetwork=1,IRPAgent=1" fileFormatVersion="32.435 V7.0" vendorName="Company NN">
+        <fileSender elementType="RNC" localDn="SubNetwork=CountryNN,MeContext=MEC-Gbg-1,ManagedElement=RNC-Gbg-1" />
         <measCollec beginTime="2000-03-01T14:00:00+02:00" />
     </fileHeader>
     <measData>
index 628b330..cc2a24e 100755 (executable)
 #!/usr/bin/env python3
 
+import logging.config
+import os
 import re
+
 import sysrepo as sr
+import yaml
+
 from pnf import PNF
 
+log_file_path = os.path.join(os.path.dirname(__file__), 'app_config/logger_config.yaml')
+with open(log_file_path, 'r') as f:
+    log_cfg = yaml.safe_load(f.read())
+logging.config.dictConfig(log_cfg)
+logger = logging.getLogger('dev')
+
 
 def module_change_cb(sess, module_name, event, private_ctx):
     """  Handle event change based on yang operation. """
     try:
-        change_path = "/" + module_name + ":*"
+        change_path = f'/{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 <------------------")
+            logger.info('------------------> 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()
+                create_sub(changelist, iterate, pnf, sess)
             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()
+                delete_sub(change, changelist, pnf)
             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()
+                edit_sub(change, changelist, module_name, pnf, sess)
             else:
-                print("Unknown Operation")
-            print("------------------> End Handle Change <------------------")
+                logger.info('Unknown Operation')
+            logger.info('------------------> End Handle Change <------------------')
     except Exception as error:
-        print(error)
+        logger.info(error, exc_info=True)
     return sr.SR_ERR_OK
 
 
+def edit_sub(change, changelist, module_name, pnf, sess):
+    changelist.append(change.new_val().to_string())
+    element = changelist[0]
+    jobid = get_job_id(changelist)
+    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()
+    logger.info(f'Subscription Modified : {element}')
+
+
+def create_sub(changelist, iterate, pnf, sess):
+    while True:
+        change = sess.get_change_next(iterate)
+        if change is None:
+            break
+        changelist.append(change.new_val().to_string())
+    jobid = get_job_id(changelist)
+    pnf.create_job_id(jobid, changelist)
+    pnf.pm_job()
+    logger.info(f'Subscription Created : {changelist[0]}')
+
+
+def delete_sub(change, changelist, pnf):
+    changelist.append(change.old_val().to_string())
+    jobid = get_job_id(changelist)
+    pnf.delete_job_id(jobid)
+    pnf.pm_job()
+    logger.info(f'Subscription Deleted : {changelist[0]}')
+
+
+def get_job_id(changelist):
+    result = re.findall(r'\'(.*?)\'', changelist[0])
+    jobid = result[0]
+    return jobid
+
+
 def start():
-    """ main function to create connection based on moudule name. """
+    """ main function to create connection based on module name. """
     try:
-        module_name = "pnf-subscriptions"
+        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.")
+        logger.info('Application exit requested, exiting.')
     except Exception as error:
-        print(error)
+        logger.error(error, exc_info=True)
 
 
 if __name__ == '__main__':