diff options
Diffstat (limited to 'src/onaptests/steps/simulator')
-rw-r--r-- | src/onaptests/steps/simulator/pnf/__init__.py | 0 | ||||
-rw-r--r-- | src/onaptests/steps/simulator/pnf/pnf_config.yaml | 16 | ||||
-rw-r--r-- | src/onaptests/steps/simulator/pnf/pnf_instantiate.py | 30 | ||||
-rw-r--r-- | src/onaptests/steps/simulator/pnf/pnf_register.py | 38 | ||||
-rw-r--r-- | src/onaptests/steps/simulator/pnf/utils.py | 157 | ||||
-rw-r--r-- | src/onaptests/steps/simulator/pnf_simulator_cnf/__init__.py | 1 | ||||
-rw-r--r-- | src/onaptests/steps/simulator/pnf_simulator_cnf/pnf_register.py | 144 |
7 files changed, 386 insertions, 0 deletions
diff --git a/src/onaptests/steps/simulator/pnf/__init__.py b/src/onaptests/steps/simulator/pnf/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/onaptests/steps/simulator/pnf/__init__.py diff --git a/src/onaptests/steps/simulator/pnf/pnf_config.yaml b/src/onaptests/steps/simulator/pnf/pnf_config.yaml new file mode 100644 index 0000000..13b0289 --- /dev/null +++ b/src/onaptests/steps/simulator/pnf/pnf_config.yaml @@ -0,0 +1,16 @@ +setup: + count: 1 + vesprotocol: http # use `https` for the real VES + vesip: 172.17.0.1 # use 172.17.0.1 to communicate with localhost + vesport: 10000 + vesresource: eventListener + vesversion: v7 + ipstart: 10.11.0.16 + user: "" + password: "" + ipfileserver: 127.0.0.1 + typefileserver: sftp +data: + commonEventHeaderParams: + sourceName: pyint-000 + reportingEntityName: pyint-000 diff --git a/src/onaptests/steps/simulator/pnf/pnf_instantiate.py b/src/onaptests/steps/simulator/pnf/pnf_instantiate.py new file mode 100644 index 0000000..d9d2620 --- /dev/null +++ b/src/onaptests/steps/simulator/pnf/pnf_instantiate.py @@ -0,0 +1,30 @@ +"""Base step that runs a PNF simulator.""" +from onaptests.steps.simulator.pnf import utils +from onaptests.steps.base import BaseStep + +class PNFInstanceStep(BaseStep): + """Run PNF simulator containers.""" + + @property + def description(self) -> str: + """Step description.""" + return "Run PNF simulator containers." + + @property + def component(self) -> str: + """Component name.""" + return "Environment" + + @BaseStep.store_state + def execute(self) -> None: + """Run PNF simulator containers.""" + super().execute() + utils.build_image() + utils.bootstrap_simulator() + utils.run_container() + + def cleanup(self) -> None: + """Remove containers and images.""" + utils.stop_container() + utils.remove_simulator() + utils.remove_image() diff --git a/src/onaptests/steps/simulator/pnf/pnf_register.py b/src/onaptests/steps/simulator/pnf/pnf_register.py new file mode 100644 index 0000000..8d5467a --- /dev/null +++ b/src/onaptests/steps/simulator/pnf/pnf_register.py @@ -0,0 +1,38 @@ +"""Base step that runs a PNF simulator.""" +from onaptests.steps.simulator.pnf import utils +from onaptests.steps.base import BaseStep +from onaptests.steps.simulator.pnf.pnf_instantiate import PNFInstanceStep + +class PNFRegisterStep(BaseStep): + """Run PNF simulator containers.""" + + def __init__(self, cleanup=True): + """Initialize step. + + Substeps: + - PNFInstanceStep + + """ + super().__init__(cleanup=cleanup) + self.add_step(PNFInstanceStep(cleanup=cleanup)) + + @property + def description(self) -> str: + """Step description.""" + return "Register PNF with VES." + + @property + def component(self) -> str: + """Component name.""" + return "Environment" + + @BaseStep.store_state + def execute(self) -> None: + """Register with VES.""" + super().execute() + utils.register() + + @BaseStep.store_state + def cleanup(self) -> None: + """Substeps cleanup - no unregister.""" + super().cleanup() diff --git a/src/onaptests/steps/simulator/pnf/utils.py b/src/onaptests/steps/simulator/pnf/utils.py new file mode 100644 index 0000000..efac46e --- /dev/null +++ b/src/onaptests/steps/simulator/pnf/utils.py @@ -0,0 +1,157 @@ +"""Utility functions that invoke operations of simulator script.""" +import os +import sys +import time +import urllib.parse +import yaml +from ipaddress import ip_address +from typing import Dict, Optional +from decorator import decorator +import docker + +from onapsdk.configuration import settings +from onaptests.masspnfsimulator.MassPnfSim import ( + MassPnfSim, get_parser +) + +def get_config() -> Dict: + """Read a config YAML file.""" + config = None + dir_path = os.path.dirname(os.path.realpath(__file__)) + with open(f"{dir_path}/pnf_config.yaml", "r") as ymlfile: + config = yaml.load(ymlfile) + return config + +def get_default_args() -> None: + """Prepare default arguments for required operations. + + Returns: + args (argparse.Namespace): default arguments. + + """ + parser = get_parser() + args = parser.parse_args('') + return args + +def switch_workdir(back_pwd: str = None) -> Optional[str]: + """Switch work directory temporarily for PNF simulator operations. + + When `back_pwd` path is provided, it means go back tp the repository + you came from. + + Arguments: + back_pwd: path to go back to. + + Returns: + old_pwd (str): previous path. + + """ + sim_file_path = sys.modules[MassPnfSim.__module__].__file__ + sim_dir_path = os.path.dirname(sim_file_path) + + old_pwd = os.getcwd() + + if not back_pwd: + curr_pwd = sim_dir_path + else: + curr_pwd = back_pwd + + os.chdir(curr_pwd) + return old_pwd + +@decorator +def chdir(func, *args, **kwargs): + """Switches to and from the simulator workspace.""" + old_pwd = switch_workdir() + ret = func(*args, **kwargs) + switch_workdir(old_pwd) + return ret + +@chdir +def build_image() -> None: + """Build simulator image.""" + build = getattr(MassPnfSim(), "build") + args = get_default_args() + build(args) + +@chdir +def remove_image() -> None: + """Remove simulator image(s).""" + client = docker.from_env() + sim_image_name = "nexus3.onap.org:10003/onap/masspnf-simulator" + images = client.images.list(sim_image_name) + for obj in images: + client.images.remove(obj.id, force=True) + +@chdir +def bootstrap_simulator() -> None: + """Setup simulator(s) repo, data and configs.""" + args = get_default_args() + config = get_config() + + # collect settings that will be placed in the simulator directory + vesprotocol = config["setup"].get('vesprotocol', "http") + ves_url = urllib.parse.urlparse(settings.VES_URL) + vesip = ves_url.hostname + vesport = ves_url.port + vesresource = config["setup"].get('vesresource', "") + vesversion = config["setup"].get('vesversion', "") + + urlves = f"{vesprotocol}://{vesip}:{vesport}/{vesresource}/{vesversion}" + + # assign to simulator's arguments + args.count = config["setup"].get('count', 1) + args.urlves = urlves + args.ipstart = ip_address(config["setup"].get('ipstart', '')) + args.ipfileserver = config["setup"].get('ipfileserver', '') + args.typefileserver = config["setup"].get('typefileserver', '') + args.user = config["setup"].get('user', '') + args.password = config["setup"].get('password', '') + + # bootstrap with assigned arguments + bootstrap = getattr(MassPnfSim(), "bootstrap") + bootstrap(args) + +@chdir +def run_container() -> None: + """Run simulator container(s).""" + start = getattr(MassPnfSim(), "start") + args = get_default_args() + start(args) + +@chdir +def register() -> None: + """Send an event to VES. + + Use time.sleep(seconds) if registering with VES right after run_container(). + Containers take a few seconds to run properly. Normally 5 seconds should be + enough. + + """ + time.sleep(5) + config = get_config() + trigger = getattr(MassPnfSim(), "trigger") + args = get_default_args() + + args.user = config['setup'].get('user', '') + args.password = config['setup'].get('password', '') + + custom_data = config['data'] + if custom_data: + args.data = custom_data + + trigger(args) + +@chdir +def stop_container() -> None: + """Stop simulator container(s).""" + stop = getattr(MassPnfSim(), "stop") + args = get_default_args() + stop(args) + +@chdir +def remove_simulator() -> None: + """Remove simulator container(s).""" + clean = getattr(MassPnfSim(), "clean") + args = get_default_args() + clean(args) diff --git a/src/onaptests/steps/simulator/pnf_simulator_cnf/__init__.py b/src/onaptests/steps/simulator/pnf_simulator_cnf/__init__.py new file mode 100644 index 0000000..477f7ae --- /dev/null +++ b/src/onaptests/steps/simulator/pnf_simulator_cnf/__init__.py @@ -0,0 +1 @@ +"""PNF simulator CNF package.""" diff --git a/src/onaptests/steps/simulator/pnf_simulator_cnf/pnf_register.py b/src/onaptests/steps/simulator/pnf_simulator_cnf/pnf_register.py new file mode 100644 index 0000000..a73f668 --- /dev/null +++ b/src/onaptests/steps/simulator/pnf_simulator_cnf/pnf_register.py @@ -0,0 +1,144 @@ +# http://www.apache.org/licenses/LICENSE-2.0 +"""PNF simulator registration module.""" + +import time +from typing import Tuple + +import requests +from kubernetes import client, config, watch +from onapsdk.configuration import settings + +from onaptests.steps.base import BaseStep +from onaptests.steps.instantiate.msb_k8s import CreateInstanceStep +from onaptests.utils.exceptions import EnvironmentPreparationException + + +class PnfSimulatorCnfRegisterStep(BaseStep): + """PNF simulator registration step.""" + + def __init__(self, cleanup: bool = False) -> None: + """Initialize step. + + Substeps: + - CreateInstanceStep. + """ + super().__init__(cleanup=cleanup) + self.add_step(CreateInstanceStep(cleanup=cleanup)) + + @property + def description(self) -> str: + """Step description.""" + return "Register PNF simulator with VES." + + @property + def component(self) -> str: + """Component name.""" + return "Environment" + + @staticmethod + def is_pnf_pod_running(timeout_seconds=120) -> bool: + """Check if PNF simulator pod is running. + + Args: + timeout_seconds (int, optional): Timeout. Defaults to 120. + + Returns: + bool: True if PNF simulator pod is running, False otherwise + + """ + config.load_kube_config(settings.K8S_CONFIG) + k8s_client: "CoreV1API" = client.CoreV1Api() + k8s_watch: "Watch" = watch.Watch() + for event in k8s_watch.stream(k8s_client.list_namespaced_pod, + namespace=settings.K8S_NAMESPACE, + timeout_seconds=timeout_seconds): + if event["object"].metadata.name == "pnf-simulator": + if not event["object"].status.phase in ["Pending", "Running"]: + # Invalid pod state + return False + return event["object"].status.phase == "Running" + return False + + @staticmethod + def get_ves_ip_and_port() -> Tuple[str, str]: + """Static method to get VES ip address and port. + + Raises: + EnvironmentPreparationException: VES pod is not running + + Returns: + Tuple[str, str]: VES IP and port + + """ + config.load_kube_config(settings.K8S_CONFIG) + k8s_client: "CoreV1API" = client.CoreV1Api() + for service in k8s_client.list_namespaced_service(namespace=settings.K8S_NAMESPACE).items: + if service.metadata.name == "xdcae-ves-collector": + return service.spec.cluster_ip, service.spec.ports[0].port + raise EnvironmentPreparationException("Couldn't get VES ip and port") + + @BaseStep.store_state + def execute(self) -> None: + """Send PNF registration event.""" + super().execute() + if not self.is_pnf_pod_running(): + EnvironmentPreparationException("PNF simulator is not running") + time.sleep(30.0) # Let's still wait for PNF simulator to make sure it's initialized + ves_ip, ves_port = self.get_ves_ip_and_port() + response = requests.post( + "http://portal.api.simpledemo.onap.org:30999/simulator/event", + json={ + "vesServerUrl": f"https://{ves_ip}:{ves_port}/eventListener/v7", + "event": { + "event": { + "commonEventHeader": { + "domain": "pnfRegistration", + "eventId": "ORAN_SIM_400600927_2020-04-02T17:20:22.2Z", + "eventName": "pnfRegistration", + "eventType": "EventType5G", + "sequence": 0, + "priority": "Low", + "reportingEntityId": "", + "reportingEntityName": "ORAN_SIM_400600927", + "sourceId": "", + "sourceName": settings.SERVICE_INSTANCE_NAME, + "startEpochMicrosec": 94262132085746, + "lastEpochMicrosec": 94262132085746, + "nfNamingCode": "sdn controller", + "nfVendorName": "sdn", + "timeZoneOffset": "+00:00", + "version": "4.0.1", + "vesEventListenerVersion": "7.0.1" + }, + "pnfRegistrationFields": { + "pnfRegistrationFieldsVersion": "2.0", + "lastServiceDate": "2019-08-16", + "macAddress": "D7:64:C8:CC:E9:32", + "manufactureDate": "2019-08-16", + "modelNumber": "Simulated Device", + "oamV4IpAddress": "172.30.1.6", + "oamV6IpAddress": "0:0:0:0:0:ffff:a0a:011", + "serialNumber": "Simulated Device", + "softwareVersion": "2.3.5", + "unitFamily": "Simulated Device", + "unitType": "ntsim_oran", + "vendorName": "Melacon", + "additionalFields": { + "oamPort": "830", + "protocol": "SSH", + "username": "netconf", + "password": "netconf", + "reconnectOnChangedSchema": "false", + "sleep-factor": "1.5", + "tcpOnly": "false", + "connectionTimeout": "20000", + "maxConnectionAttempts": "100", + "betweenAttemptsTimeout": "2000", + "keepaliveDelay": "120" + } + } + } + } + } + ) + response.raise_for_status() |