Merge "Integration test for metrics + bug fix"
[osm/N2VC.git] / n2vc / vnf.py
index bd6b4f9..f642ead 100644 (file)
@@ -297,7 +297,7 @@ class N2VC:
         ########################################
         app = await self.get_application(model, application_name)
         if app:
-            raise JujuApplicationExists("Can't deploy application \"{}\" to model \"{}\" because it already exists.".format(application_name, model))
+            raise JujuApplicationExists("Can't deploy application \"{}\" to model \"{}\" because it already exists.".format(application_name, model_name))
 
         ################################################################
         # Register this application with the model-level event monitor #
@@ -332,6 +332,10 @@ class N2VC:
         if 'rw_mgmt_ip' in params:
             rw_mgmt_ip = params['rw_mgmt_ip']
 
+        # initial_config = {}
+        if 'initial-config-primitive' not in params:
+            params['initial-config-primitive'] = {}
+
         initial_config = self._get_config_from_dict(
             params['initial-config-primitive'],
             {'<rw_mgmt_ip>': rw_mgmt_ip}
@@ -375,10 +379,14 @@ class N2VC:
                 else:
                     seq = primitive['seq']
 
+                    params = {}
+                    if 'parameter' in primitive:
+                        params = primitive['parameter']
+
                     primitives[seq] = {
                         'name': primitive['name'],
                         'parameters': self._map_primitive_parameters(
-                            primitive['parameter'],
+                            params,
                             {'<rw_mgmt_ip>': rw_mgmt_ip}
                         ),
                     }
@@ -393,11 +401,34 @@ class N2VC:
                             **primitives[primitive]['parameters'],
                         )
             except N2VCPrimitiveExecutionFailed as e:
-                self.debug.log(
+                self.log.debug(
                     "[N2VC] Exception executing primitive: {}".format(e)
                 )
                 raise
 
+    async def GetPrimitiveStatus(self, model_name, uuid):
+        results = None
+        try:
+            if not self.authenticated:
+                await self.login()
+
+            # FIXME: This is hard-coded until model-per-ns is added
+            model_name = 'default'
+
+            model = await self.controller.get_model(model_name)
+
+            results = await model.get_action_output(uuid)
+
+            await model.disconnect()
+        except Exception as e:
+            self.log.debug(
+                "Caught exception while getting primitive status: {}".format(e)
+            )
+            raise N2VCPrimitiveExecutionFailed(e)
+
+        return results
+
+
     async def ExecutePrimitive(self, model_name, application_name, primitive, callback, *callback_args, **params):
         """Execute a primitive of a charm for Day 1 or Day 2 configuration.
 
@@ -428,22 +459,28 @@ class N2VC:
 
             if primitive == 'config':
                 # config is special, and expecting params to be a dictionary
-                self.log.debug("Setting charm configuration for {}".format(application_name))
-                self.log.debug(params['params'])
-                await self.set_config(model, application_name, params['params'])
+                await self.set_config(
+                    model,
+                    application_name,
+                    params['params'],
+                )
             else:
                 app = await self.get_application(model, application_name)
                 if app:
                     # Run against the first (and probably only) unit in the app
                     unit = app.units[0]
                     if unit:
-                        self.log.debug("Executing primitive {}".format(primitive))
+                        self.log.debug(
+                            "Executing primitive {}".format(primitive)
+                        )
                         action = await unit.run_action(primitive, **params)
                         uuid = action.id
                 await model.disconnect()
         except Exception as e:
-            self.log.debug("Caught exception while executing primitive: {}".format(e))
-            raise e
+            self.log.debug(
+                "Caught exception while executing primitive: {}".format(e)
+            )
+            raise N2VCPrimitiveExecutionFailed(e)
         return uuid
 
     async def RemoveCharms(self, model_name, application_name, callback=None, *callback_args):
@@ -550,7 +587,50 @@ class N2VC:
             if parameter['value'] == "<rw_mgmt_ip>":
                 params[param] = str(values[parameter['value']])
             else:
-                params[param] = str(parameter['value'])
+                """
+                The Juju API uses strictly typed data-types, so we must make
+                sure the parameters from the VNFD match the appropriate type.
+
+                The honus will still be on the operator, to make sure the
+                data-type in the VNFD matches the one in the charm. N2VC will
+                raise N2VCPrimitiveExecutionFailed when there is a mismatch.
+
+                There are three data types supported by the YANG model:
+                # - STRING
+                # - INTEGER
+                # - BOOLEAN
+
+                Each parameter will look like this:
+                {
+                    'seq': '3',
+                    'name': 'testint',
+                    'parameter': [
+                        {
+                            'name': 'interval',
+                            'data-type': 'INTEGER',
+                            'value': 20
+                        }
+                    ]
+                }
+                """
+
+                if 'value' in parameter:
+                    # String is the default format
+                    val = str(parameter['value'])
+
+                    # If the data-type is explicitly set, cast to that type.
+                    if 'data-type' in parameter:
+                        dt = parameter['data-type'].upper()
+                        if dt == "INTEGER":
+                            val = int(val)
+
+                        elif dt == "BOOLEAN":
+                            if val in ['true', 'false', '0', '1']:
+                                val = True
+                            else:
+                                val = False
+
+                    params[param] = val
         return params
 
     def _get_config_from_yang(self, config_primitive, values):