From 95843eb0910fc9a0f05fc680160c5dec2aba1ba2 Mon Sep 17 00:00:00 2001 From: Eli Halych Date: Wed, 25 Nov 2020 10:52:03 +0000 Subject: Add PNF simulator execution and cleanup as a BaseStep 1. The simulator is the masspnfsim from integration project. Added as a git submodule. 2. The flow: build image, bootstrap simulator, run simulator, stop simulator, remove simulator, remove image (only simulator). 3. Additionally trigger (sending a message to VES) is handled in pnf/utils.py. To send a request to VES, vesip in settings.PNF_VES_CONFIG should be set to the one accessible from simulator container. Default one (172.17.0.1) communicates with the machine the simulator runs at. 4. commonEventHeader's fields can be overridden in settings.py (here sourceName, reportingEntityName) Issue-ID: TEST-278 Signed-off-by: Eli Halych Change-Id: Id77dc8c517a30458abd81f2aadc416204be522b5 --- .gitignore | 1 + .gitmodules | 3 + requirements.txt | 1 + src/onaptests/integration | 1 + src/onaptests/steps/simulator/pnf/__init__.py | 0 src/onaptests/steps/simulator/pnf/pnf_config.yaml | 16 +++ .../steps/simulator/pnf/pnf_instantiate.py | 30 ++++ src/onaptests/steps/simulator/pnf/pnf_register.py | 38 +++++ src/onaptests/steps/simulator/pnf/utils.py | 153 +++++++++++++++++++++ 9 files changed, 243 insertions(+) create mode 100644 .gitmodules create mode 160000 src/onaptests/integration create mode 100644 src/onaptests/steps/simulator/pnf/__init__.py create mode 100644 src/onaptests/steps/simulator/pnf/pnf_config.yaml create mode 100644 src/onaptests/steps/simulator/pnf/pnf_instantiate.py create mode 100644 src/onaptests/steps/simulator/pnf/pnf_register.py create mode 100644 src/onaptests/steps/simulator/pnf/utils.py diff --git a/.gitignore b/.gitignore index c3fd147..69cc86e 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ csit/ benchmark/ .tox/ **/__pycache__/ +*.pyc diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..bf396ae --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/onaptests/integration"] + path = src/onaptests/integration + url = ../../integration diff --git a/requirements.txt b/requirements.txt index f56f12e..ead56f4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ openstacksdk onapsdk>=7.1.0 jinja2 kubernetes +docker \ No newline at end of file diff --git a/src/onaptests/integration b/src/onaptests/integration new file mode 160000 index 0000000..b019459 --- /dev/null +++ b/src/onaptests/integration @@ -0,0 +1 @@ +Subproject commit b01945987f9a0ab3ac5f4895ffd03c8e975036b4 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 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..31ea6bf --- /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.""" + utils.build_image() + utils.bootstrap_simulator() + utils.run_container() + + @BaseStep.store_state + 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..3f9b233 --- /dev/null +++ b/src/onaptests/steps/simulator/pnf/utils.py @@ -0,0 +1,153 @@ +"""Utility functions that invoke operations of simulator script.""" +import os +import sys +import time +import yaml +from ipaddress import ip_address +from typing import Dict, Optional +from decorator import decorator +import docker +from onaptests.integration.test.mocks.masspnfsim.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") + vesip = config["setup"].get('vesip', "") + vesport = config["setup"].get('vesport', "") + 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) -- cgit 1.2.3-korg