Add N2VC support 85/5885/5
authorAdam Israel <adam.israel@canonical.com>
Sun, 18 Mar 2018 18:46:23 +0000 (14:46 -0400)
committerAdam Israel <adam.israel@canonical.com>
Fri, 30 Mar 2018 21:44:08 +0000 (17:44 -0400)
This patch adds support for using the N2VC for managing the VCA.

Signed-off-by: Adam Israel <adam.israel@canonical.com>
Change-Id: Iddb0b9b0e5541b2faaf006170354b49830339d1a

lcm/Dockerfile
lcm/osm_lcm/lcm.py

index b603c13..68f6247 100644 (file)
@@ -6,11 +6,23 @@ WORKDIR /app/osm_lcm
 # Copy the current directory contents into the container at /app
 ADD . /app
 
-RUN apt-get update && apt-get install -y git  python3 \
+RUN apt-get update && apt-get install -y git python3 \
     python3-pip python3-pymongo python3-yaml python3-aiohttp \
-    && pip3 install aiokafka juju \
-    && mkdir -p /app/storage/kafka && mkdir -p /app/log 
+    python3-stdeb python3-setuptools python3-all python-all \
+    python3-bitarray python3-regex python3-lxml debhelper dh-python tox wget \
+    python3-cffi \
+    && pip3 install -U aiokafka pyang lxml six enum34
 
+RUN git clone https://osm.etsi.org/gerrit/osm/N2VC.git \
+    && cd N2VC \
+    && git fetch https://osm.etsi.org/gerrit/osm/N2VC refs/changes/70/5870/46 \
+    && git checkout FETCH_HEAD \
+    && cd modules/libjuju && python3 setup.py develop && cd ../.. \
+    && pip3 install -U -r requirements.txt \
+    && python3 setup.py develop \
+    && cd ..
+
+RUN mkdir -p /app/storage/kafka && mkdir -p /app/log
 
 
 LABEL Maintainer="alfonso.tiernosepulveda@telefonica.com" \
@@ -50,4 +62,3 @@ ENV OSMLCM_MESSAGE_PORT    9092
 ENV PYTHONPATH             /app/osm_common
 # Run app.py when the container launches
 CMD ["python3", "lcm.py"]
-
index 3b4ab60..b39efe8 100644 (file)
@@ -15,7 +15,11 @@ from dbbase import DbException
 from fsbase import FsException
 from msgbase import MsgException
 from os import environ
-from vca import DeployApplication, RemoveApplication
+# from vca import DeployApplication, RemoveApplication
+from n2vc.vnf import N2VC
+import os.path
+import time
+
 from copy import deepcopy
 from http import HTTPStatus
 
@@ -44,6 +48,7 @@ class Lcm:
             "logger_name": "lcm.ROclient",
             "loglevel": "ERROR",
         }
+
         self.vca = config["VCA"]  # TODO VCA
         self.loop = None
 
@@ -78,6 +83,19 @@ class Lcm:
             if "loglevel" in config[k1]:
                 logger_module.setLevel(config[k1]["loglevel"])
 
+        self.n2vc = N2VC(
+            log=self.logger,
+            server=config['VCA']['host'],
+            port=config['VCA']['port'],
+            user=config['VCA']['user'],
+            secret=config['VCA']['secret'],
+            # TODO: This should point to the base folder where charms are stored,
+            # if there is a common one (like object storage). Otherwise, leave
+            # it unset and pass it via DeployCharms
+            # artifacts=config['VCA'][''],
+            artifacts=None,
+        )
+
         try:
             if config["database"]["driver"] == "mongo":
                 self.db = dbmongo.DbMongo()
@@ -115,6 +133,70 @@ class Lcm:
         except DbException as e:
             self.logger.error("Updating nsr_id={}: {}".format(nsr_id, e))
 
+    def n2vc_callback(self, nsd, vnfd, vnf_member_index, workload_status, *args):
+        """Update the lcm database with the status of the charm.
+
+        Updates the VNF's operational status with the state of the charm:
+        - blocked: The unit needs manual intervention
+        - maintenance: The unit is actively deploying/configuring
+        - waiting: The unit is waiting for another charm to be ready
+        - active: The unit is deployed, configured, and ready
+        - error: The charm has failed and needs attention.
+        - terminated: The charm has been destroyed
+
+        Updates the network service's config-status to reflect the state of all
+        charms.
+        """
+        if workload_status and len(args) == 3:
+            # self.logger.debug("[n2vc_callback] Workload status \"{}\"".format(workload_status))
+            try:
+                (db_nsr, vnf_index, task) = args
+
+                nsr_id = db_nsr["_id"]
+                nsr_lcm = db_nsr["_admin"]["deploy"]
+                nsr_lcm["VCA"][vnf_index]['operational-status'] = workload_status
+
+                if task:
+                    if task.cancelled():
+                        return
+
+                    if task.done():
+                        exc = task.exception()
+                        if exc:
+                            nsr_lcm = db_nsr["_admin"]["deploy"]
+                            nsr_lcm["VCA"][vnf_index]['operational-status'] = "failed"
+                            db_nsr["detailed-status"] = "fail configuring vnf_index={} {}".format(vnf_index, exc)
+                            db_nsr["config-status"] = "failed"
+                            self.update_nsr_db(nsr_id, db_nsr)
+                else:
+                    units = len(nsr_lcm["VCA"])
+                    active = 0
+                    statusmap = {}
+                    for vnf_index in nsr_lcm["VCA"]:
+                        if 'operational-status' in nsr_lcm["VCA"][vnf_index]:
+
+                            if nsr_lcm["VCA"][vnf_index]['operational-status'] not in statusmap:
+                                # Initialize it
+                                statusmap[nsr_lcm["VCA"][vnf_index]['operational-status']] = 0
+
+                            statusmap[nsr_lcm["VCA"][vnf_index]['operational-status']] += 1
+
+                            if nsr_lcm["VCA"][vnf_index]['operational-status'] == "active":
+                                active += 1
+                        else:
+                            self.logger.debug("No operational-status")
+
+                    cs = ""
+                    for status in statusmap:
+                        cs += "{} ({}) ".format(status, statusmap[status])
+                    db_nsr["config-status"] = cs
+                    self.update_nsr_db(nsr_id, db_nsr)
+
+            except Exception as e:
+                # self.logger.critical("Task create_ns={} n2vc_callback Exception {}".format(nsr_id, e), exc_info=True)
+                self.logger.critical("Task create_ns n2vc_callback Exception {}".format(e), exc_info=True)
+            pass
+
     def vca_deploy_callback(self, db_nsr, vnf_index, status, task):
         # TODO study using this callback when VCA.DeployApplication success from VCAMonitor
         # By the moment this callback is used only to capture exception conditions from VCA DeployApplication
@@ -293,17 +375,14 @@ class Lcm:
                         base_folder["file"],
                         proxy_charm
                     )
+
+                    self.logger.debug("Passing artifacts path '{}' for {}".format(charm_path, proxy_charm))
                     task = asyncio.ensure_future(
-                        DeployApplication(
-                            self.config['VCA'],
-                            self.db,
-                            db_nsr,
-                            vnfd,
-                            vnf_index,
-                            charm_path,
-                        )
+                        self.n2vc.DeployCharms(nsd, vnfd, vnf_index, charm_path, self.n2vc_callback, db_nsr, vnf_index, None)
                     )
-                    task.add_done_callback(functools.partial(self.vca_deploy_callback, db_nsr, vnf_index, None))
+                    task.add_done_callback(functools.partial(self.n2vc_callback, None, None, None, None, None, db_nsr, vnf_index))
+
+                    # task.add_done_callback(functools.partial(self.vca_deploy_callback, db_nsr, vnf_index, None))
                     self.lcm_tasks[nsr_id][order_id]["create_charm:" + vnf_index] = task
             db_nsr["config-status"] = "configuring" if vnfd_to_config else "configured"
             db_nsr["detailed-status"] = "Configuring 1/{}".format(vnfd_to_config) if vnfd_to_config else "done"
@@ -346,13 +425,9 @@ class Lcm:
                 self.logger.debug(logging_text + step)
                 for vnf_index, deploy_info in nsr_lcm["VCA"].items():
                     if deploy_info and deploy_info.get("appliation"):
+
                         task = asyncio.ensure_future(
-                            RemoveApplication(
-                                self.config['VCA'],
-                                self.db,
-                                db_nsr,
-                                vnf_index,
-                            )
+                            self.n2vc.RemoveCharms(nsd, vnfd, vnf_index, self.n2vc_callback, db_nsr, vnf_index, None)
                         )
                         self.lcm_tasks[nsr_id][order_id]["delete_charm:" + vnf_index] = task
             except Exception as e: