Enable lint, flake8 and unit tests 72/8872/1
authorbeierlm <mark.beierl@canonical.com>
Tue, 21 Apr 2020 20:36:35 +0000 (16:36 -0400)
committerDavid Garcia <david.garcia@canonical.com>
Thu, 7 May 2020 09:03:32 +0000 (11:03 +0200)
Cleans up non pep compliant code.
Adds a simple unit test.
Formats according to black.

Tox automatically runs lint, flake8 and unit test suite
with coverage.  To run each individually, execute:

tox -e pylint
tox -e black
tox -e flake8
tox -e cover

Note that these are all run for each patch via Jenkins.  The full
tox suite should be run locally before any commit to ensure it
will not fail in Jenkins.

Change-Id: I2f87abe3d5086d6d65ac33a27780c498fc7b1cd3
Signed-off-by: beierlm <mark.beierl@canonical.com>
19 files changed:
.gitignore
devops-stages/stage-test.sh
n2vc/__init__.py
n2vc/exceptions.py
n2vc/juju_observer.py
n2vc/k8s_conn.py
n2vc/k8s_helm_conn.py
n2vc/k8s_juju_conn.py
n2vc/loggable.py
n2vc/n2vc_conn.py
n2vc/n2vc_juju_conn.py
n2vc/provisioner.py
n2vc/tests/__init__.py [new file with mode: 0644]
n2vc/tests/unit/__init__.py [new file with mode: 0644]
n2vc/tests/unit/test_provisioner.py [new file with mode: 0644]
n2vc/vnf.py
requirements.txt
test-requirements.txt [new file with mode: 0644]
tox.ini

index 543898d..11426c9 100644 (file)
@@ -1,3 +1,17 @@
+# Copyright 2020 Canonical Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#     Unless required by applicable law or agreed to in writing, software
+#     distributed under the License is distributed on an "AS IS" BASIS,
+#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#     See the License for the specific language governing permissions and
+#     limitations under the License.
+
 __pycache__
 *.pyc
 .tox/
 __pycache__
 *.pyc
 .tox/
@@ -7,3 +21,12 @@ dist/
 .cache/
 .local/
 N2VC.egg-info/
 .cache/
 .local/
 N2VC.egg-info/
+.coverage
+cover
+coverage.xml
+.tox
+nosetests.xml
+.cache
+.vscode/
+.project
+.pydevproject
index 9c960cb..a4a0604 100755 (executable)
@@ -13,4 +13,4 @@
 #     limitations under the License.
 
 #!/bin/sh
 #     limitations under the License.
 
 #!/bin/sh
-#tox
+tox
\ No newline at end of file
index ac8adf5..d97c31c 100644 (file)
@@ -12,4 +12,4 @@
 #     See the License for the specific language governing permissions and
 #     limitations under the License.
 
 #     See the License for the specific language governing permissions and
 #     limitations under the License.
 
-version = '0.0.2'
+version = "0.0.2"
index 815d4ea..09f3573 100644 (file)
@@ -41,7 +41,7 @@ class AuthenticationFailed(Exception):
     """The authentication for the specified user failed."""
 
 
     """The authentication for the specified user failed."""
 
 
-class NotImplemented(Exception):
+class MethodNotImplemented(Exception):
     """The method is not implemented."""
 
 
     """The method is not implemented."""
 
 
@@ -50,7 +50,7 @@ class N2VCException(Exception):
     N2VC exception base class
     """
 
     N2VC exception base class
     """
 
-    def __init__(self, message: str = ''):
+    def __init__(self, message: str = ""):
         Exception.__init__(self, message)
         self.message = message
 
         Exception.__init__(self, message)
         self.message = message
 
@@ -58,7 +58,7 @@ class N2VCException(Exception):
         return self.message
 
     def __repr__(self):
         return self.message
 
     def __repr__(self):
-        return '{}({})'.format(type(self), self.message)
+        return "{}({})".format(type(self), self.message)
 
 
 class N2VCBadArgumentsException(N2VCException):
 
 
 class N2VCBadArgumentsException(N2VCException):
@@ -66,12 +66,14 @@ class N2VCBadArgumentsException(N2VCException):
     Bad argument values exception
     """
 
     Bad argument values exception
     """
 
-    def __init__(self, message: str = '', bad_args: list = None):
+    def __init__(self, message: str = "", bad_args: list = None):
         N2VCException.__init__(self, message=message)
         self.bad_args = bad_args
 
     def __str__(self):
         N2VCException.__init__(self, message=message)
         self.bad_args = bad_args
 
     def __str__(self):
-        return '<{}> Bad arguments: {} -> {}'.format(type(self), super().__str__(), self.bad_args)
+        return "<{}> Bad arguments: {} -> {}".format(
+            type(self), super().__str__(), self.bad_args
+        )
 
 
 class N2VCConnectionException(N2VCException):
 
 
 class N2VCConnectionException(N2VCException):
@@ -79,12 +81,14 @@ class N2VCConnectionException(N2VCException):
     Error connecting to VCA
     """
 
     Error connecting to VCA
     """
 
-    def __init__(self, message: str = '', url: str = None):
+    def __init__(self, message: str = "", url: str = None):
         N2VCException.__init__(self, message=message)
         self.url = url
 
     def __str__(self):
         N2VCException.__init__(self, message=message)
         self.url = url
 
     def __str__(self):
-        return '<{}> Connection to {} failed: {}'.format(type(self), self.url, super().__str__())
+        return "<{}> Connection to {} failed: {}".format(
+            type(self), self.url, super().__str__()
+        )
 
 
 class N2VCTimeoutException(N2VCException):
 
 
 class N2VCTimeoutException(N2VCException):
@@ -92,12 +96,12 @@ class N2VCTimeoutException(N2VCException):
     Timeout
     """
 
     Timeout
     """
 
-    def __init__(self, message: str = '', timeout: str = ''):
+    def __init__(self, message: str = "", timeout: str = ""):
         N2VCException.__init__(self, message=message)
         self.timeout = timeout
 
     def __str__(self):
         N2VCException.__init__(self, message=message)
         self.timeout = timeout
 
     def __str__(self):
-        return '<{}> {} timeout: {}'.format(type(self), self.timeout, super().__str__())
+        return "<{}> {} timeout: {}".format(type(self), self.timeout, super().__str__())
 
 
 class N2VCExecutionException(N2VCException):
 
 
 class N2VCExecutionException(N2VCException):
@@ -105,12 +109,14 @@ class N2VCExecutionException(N2VCException):
     Error executing primitive
     """
 
     Error executing primitive
     """
 
-    def __init__(self, message: str = '', primitive_name: str = ''):
+    def __init__(self, message: str = "", primitive_name: str = ""):
         N2VCException.__init__(self, message=message)
         self.primitive_name = primitive_name
 
     def __str__(self):
         N2VCException.__init__(self, message=message)
         self.primitive_name = primitive_name
 
     def __str__(self):
-        return '<{}> Error executing primitive {} failed: {}'.format(type(self), self.primitive_name, super().__str__())
+        return "<{}> Error executing primitive {} failed: {}".format(
+            type(self), self.primitive_name, super().__str__()
+        )
 
 
 class N2VCInvalidCertificate(N2VCException):
 
 
 class N2VCInvalidCertificate(N2VCException):
@@ -118,11 +124,11 @@ class N2VCInvalidCertificate(N2VCException):
     Invalid certificate
     """
 
     Invalid certificate
     """
 
-    def __init__(self, message: str = ''):
+    def __init__(self, message: str = ""):
         N2VCException.__init__(self, message=message)
 
     def __str__(self):
         N2VCException.__init__(self, message=message)
 
     def __str__(self):
-        return '<{}> Invalid certificate: {}'.format(type(self), super().__str__())
+        return "<{}> Invalid certificate: {}".format(type(self), super().__str__())
 
 
 class N2VCNotFound(N2VCException):
 
 
 class N2VCNotFound(N2VCException):
@@ -130,11 +136,11 @@ class N2VCNotFound(N2VCException):
     Not found
     """
 
     Not found
     """
 
-    def __init__(self, message: str = ''):
+    def __init__(self, message: str = ""):
         N2VCException.__init__(self, message=message)
 
     def __str__(self):
         N2VCException.__init__(self, message=message)
 
     def __str__(self):
-        return '<{}> Not found: {}'.format(type(self), super().__str__())
+        return "<{}> Not found: {}".format(type(self), super().__str__())
 
 
 class K8sException(Exception):
 
 
 class K8sException(Exception):
index e2f0470..7ed3dee 100644 (file)
 import asyncio
 import time
 
 import asyncio
 import time
 
-from juju.model import ModelObserver, Model
-from juju.machine import Machine
-from juju.application import Application
 from juju.action import Action
 from juju.action import Action
+from juju.application import Application
+from juju.machine import Machine
+from juju.model import ModelObserver, Model
 
 
-from n2vc.n2vc_conn import N2VCConnector, juju_status_2_osm_status
 from n2vc.exceptions import N2VCTimeoutException
 from n2vc.exceptions import N2VCTimeoutException
+from n2vc.n2vc_conn import N2VCConnector, juju_status_2_osm_status
 
 
 class _Entity:
 
 
 class _Entity:
@@ -42,7 +42,6 @@ class _Entity:
 
 
 class JujuModelObserver(ModelObserver):
 
 
 class JujuModelObserver(ModelObserver):
-
     def __init__(self, n2vc: N2VCConnector, model: Model):
         self.n2vc = n2vc
         self.model = model
     def __init__(self, n2vc: N2VCConnector, model: Model):
         self.n2vc = n2vc
         self.model = model
@@ -54,11 +53,14 @@ class JujuModelObserver(ModelObserver):
     def register_machine(self, machine: Machine, db_dict: dict):
         try:
             entity_id = machine.entity_id
     def register_machine(self, machine: Machine, db_dict: dict):
         try:
             entity_id = machine.entity_id
-        except Exception as e:
+        except Exception:
             # no entity_id aatribute, try machine attribute
             entity_id = machine.machine
             # no entity_id aatribute, try machine attribute
             entity_id = machine.machine
-        # self.n2vc.debug(msg='Registering machine for change notifications: {}'.format(entity_id))
-        entity = _Entity(entity_id=entity_id, entity_type='machine', obj=machine, db_dict=db_dict)
+        # self.n2vc.debug(
+        #   msg='Registering machine for change notifications: {}'.format(entity_id))
+        entity = _Entity(
+            entity_id=entity_id, entity_type="machine", obj=machine, db_dict=db_dict
+        )
         self.machines[entity_id] = entity
 
     def unregister_machine(self, machine_id: str):
         self.machines[entity_id] = entity
 
     def unregister_machine(self, machine_id: str):
@@ -70,8 +72,14 @@ class JujuModelObserver(ModelObserver):
 
     def register_application(self, application: Application, db_dict: dict):
         entity_id = application.entity_id
 
     def register_application(self, application: Application, db_dict: dict):
         entity_id = application.entity_id
-        # self.n2vc.debug(msg='Registering application for change notifications: {}'.format(entity_id))
-        entity = _Entity(entity_id=entity_id, entity_type='application', obj=application, db_dict=db_dict)
+        # self.n2vc.debug(
+        #  msg='Registering application for change notifications: {}'.format(entity_id))
+        entity = _Entity(
+            entity_id=entity_id,
+            entity_type="application",
+            obj=application,
+            db_dict=db_dict,
+        )
         self.applications[entity_id] = entity
 
     def unregister_application(self, application_id: str):
         self.applications[entity_id] = entity
 
     def unregister_application(self, application_id: str):
@@ -83,8 +91,11 @@ class JujuModelObserver(ModelObserver):
 
     def register_action(self, action: Action, db_dict: dict):
         entity_id = action.entity_id
 
     def register_action(self, action: Action, db_dict: dict):
         entity_id = action.entity_id
-        # self.n2vc.debug(msg='Registering action for changes notifications: {}'.format(entity_id))
-        entity = _Entity(entity_id=entity_id, entity_type='action', obj=action, db_dict=db_dict)
+        # self.n2vc.debug(
+        #    msg='Registering action for changes notifications: {}'.format(entity_id))
+        entity = _Entity(
+            entity_id=entity_id, entity_type="action", obj=action, db_dict=db_dict
+        )
         self.actions[entity_id] = entity
 
     def unregister_action(self, action_id: str):
         self.actions[entity_id] = entity
 
     def unregister_action(self, action_id: str):
@@ -95,74 +106,81 @@ class JujuModelObserver(ModelObserver):
         return action_id in self.actions
 
     async def wait_for_machine(
         return action_id in self.actions
 
     async def wait_for_machine(
-            self,
-            machine_id: str,
-            progress_timeout: float = None,
-            total_timeout: float = None) -> int:
+        self,
+        machine_id: str,
+        progress_timeout: float = None,
+        total_timeout: float = None,
+    ) -> int:
 
         if not self.is_machine_registered(machine_id):
             return
 
 
         if not self.is_machine_registered(machine_id):
             return
 
-        self.n2vc.debug('Waiting for machine completed: {}'.format(machine_id))
+        self.n2vc.debug("Waiting for machine completed: {}".format(machine_id))
 
         # wait for a final state
         entity = self.machines[machine_id]
         return await self._wait_for_entity(
             entity=entity,
 
         # wait for a final state
         entity = self.machines[machine_id]
         return await self._wait_for_entity(
             entity=entity,
-            field_to_check='agent_status',
-            final_states_list=['started'],
+            field_to_check="agent_status",
+            final_states_list=["started"],
             progress_timeout=progress_timeout,
             progress_timeout=progress_timeout,
-            total_timeout=total_timeout)
+            total_timeout=total_timeout,
+        )
 
     async def wait_for_application(
 
     async def wait_for_application(
-            self,
-            application_id: str,
-            progress_timeout: float = None,
-            total_timeout: float = None) -> int:
+        self,
+        application_id: str,
+        progress_timeout: float = None,
+        total_timeout: float = None,
+    ) -> int:
 
         if not self.is_application_registered(application_id):
             return
 
 
         if not self.is_application_registered(application_id):
             return
 
-        self.n2vc.debug('Waiting for application completed: {}'.format(application_id))
+        self.n2vc.debug("Waiting for application completed: {}".format(application_id))
 
         # application statuses: unknown, active, waiting
         # wait for a final state
         entity = self.applications[application_id]
         return await self._wait_for_entity(
             entity=entity,
 
         # application statuses: unknown, active, waiting
         # wait for a final state
         entity = self.applications[application_id]
         return await self._wait_for_entity(
             entity=entity,
-            field_to_check='status',
-            final_states_list=['active', 'blocked'],
+            field_to_check="status",
+            final_states_list=["active", "blocked"],
             progress_timeout=progress_timeout,
             progress_timeout=progress_timeout,
-            total_timeout=total_timeout)
+            total_timeout=total_timeout,
+        )
 
     async def wait_for_action(
 
     async def wait_for_action(
-            self,
-            action_id: str,
-            progress_timeout: float = None,
-            total_timeout: float = None) -> int:
+        self,
+        action_id: str,
+        progress_timeout: float = None,
+        total_timeout: float = None,
+    ) -> int:
 
         if not self.is_action_registered(action_id):
             return
 
 
         if not self.is_action_registered(action_id):
             return
 
-        self.n2vc.debug('Waiting for action completed: {}'.format(action_id))
+        self.n2vc.debug("Waiting for action completed: {}".format(action_id))
 
         # action statuses: pending, running, completed, failed, cancelled
         # wait for a final state
         entity = self.actions[action_id]
         return await self._wait_for_entity(
             entity=entity,
 
         # action statuses: pending, running, completed, failed, cancelled
         # wait for a final state
         entity = self.actions[action_id]
         return await self._wait_for_entity(
             entity=entity,
-            field_to_check='status',
-            final_states_list=['completed', 'failed', 'cancelled'],
+            field_to_check="status",
+            final_states_list=["completed", "failed", "cancelled"],
             progress_timeout=progress_timeout,
             progress_timeout=progress_timeout,
-            total_timeout=total_timeout)
+            total_timeout=total_timeout,
+        )
 
     async def _wait_for_entity(
 
     async def _wait_for_entity(
-            self,
-            entity: _Entity,
-            field_to_check: str,
-            final_states_list: list,
-            progress_timeout: float = None,
-            total_timeout: float = None) -> int:
+        self,
+        entity: _Entity,
+        field_to_check: str,
+        final_states_list: list,
+        progress_timeout: float = None,
+        total_timeout: float = None,
+    ) -> int:
 
         # default values for no timeout
         if total_timeout is None:
 
         # default values for no timeout
         if total_timeout is None:
@@ -176,8 +194,10 @@ class JujuModelObserver(ModelObserver):
 
         if now >= total_end:
             raise N2VCTimeoutException(
 
         if now >= total_end:
             raise N2VCTimeoutException(
-                message='Total timeout {} seconds, {}: {}'.format(total_timeout, entity.entity_type, entity.entity_id),
-                timeout='total'
+                message="Total timeout {} seconds, {}: {}".format(
+                    total_timeout, entity.entity_type, entity.entity_id
+                ),
+                timeout="total",
             )
 
         # update next progress timeout
             )
 
         # update next progress timeout
@@ -195,10 +215,11 @@ class JujuModelObserver(ModelObserver):
             if await _wait_for_event_or_timeout(entity.event, next_timeout):
                 entity.event.clear()
             else:
             if await _wait_for_event_or_timeout(entity.event, next_timeout):
                 entity.event.clear()
             else:
-                message = 'Progress timeout {} seconds, {}}: {}'\
-                    .format(progress_timeout, entity.entity_type, entity.entity_id)
+                message = "Progress timeout {} seconds, {}}: {}".format(
+                    progress_timeout, entity.entity_type, entity.entity_id
+                )
                 self.n2vc.debug(message)
                 self.n2vc.debug(message)
-                raise N2VCTimeoutException(message=message, timeout='progress')
+                raise N2VCTimeoutException(message=message, timeout="progress")
         # self.n2vc.debug('End of wait. Final state: {}, retries: {}'
         #                 .format(entity.obj.__getattribute__(field_to_check), retries))
         return retries
         # self.n2vc.debug('End of wait. Final state: {}, retries: {}'
         #                 .format(entity.obj.__getattribute__(field_to_check), retries))
         return retries
@@ -212,7 +233,7 @@ class JujuModelObserver(ModelObserver):
         # self.n2vc.debug('on_change(): type: {}, entity: {}, id: {}'
         #                 .format(delta.type, delta.entity, new.entity_id))
 
         # self.n2vc.debug('on_change(): type: {}, entity: {}, id: {}'
         #                 .format(delta.type, delta.entity, new.entity_id))
 
-        if delta.entity == 'machine':
+        if delta.entity == "machine":
 
             # check registered machine
             if new.entity_id not in self.machines:
 
             # check registered machine
             if new.entity_id not in self.machines:
@@ -224,13 +245,13 @@ class JujuModelObserver(ModelObserver):
                 status=juju_status_2_osm_status(delta.entity, new.agent_status),
                 detailed_status=new.status_message,
                 vca_status=new.status,
                 status=juju_status_2_osm_status(delta.entity, new.agent_status),
                 detailed_status=new.status_message,
                 vca_status=new.status,
-                entity_type='machine'
+                entity_type="machine",
             )
 
             # set event for this machine
             self.machines[new.entity_id].event.set()
 
             )
 
             # set event for this machine
             self.machines[new.entity_id].event.set()
 
-        elif delta.entity == 'application':
+        elif delta.entity == "application":
 
             # check registered application
             if new.entity_id not in self.applications:
 
             # check registered application
             if new.entity_id not in self.applications:
@@ -242,16 +263,16 @@ class JujuModelObserver(ModelObserver):
                 status=juju_status_2_osm_status(delta.entity, new.status),
                 detailed_status=new.status_message,
                 vca_status=new.status,
                 status=juju_status_2_osm_status(delta.entity, new.status),
                 detailed_status=new.status_message,
                 vca_status=new.status,
-                entity_type='application'
+                entity_type="application",
             )
 
             # set event for this application
             self.applications[new.entity_id].event.set()
 
             )
 
             # set event for this application
             self.applications[new.entity_id].event.set()
 
-        elif delta.entity == 'unit':
+        elif delta.entity == "unit":
 
             # get the application for this unit
 
             # get the application for this unit
-            application_id = delta.data['application']
+            application_id = delta.data["application"]
 
             # check registered application
             if application_id not in self.applications:
 
             # check registered application
             if application_id not in self.applications:
@@ -264,13 +285,13 @@ class JujuModelObserver(ModelObserver):
                     status=juju_status_2_osm_status(delta.entity, new.workload_status),
                     detailed_status=new.workload_status_message,
                     vca_status=new.workload_status,
                     status=juju_status_2_osm_status(delta.entity, new.workload_status),
                     detailed_status=new.workload_status_message,
                     vca_status=new.workload_status,
-                    entity_type='unit'
+                    entity_type="unit",
                 )
 
             # set event for this application
             self.applications[application_id].event.set()
 
                 )
 
             # set event for this application
             self.applications[application_id].event.set()
 
-        elif delta.entity == 'action':
+        elif delta.entity == "action":
 
             # check registered action
             if new.entity_id not in self.actions:
 
             # check registered action
             if new.entity_id not in self.actions:
@@ -282,7 +303,7 @@ class JujuModelObserver(ModelObserver):
                 status=juju_status_2_osm_status(delta.entity, new.status),
                 detailed_status=new.status,
                 vca_status=new.status,
                 status=juju_status_2_osm_status(delta.entity, new.status),
                 detailed_status=new.status,
                 vca_status=new.status,
-                entity_type='action'
+                entity_type="action",
             )
 
             # set event for this application
             )
 
             # set event for this application
index b1f3230..a3ad29a 100644 (file)
 # contact with: nfvlabs@tid.es
 ##
 
 # contact with: nfvlabs@tid.es
 ##
 
-import asyncio
-from n2vc.loggable import Loggable
 import abc
 import abc
+import asyncio
 import time
 
 import time
 
+from n2vc.loggable import Loggable
 
 
-class K8sConnector(abc.ABC, Loggable):
 
 
+class K8sConnector(abc.ABC, Loggable):
     """
     """
-    ##################################################################################################
-    ########################################## P U B L I C ###########################################
-    ##################################################################################################
+    ####################################################################################
+    ################################### P U B L I C ####################################
+    ####################################################################################
     """
 
     """
 
-    def __init__(
-            self,
-            db: object,
-            log: object = None,
-            on_update_db=None
-    ):
+    def __init__(self, db: object, log: object = None, on_update_db=None):
         """
 
         :param db: database object to write current operation status
         """
 
         :param db: database object to write current operation status
@@ -48,7 +43,7 @@ class K8sConnector(abc.ABC, Loggable):
         """
 
         # parent class
         """
 
         # parent class
-        Loggable.__init__(self, log=log, log_to_console=True, prefix='\nK8S')
+        Loggable.__init__(self, log=log, log_to_console=True, prefix="\nK8S")
 
         # self.log.info('Initializing generic K8S connector')
 
 
         # self.log.info('Initializing generic K8S connector')
 
@@ -60,31 +55,26 @@ class K8sConnector(abc.ABC, Loggable):
 
     @abc.abstractmethod
     async def init_env(
 
     @abc.abstractmethod
     async def init_env(
-            self,
-            k8s_creds: str,
-            namespace: str = 'kube-system',
-            reuse_cluster_uuid=None
+        self, k8s_creds: str, namespace: str = "kube-system", reuse_cluster_uuid=None
     ) -> (str, bool):
         """
     ) -> (str, bool):
         """
-        It prepares a given K8s cluster environment to run Charts or juju Bundles on both sides:
+        It prepares a given K8s cluster environment to run Charts or juju Bundles on
+        both sides:
             client (OSM)
             server (Tiller/Charm)
 
             client (OSM)
             server (Tiller/Charm)
 
-        :param k8s_creds: credentials to access a given K8s cluster, i.e. a valid '.kube/config'
-        :param namespace: optional namespace to be used for the K8s engine (helm tiller, juju).
-        By default, 'kube-system' will be used
+        :param k8s_creds: credentials to access a given K8s cluster, i.e. a valid
+        '.kube/config'
+        :param namespace: optional namespace to be used for the K8s engine (helm
+        tiller, juju). By default, 'kube-system' will be used
         :param reuse_cluster_uuid: existing cluster uuid for reuse
         :param reuse_cluster_uuid: existing cluster uuid for reuse
-        :return: uuid of the K8s cluster and True if connector has installed some software in the cluster
-        (on error, an exception will be raised)
+        :return: uuid of the K8s cluster and True if connector has installed some
+        software in the cluster (on error, an exception will be raised)
         """
 
     @abc.abstractmethod
     async def repo_add(
         """
 
     @abc.abstractmethod
     async def repo_add(
-            self,
-            cluster_uuid: str,
-            name: str,
-            url: str,
-            repo_type: str = 'chart'
+        self, cluster_uuid: str, name: str, url: str, repo_type: str = "chart"
     ):
         """
         Add a new repository to OSM database
     ):
         """
         Add a new repository to OSM database
@@ -97,10 +87,7 @@ class K8sConnector(abc.ABC, Loggable):
         """
 
     @abc.abstractmethod
         """
 
     @abc.abstractmethod
-    async def repo_list(
-            self,
-            cluster_uuid: str
-    ):
+    async def repo_list(self, cluster_uuid: str):
         """
         Get the list of registered repositories
 
         """
         Get the list of registered repositories
 
@@ -109,11 +96,7 @@ class K8sConnector(abc.ABC, Loggable):
         """
 
     @abc.abstractmethod
         """
 
     @abc.abstractmethod
-    async def repo_remove(
-            self,
-            cluster_uuid: str,
-            name: str
-    ):
+    async def repo_remove(self, cluster_uuid: str, name: str):
         """
         Remove a repository from OSM
 
         """
         Remove a repository from OSM
 
@@ -123,66 +106,65 @@ class K8sConnector(abc.ABC, Loggable):
         """
 
     @abc.abstractmethod
         """
 
     @abc.abstractmethod
-    async def synchronize_repos(
-            self,
-            cluster_uuid: str,
-            name: str
-    ):
+    async def synchronize_repos(self, cluster_uuid: str, name: str):
         """
         Synchronizes the list of repositories created in the cluster with
         the repositories added by the NBI
 
         :param cluster_uuid: the cluster
         """
         Synchronizes the list of repositories created in the cluster with
         the repositories added by the NBI
 
         :param cluster_uuid: the cluster
-        :return: List of repositories deleted from the cluster and dictionary with repos added
+        :return: List of repositories deleted from the cluster and dictionary with
+        repos added
         """
 
     @abc.abstractmethod
     async def reset(
         """
 
     @abc.abstractmethod
     async def reset(
-            self,
-            cluster_uuid: str,
-            force: bool = False,
-            uninstall_sw: bool = False
+        self, cluster_uuid: str, force: bool = False, uninstall_sw: bool = False
     ) -> bool:
         """
     ) -> bool:
         """
-        Uninstalls Tiller/Charm from a known K8s cluster and removes it from the list of known K8s clusters.
-        Intended to be used e.g. when the NS instance is deleted.
+        Uninstalls Tiller/Charm from a known K8s cluster and removes it from the list
+        of known K8s clusters. Intended to be used e.g. when the NS instance is deleted.
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM.
         :param force: force deletion, even in case there are deployed releases
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM.
         :param force: force deletion, even in case there are deployed releases
-        :param uninstall_sw: flag to indicate that sw uninstallation from software is needed
+        :param uninstall_sw: flag to indicate that sw uninstallation from software is
+        needed
         :return: str: kdu_instance generated by helm
         """
 
     @abc.abstractmethod
     async def install(
         :return: str: kdu_instance generated by helm
         """
 
     @abc.abstractmethod
     async def install(
-            self,
-            cluster_uuid: str,
-            kdu_model: str,
-            atomic: bool = True,
-            timeout: float = 300,
-            params: dict = None,
-            db_dict: dict = None,
-            kdu_name: str = None,
-            namespace: str = None
+        self,
+        cluster_uuid: str,
+        kdu_model: str,
+        atomic: bool = True,
+        timeout: float = 300,
+        params: dict = None,
+        db_dict: dict = None,
+        kdu_name: str = None,
+        namespace: str = None,
     ):
         """
     ):
         """
-        Deploys of a new KDU instance. It would implicitly rely on the `install` call to deploy the Chart/Bundle
-        properly parametrized (in practice, this call would happen before any _initial-config-primitive_
-        of the VNF is called).
+        Deploys of a new KDU instance. It would implicitly rely on the `install` call
+        to deploy the Chart/Bundle properly parametrized (in practice, this call would
+        happen before any _initial-config-primitive_of the VNF is called).
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
-        :param kdu_model: chart/bundle:version reference (string), which can be either of these options:
+        :param kdu_model: chart/bundle:version reference (string), which can be either
+            of these options:
             - a name of chart/bundle available via the repos known by OSM
             - a path to a packaged chart/bundle
             - a path to an unpacked chart/bundle directory or a URL
             - a name of chart/bundle available via the repos known by OSM
             - a path to a packaged chart/bundle
             - a path to an unpacked chart/bundle directory or a URL
-        :param atomic: If set, installation process purges chart/bundle on fail, also will wait until
-            all the K8s objects are active
-        :param timeout: Time in seconds to wait for the install of the chart/bundle (defaults to
-            Helm default timeout: 300s)
-        :param params: dictionary of key-value pairs for instantiation parameters (overriding default values)
+        :param atomic: If set, installation process purges chart/bundle on fail, also
+            will wait until all the K8s objects are active
+        :param timeout: Time in seconds to wait for the install of the chart/bundle
+            (defaults to Helm default timeout: 300s)
+        :param params: dictionary of key-value pairs for instantiation parameters
+            (overriding default values)
         :param dict db_dict: where to write into database when the status changes.
         :param dict db_dict: where to write into database when the status changes.
-                        It contains a dict with {collection: <str>, filter: {},  path: <str>},
-                            e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
+                        It contains a dict with {collection: <str>, filter: {},
+                        path: <str>},
+                            e.g. {collection: "nsrs", filter:
+                            {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
         :param kdu_name: Name of the KDU instance to be installed
         :param namespace: K8s namespace to use for the KDU instance
         :return: True if successful
         :param kdu_name: Name of the KDU instance to be installed
         :param namespace: K8s namespace to use for the KDU instance
         :return: True if successful
@@ -190,63 +172,64 @@ class K8sConnector(abc.ABC, Loggable):
 
     @abc.abstractmethod
     async def upgrade(
 
     @abc.abstractmethod
     async def upgrade(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str,
-            kdu_model: str = None,
-            atomic: bool = True,
-            timeout: float = 300,
-            params: dict = None,
-            db_dict: dict = None
+        self,
+        cluster_uuid: str,
+        kdu_instance: str,
+        kdu_model: str = None,
+        atomic: bool = True,
+        timeout: float = 300,
+        params: dict = None,
+        db_dict: dict = None,
     ):
         """
     ):
         """
-        Upgrades an existing KDU instance. It would implicitly use the `upgrade` call over an existing Chart/Bundle.
-        It can be used both to upgrade the chart or to reconfigure it. This would be exposed as Day-2 primitive.
+        Upgrades an existing KDU instance. It would implicitly use the `upgrade` call
+        over an existing Chart/Bundle. It can be used both to upgrade the chart or to
+        reconfigure it. This would be exposed as Day-2 primitive.
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance to be updated
         :param kdu_model: new chart/bundle:version reference
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance to be updated
         :param kdu_model: new chart/bundle:version reference
-        :param atomic: rollback in case of fail and wait for pods and services are available
-        :param timeout: Time in seconds to wait for the install of the chart/bundle (defaults to
-            Helm default timeout: 300s)
+        :param atomic: rollback in case of fail and wait for pods and services are
+            available
+        :param timeout: Time in seconds to wait for the install of the chart/bundle
+            (defaults to Helm default timeout: 300s)
         :param params: new dictionary of key-value pairs for instantiation parameters
         :param dict db_dict: where to write into database when the status changes.
         :param params: new dictionary of key-value pairs for instantiation parameters
         :param dict db_dict: where to write into database when the status changes.
-                        It contains a dict with {collection: <str>, filter: {},  path: <str>},
-                            e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
+                        It contains a dict with {collection: <str>, filter: {},
+                        path: <str>},
+                            e.g. {collection: "nsrs", filter:
+                            {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
         :return: reference to the new revision number of the KDU instance
         """
 
     @abc.abstractmethod
     async def rollback(
         :return: reference to the new revision number of the KDU instance
         """
 
     @abc.abstractmethod
     async def rollback(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str,
-            revision=0,
-            db_dict: dict = None
+        self, cluster_uuid: str, kdu_instance: str, revision=0, db_dict: dict = None
     ):
         """
     ):
         """
-        Rolls back a previous update of a KDU instance. It would implicitly use the `rollback` call.
-        It can be used both to rollback from a Chart/Bundle version update or from a reconfiguration.
-        This would be exposed as Day-2 primitive.
+        Rolls back a previous update of a KDU instance. It would implicitly use the
+        `rollback` call. It can be used both to rollback from a Chart/Bundle version
+        update or from a reconfiguration. This would be exposed as Day-2 primitive.
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance
-        :param revision: revision to which revert changes. If omitted, it will revert the last update only
+        :param revision: revision to which revert changes. If omitted, it will revert
+            the last update only
         :param dict db_dict: where to write into database when the status changes.
         :param dict db_dict: where to write into database when the status changes.
-                        It contains a dict with {collection: <str>, filter: {},  path: <str>},
-                            e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
-        :return:If successful, reference to the current active revision of the KDU instance after the rollback
+                        It contains a dict with {collection: <str>, filter: {},
+                        path: <str>},
+                            e.g. {collection: "nsrs", filter:
+                            {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
+        :return:If successful, reference to the current active revision of the KDU
+            instance after the rollback
         """
 
     @abc.abstractmethod
         """
 
     @abc.abstractmethod
-    async def uninstall(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str
-    ):
+    async def uninstall(self, cluster_uuid: str, kdu_instance: str):
         """
         """
-        Removes an existing KDU instance. It would implicitly use the `delete` call (this call would happen
-        after all _terminate-config-primitive_ of the VNF are invoked).
+        Removes an existing KDU instance. It would implicitly use the `delete` call
+        (this call would happen after all _terminate-config-primitive_ of the VNF are
+        invoked).
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance to be deleted
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance to be deleted
@@ -276,48 +259,41 @@ class K8sConnector(abc.ABC, Loggable):
         """
 
     @abc.abstractmethod
         """
 
     @abc.abstractmethod
-    async def inspect_kdu(
-            self,
-            kdu_model: str,
-            repo_url: str = None
-    ) -> str:
+    async def inspect_kdu(self, kdu_model: str, repo_url: str = None) -> str:
         """
         These calls will retrieve from the Chart/Bundle:
 
         """
         These calls will retrieve from the Chart/Bundle:
 
-            - The list of configurable values and their defaults (e.g. in Charts, it would retrieve
-                the contents of `values.yaml`).
-            - If available, any embedded help file (e.g. `readme.md`) embedded in the Chart/Bundle.
+            - The list of configurable values and their defaults (e.g. in Charts,
+                it would retrieve the contents of `values.yaml`).
+            - If available, any embedded help file (e.g. `readme.md`) embedded in the
+                Chart/Bundle.
 
         :param kdu_model: chart/bundle reference
 
         :param kdu_model: chart/bundle reference
-        :param repo_url: optional, reposotory URL (None if tar.gz, URl in other cases, even stable URL)
+        :param repo_url: optional, reposotory URL (None if tar.gz, URl in other cases,
+            even stable URL)
         :return:
 
         :return:
 
-        If successful, it will return the available parameters and their default values as provided by the backend.
+        If successful, it will return the available parameters and their default values
+        as provided by the backend.
         """
 
     @abc.abstractmethod
         """
 
     @abc.abstractmethod
-    async def help_kdu(
-            self,
-            kdu_model: str,
-            repo_url: str = None
-    ) -> str:
+    async def help_kdu(self, kdu_model: str, repo_url: str = None) -> str:
         """
 
         :param kdu_model: chart/bundle reference
         """
 
         :param kdu_model: chart/bundle reference
-        :param repo_url: optional, reposotory URL (None if tar.gz, URl in other cases, even stable URL)
+        :param repo_url: optional, reposotory URL (None if tar.gz, URl in other cases,
+            even stable URL)
         :return: If successful, it will return the contents of the 'readme.md'
         """
 
     @abc.abstractmethod
         :return: If successful, it will return the contents of the 'readme.md'
         """
 
     @abc.abstractmethod
-    async def status_kdu(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str
-    ) -> str:
+    async def status_kdu(self, cluster_uuid: str, kdu_instance: str) -> str:
         """
         """
-        This call would retrieve tha current state of a given KDU instance. It would be would allow to retrieve
-        the _composition_ (i.e. K8s objects) and _specific values_ of the configuration parameters applied
-        to a given instance. This call would be based on the `status` call.
+        This call would retrieve tha current state of a given KDU instance. It would be
+        would allow to retrieve the _composition_ (i.e. K8s objects) and _specific
+        values_ of the configuration parameters applied to a given instance. This call
+        would be based on the `status` call.
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance
@@ -330,65 +306,64 @@ class K8sConnector(abc.ABC, Loggable):
               - SUPERSEDED
               - FAILED or
               - DELETING
               - SUPERSEDED
               - FAILED or
               - DELETING
-        - List of `resources` (objects) that this release consists of, sorted by kind, and the status of those resources
+        - List of `resources` (objects) that this release consists of, sorted by kind,
+          and the status of those resources
         - Last `deployment_time`.
 
         """
 
     """
         - Last `deployment_time`.
 
         """
 
     """
-    ##################################################################################################
-    ########################################## P R I V A T E #########################################
-    ##################################################################################################
+    ####################################################################################
+    ################################### P R I V A T E ##################################
+    ####################################################################################
     """
 
     async def write_app_status_to_db(
     """
 
     async def write_app_status_to_db(
-            self,
-            db_dict: dict,
-            status: str,
-            detailed_status: str,
-            operation: str
+        self, db_dict: dict, status: str, detailed_status: str, operation: str
     ) -> bool:
 
         if not self.db:
     ) -> bool:
 
         if not self.db:
-            self.warning('No db => No database write')
+            self.warning("No db => No database write")
             return False
 
         if not db_dict:
             return False
 
         if not db_dict:
-            self.warning('No db_dict => No database write')
+            self.warning("No db_dict => No database write")
             return False
 
             return False
 
-        self.log.debug('status={}'.format(status))
+        self.log.debug("status={}".format(status))
 
         try:
 
 
         try:
 
-            the_table = db_dict['collection']
-            the_filter = db_dict['filter']
-            the_path = db_dict['path']
-            if not the_path[-1] == '.':
-                the_path = the_path + '.'
+            the_table = db_dict["collection"]
+            the_filter = db_dict["filter"]
+            the_path = db_dict["path"]
+            if not the_path[-1] == ".":
+                the_path = the_path + "."
             update_dict = {
             update_dict = {
-                the_path + 'operation': operation,
-                the_path + 'status': status,
-                the_path + 'detailed-status': detailed_status,
-                the_path + 'status-time': str(time.time()),
+                the_path + "operation": operation,
+                the_path + "status": status,
+                the_path + "detailed-status": detailed_status,
+                the_path + "status-time": str(time.time()),
             }
 
             self.db.set_one(
                 table=the_table,
                 q_filter=the_filter,
                 update_dict=update_dict,
             }
 
             self.db.set_one(
                 table=the_table,
                 q_filter=the_filter,
                 update_dict=update_dict,
-                fail_on_empty=True
+                fail_on_empty=True,
             )
 
             # database callback
             if self.on_update_db:
                 if asyncio.iscoroutinefunction(self.on_update_db):
             )
 
             # database callback
             if self.on_update_db:
                 if asyncio.iscoroutinefunction(self.on_update_db):
-                    await self.on_update_db(the_table, the_filter, the_path, update_dict)
+                    await self.on_update_db(
+                        the_table, the_filter, the_path, update_dict
+                    )
                 else:
                     self.on_update_db(the_table, the_filter, the_path, update_dict)
 
             return True
 
         except Exception as e:
                 else:
                     self.on_update_db(the_table, the_filter, the_path, update_dict)
 
             return True
 
         except Exception as e:
-            self.log.info('Exception writing status to database: {}'.format(e))
+            self.log.info("Exception writing status to database: {}".format(e))
             return False
             return False
index d3fbed6..fdfc443 100644 (file)
 # contact with: nfvlabs@tid.es
 ##
 
 # contact with: nfvlabs@tid.es
 ##
 
-import subprocess
+import asyncio
 import os
 import os
+import random
 import shutil
 import shutil
-import asyncio
+import subprocess
 import time
 import time
-import yaml
 from uuid import uuid4
 from uuid import uuid4
-import random
-from n2vc.k8s_conn import K8sConnector
+
 from n2vc.exceptions import K8sException
 from n2vc.exceptions import K8sException
+from n2vc.k8s_conn import K8sConnector
+import yaml
 
 
 class K8sHelmConnector(K8sConnector):
 
     """
 
 
 class K8sHelmConnector(K8sConnector):
 
     """
-    ##################################################################################################
-    ########################################## P U B L I C ###########################################
-    ##################################################################################################
+    ####################################################################################
+    ################################### P U B L I C ####################################
+    ####################################################################################
     """
 
     def __init__(
     """
 
     def __init__(
-            self,
-            fs: object,
-            db: object,
-            kubectl_command: str = '/usr/bin/kubectl',
-            helm_command: str = '/usr/bin/helm',
-            log: object = None,
-            on_update_db=None
+        self,
+        fs: object,
+        db: object,
+        kubectl_command: str = "/usr/bin/kubectl",
+        helm_command: str = "/usr/bin/helm",
+        log: object = None,
+        on_update_db=None,
     ):
         """
 
     ):
         """
 
@@ -60,14 +61,9 @@ class K8sHelmConnector(K8sConnector):
         """
 
         # parent class
         """
 
         # parent class
-        K8sConnector.__init__(
-            self,
-            db=db,
-            log=log,
-            on_update_db=on_update_db
-        )
+        K8sConnector.__init__(self, db=db, log=log, on_update_db=on_update_db)
 
 
-        self.log.info('Initializing K8S Helm connector')
+        self.log.info("Initializing K8S Helm connector")
 
         # random numbers for release name generation
         random.seed(time.time())
 
         # random numbers for release name generation
         random.seed(time.time())
@@ -84,32 +80,37 @@ class K8sHelmConnector(K8sConnector):
         self._check_file_exists(filename=helm_command, exception_if_not_exists=True)
 
         # initialize helm client-only
         self._check_file_exists(filename=helm_command, exception_if_not_exists=True)
 
         # initialize helm client-only
-        self.log.debug('Initializing helm client-only...')
-        command = '{} init --client-only'.format(self._helm_command)
+        self.log.debug("Initializing helm client-only...")
+        command = "{} init --client-only".format(self._helm_command)
         try:
         try:
-            asyncio.ensure_future(self._local_async_exec(command=command, raise_exception_on_error=False))
+            asyncio.ensure_future(
+                self._local_async_exec(command=command, raise_exception_on_error=False)
+            )
             # loop = asyncio.get_event_loop()
             # loop = asyncio.get_event_loop()
-            # loop.run_until_complete(self._local_async_exec(command=command, raise_exception_on_error=False))
+            # loop.run_until_complete(self._local_async_exec(command=command,
+            # raise_exception_on_error=False))
         except Exception as e:
         except Exception as e:
-            self.warning(msg='helm init failed (it was already initialized): {}'.format(e))
+            self.warning(
+                msg="helm init failed (it was already initialized): {}".format(e)
+            )
 
 
-        self.log.info('K8S Helm connector initialized')
+        self.log.info("K8S Helm connector initialized")
 
     async def init_env(
 
     async def init_env(
-            self,
-            k8s_creds: str,
-            namespace: str = 'kube-system',
-            reuse_cluster_uuid=None
+        self, k8s_creds: str, namespace: str = "kube-system", reuse_cluster_uuid=None
     ) -> (str, bool):
         """
         It prepares a given K8s cluster environment to run Charts on both sides:
             client (OSM)
             server (Tiller)
 
     ) -> (str, bool):
         """
         It prepares a given K8s cluster environment to run Charts on both sides:
             client (OSM)
             server (Tiller)
 
-        :param k8s_creds: credentials to access a given K8s cluster, i.e. a valid '.kube/config'
-        :param namespace: optional namespace to be used for helm. By default, 'kube-system' will be used
+        :param k8s_creds: credentials to access a given K8s cluster, i.e. a valid
+            '.kube/config'
+        :param namespace: optional namespace to be used for helm. By default,
+            'kube-system' will be used
         :param reuse_cluster_uuid: existing cluster uuid for reuse
         :param reuse_cluster_uuid: existing cluster uuid for reuse
-        :return: uuid of the K8s cluster and True if connector has installed some software in the cluster
+        :return: uuid of the K8s cluster and True if connector has installed some
+            software in the cluster
         (on error, an exception will be raised)
         """
 
         (on error, an exception will be raised)
         """
 
@@ -117,19 +118,23 @@ class K8sHelmConnector(K8sConnector):
         if not cluster_uuid:
             cluster_uuid = str(uuid4())
 
         if not cluster_uuid:
             cluster_uuid = str(uuid4())
 
-        self.log.debug('Initializing K8S environment. namespace: {}'.format(namespace))
+        self.log.debug("Initializing K8S environment. namespace: {}".format(namespace))
 
         # create config filename
 
         # create config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
         f = open(config_filename, "w")
         f.write(k8s_creds)
         f.close()
 
         # check if tiller pod is up in cluster
         f = open(config_filename, "w")
         f.write(k8s_creds)
         f.close()
 
         # check if tiller pod is up in cluster
-        command = '{} --kubeconfig={} --namespace={} get deployments'\
-            .format(self.kubectl_command, config_filename, namespace)
-        output, rc = await self._local_async_exec(command=command, raise_exception_on_error=True)
+        command = "{} --kubeconfig={} --namespace={} get deployments".format(
+            self.kubectl_command, config_filename, namespace
+        )
+        output, _rc = await self._local_async_exec(
+            command=command, raise_exception_on_error=True
+        )
 
         output_table = K8sHelmConnector._output_to_table(output=output)
 
 
         output_table = K8sHelmConnector._output_to_table(output=output)
 
@@ -137,90 +142,98 @@ class K8sHelmConnector(K8sConnector):
         already_initialized = False
         try:
             for row in output_table:
         already_initialized = False
         try:
             for row in output_table:
-                if row[0].startswith('tiller-deploy'):
+                if row[0].startswith("tiller-deploy"):
                     already_initialized = True
                     break
                     already_initialized = True
                     break
-        except Exception as e:
+        except Exception:
             pass
 
         # helm init
         n2vc_installed_sw = False
         if not already_initialized:
             pass
 
         # helm init
         n2vc_installed_sw = False
         if not already_initialized:
-            self.log.info('Initializing helm in client and server: {}'.format(cluster_uuid))
-            command = '{} --kubeconfig={} --tiller-namespace={} --home={} init'\
-                .format(self._helm_command, config_filename, namespace, helm_dir)
-            output, rc = await self._local_async_exec(command=command, raise_exception_on_error=True)
+            self.log.info(
+                "Initializing helm in client and server: {}".format(cluster_uuid)
+            )
+            command = "{} --kubeconfig={} --tiller-namespace={} --home={} init".format(
+                self._helm_command, config_filename, namespace, helm_dir
+            )
+            output, _rc = await self._local_async_exec(
+                command=command, raise_exception_on_error=True
+            )
             n2vc_installed_sw = True
         else:
             # check client helm installation
             n2vc_installed_sw = True
         else:
             # check client helm installation
-            check_file = helm_dir + '/repository/repositories.yaml'
-            if not self._check_file_exists(filename=check_file, exception_if_not_exists=False):
-                self.log.info('Initializing helm in client: {}'.format(cluster_uuid))
-                command = '{} --kubeconfig={} --tiller-namespace={} --home={} init --client-only'\
-                    .format(self._helm_command, config_filename, namespace, helm_dir)
-                output, rc = await self._local_async_exec(command=command, raise_exception_on_error=True)
+            check_file = helm_dir + "/repository/repositories.yaml"
+            if not self._check_file_exists(
+                filename=check_file, exception_if_not_exists=False
+            ):
+                self.log.info("Initializing helm in client: {}".format(cluster_uuid))
+                command = (
+                    "{} --kubeconfig={} --tiller-namespace={} "
+                    "--home={} init --client-only"
+                ).format(self._helm_command, config_filename, namespace, helm_dir)
+                output, _rc = await self._local_async_exec(
+                    command=command, raise_exception_on_error=True
+                )
             else:
             else:
-                self.log.info('Helm client already initialized')
+                self.log.info("Helm client already initialized")
 
 
-        self.log.info('Cluster initialized {}'.format(cluster_uuid))
+        self.log.info("Cluster initialized {}".format(cluster_uuid))
 
         return cluster_uuid, n2vc_installed_sw
 
     async def repo_add(
 
         return cluster_uuid, n2vc_installed_sw
 
     async def repo_add(
-            self,
-            cluster_uuid: str,
-            name: str,
-            url: str,
-            repo_type: str = 'chart'
+        self, cluster_uuid: str, name: str, url: str, repo_type: str = "chart"
     ):
 
     ):
 
-        self.log.debug('adding {} repository {}. URL: {}'.format(repo_type, name, url))
+        self.log.debug("adding {} repository {}. URL: {}".format(repo_type, name, url))
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
         # helm repo update
 
         # helm repo update
-        command = '{} --kubeconfig={} --home={} repo update'.format(self._helm_command, config_filename, helm_dir)
-        self.log.debug('updating repo: {}'.format(command))
+        command = "{} --kubeconfig={} --home={} repo update".format(
+            self._helm_command, config_filename, helm_dir
+        )
+        self.log.debug("updating repo: {}".format(command))
         await self._local_async_exec(command=command, raise_exception_on_error=False)
 
         # helm repo add name url
         await self._local_async_exec(command=command, raise_exception_on_error=False)
 
         # helm repo add name url
-        command = '{} --kubeconfig={} --home={} repo add {} {}'\
-            .format(self._helm_command, config_filename, helm_dir, name, url)
-        self.log.debug('adding repo: {}'.format(command))
+        command = "{} --kubeconfig={} --home={} repo add {} {}".format(
+            self._helm_command, config_filename, helm_dir, name, url
+        )
+        self.log.debug("adding repo: {}".format(command))
         await self._local_async_exec(command=command, raise_exception_on_error=True)
 
         await self._local_async_exec(command=command, raise_exception_on_error=True)
 
-    async def repo_list(
-            self,
-            cluster_uuid: str
-    ) -> list:
+    async def repo_list(self, cluster_uuid: str) -> list:
         """
         Get the list of registered repositories
 
         :return: list of registered repositories: [ (name, url) .... ]
         """
 
         """
         Get the list of registered repositories
 
         :return: list of registered repositories: [ (name, url) .... ]
         """
 
-        self.log.debug('list repositories for cluster {}'.format(cluster_uuid))
+        self.log.debug("list repositories for cluster {}".format(cluster_uuid))
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
 
-        command = '{} --kubeconfig={} --home={} repo list --output yaml'\
-            .format(self._helm_command, config_filename, helm_dir)
+        command = "{} --kubeconfig={} --home={} repo list --output yaml".format(
+            self._helm_command, config_filename, helm_dir
+        )
 
 
-        output, rc = await self._local_async_exec(command=command, raise_exception_on_error=True)
+        output, _rc = await self._local_async_exec(
+            command=command, raise_exception_on_error=True
+        )
         if output and len(output) > 0:
             return yaml.load(output, Loader=yaml.SafeLoader)
         else:
             return []
 
         if output and len(output) > 0:
             return yaml.load(output, Loader=yaml.SafeLoader)
         else:
             return []
 
-    async def repo_remove(
-            self,
-            cluster_uuid: str,
-            name: str
-    ):
+    async def repo_remove(self, cluster_uuid: str, name: str):
         """
         Remove a repository from OSM
 
         """
         Remove a repository from OSM
 
@@ -229,29 +242,31 @@ class K8sHelmConnector(K8sConnector):
         :return: True if successful
         """
 
         :return: True if successful
         """
 
-        self.log.debug('list repositories for cluster {}'.format(cluster_uuid))
+        self.log.debug("list repositories for cluster {}".format(cluster_uuid))
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
 
-        command = '{} --kubeconfig={} --home={} repo remove {}'\
-            .format(self._helm_command, config_filename, helm_dir, name)
+        command = "{} --kubeconfig={} --home={} repo remove {}".format(
+            self._helm_command, config_filename, helm_dir, name
+        )
 
         await self._local_async_exec(command=command, raise_exception_on_error=True)
 
     async def reset(
 
         await self._local_async_exec(command=command, raise_exception_on_error=True)
 
     async def reset(
-            self,
-            cluster_uuid: str,
-            force: bool = False,
-            uninstall_sw: bool = False
+        self, cluster_uuid: str, force: bool = False, uninstall_sw: bool = False
     ) -> bool:
 
     ) -> bool:
 
-        self.log.debug('Resetting K8s environment. cluster uuid: {}'.format(cluster_uuid))
+        self.log.debug(
+            "Resetting K8s environment. cluster uuid: {}".format(cluster_uuid)
+        )
 
         # get kube and helm directories
 
         # get kube and helm directories
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=False)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=False
+        )
 
         # uninstall releases if needed
         releases = await self.instances_list(cluster_uuid=cluster_uuid)
 
         # uninstall releases if needed
         releases = await self.instances_list(cluster_uuid=cluster_uuid)
@@ -259,107 +274,134 @@ class K8sHelmConnector(K8sConnector):
             if force:
                 for r in releases:
                     try:
             if force:
                 for r in releases:
                     try:
-                        kdu_instance = r.get('Name')
-                        chart = r.get('Chart')
-                        self.log.debug('Uninstalling {} -> {}'.format(chart, kdu_instance))
-                        await self.uninstall(cluster_uuid=cluster_uuid, kdu_instance=kdu_instance)
+                        kdu_instance = r.get("Name")
+                        chart = r.get("Chart")
+                        self.log.debug(
+                            "Uninstalling {} -> {}".format(chart, kdu_instance)
+                        )
+                        await self.uninstall(
+                            cluster_uuid=cluster_uuid, kdu_instance=kdu_instance
+                        )
                     except Exception as e:
                     except Exception as e:
-                        self.log.error('Error uninstalling release {}: {}'.format(kdu_instance, e))
+                        self.log.error(
+                            "Error uninstalling release {}: {}".format(kdu_instance, e)
+                        )
             else:
             else:
-                msg = 'Cluster has releases and not force. Cannot reset K8s environment. Cluster uuid: {}'\
-                    .format(cluster_uuid)
+                msg = (
+                    "Cluster has releases and not force. Cannot reset K8s "
+                    "environment. Cluster uuid: {}"
+                ).format(cluster_uuid)
                 self.log.error(msg)
                 raise K8sException(msg)
 
         if uninstall_sw:
 
                 self.log.error(msg)
                 raise K8sException(msg)
 
         if uninstall_sw:
 
-            self.log.debug('Uninstalling tiller from cluster {}'.format(cluster_uuid))
+            self.log.debug("Uninstalling tiller from cluster {}".format(cluster_uuid))
 
             # find namespace for tiller pod
 
             # find namespace for tiller pod
-            command = '{} --kubeconfig={} get deployments --all-namespaces'\
-                .format(self.kubectl_command, config_filename)
-            output, rc = await self._local_async_exec(command=command, raise_exception_on_error=False)
+            command = "{} --kubeconfig={} get deployments --all-namespaces".format(
+                self.kubectl_command, config_filename
+            )
+            output, _rc = await self._local_async_exec(
+                command=command, raise_exception_on_error=False
+            )
             output_table = K8sHelmConnector._output_to_table(output=output)
             namespace = None
             for r in output_table:
                 try:
             output_table = K8sHelmConnector._output_to_table(output=output)
             namespace = None
             for r in output_table:
                 try:
-                    if 'tiller-deploy' in r[1]:
+                    if "tiller-deploy" in r[1]:
                         namespace = r[0]
                         break
                         namespace = r[0]
                         break
-                except Exception as e:
+                except Exception:
                     pass
             else:
                     pass
             else:
-                msg = 'Tiller deployment not found in cluster {}'.format(cluster_uuid)
+                msg = "Tiller deployment not found in cluster {}".format(cluster_uuid)
                 self.log.error(msg)
 
                 self.log.error(msg)
 
-            self.log.debug('namespace for tiller: {}'.format(namespace))
+            self.log.debug("namespace for tiller: {}".format(namespace))
 
 
-            force_str = '--force'
+            force_str = "--force"
 
             if namespace:
                 # delete tiller deployment
 
             if namespace:
                 # delete tiller deployment
-                self.log.debug('Deleting tiller deployment for cluster {}, namespace {}'.format(cluster_uuid, namespace))
-                command = '{} --namespace {} --kubeconfig={} {} delete deployment tiller-deploy'\
-                    .format(self.kubectl_command, namespace, config_filename, force_str)
-                await self._local_async_exec(command=command, raise_exception_on_error=False)
+                self.log.debug(
+                    "Deleting tiller deployment for cluster {}, namespace {}".format(
+                        cluster_uuid, namespace
+                    )
+                )
+                command = (
+                    "{} --namespace {} --kubeconfig={} {} delete deployment "
+                    "tiller-deploy"
+                ).format(self.kubectl_command, namespace, config_filename, force_str)
+                await self._local_async_exec(
+                    command=command, raise_exception_on_error=False
+                )
 
                 # uninstall tiller from cluster
 
                 # uninstall tiller from cluster
-                self.log.debug('Uninstalling tiller from cluster {}'.format(cluster_uuid))
-                command = '{} --kubeconfig={} --home={} reset'\
-                    .format(self._helm_command, config_filename, helm_dir)
-                self.log.debug('resetting: {}'.format(command))
-                output, rc = await self._local_async_exec(command=command, raise_exception_on_error=True)
+                self.log.debug(
+                    "Uninstalling tiller from cluster {}".format(cluster_uuid)
+                )
+                command = "{} --kubeconfig={} --home={} reset".format(
+                    self._helm_command, config_filename, helm_dir
+                )
+                self.log.debug("resetting: {}".format(command))
+                output, _rc = await self._local_async_exec(
+                    command=command, raise_exception_on_error=True
+                )
             else:
             else:
-                self.log.debug('namespace not found')
+                self.log.debug("namespace not found")
 
         # delete cluster directory
 
         # delete cluster directory
-        dir = self.fs.path + '/' + cluster_uuid
-        self.log.debug('Removing directory {}'.format(dir))
-        shutil.rmtree(dir, ignore_errors=True)
+        direct = self.fs.path + "/" + cluster_uuid
+        self.log.debug("Removing directory {}".format(direct))
+        shutil.rmtree(direct, ignore_errors=True)
 
         return True
 
     async def install(
 
         return True
 
     async def install(
-            self,
-            cluster_uuid: str,
-            kdu_model: str,
-            atomic: bool = True,
-            timeout: float = 300,
-            params: dict = None,
-            db_dict: dict = None,
-            kdu_name: str = None,
-            namespace: str = None
+        self,
+        cluster_uuid: str,
+        kdu_model: str,
+        atomic: bool = True,
+        timeout: float = 300,
+        params: dict = None,
+        db_dict: dict = None,
+        kdu_name: str = None,
+        namespace: str = None,
     ):
 
     ):
 
-        self.log.debug('installing {} in cluster {}'.format(kdu_model, cluster_uuid))
+        self.log.debug("installing {} in cluster {}".format(kdu_model, cluster_uuid))
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
         # params to str
         # params_str = K8sHelmConnector._params_to_set_option(params)
 
         # params to str
         # params_str = K8sHelmConnector._params_to_set_option(params)
-        params_str, file_to_delete = self._params_to_file_option(cluster_uuid=cluster_uuid, params=params)
+        params_str, file_to_delete = self._params_to_file_option(
+            cluster_uuid=cluster_uuid, params=params
+        )
 
 
-        timeout_str = ''
+        timeout_str = ""
         if timeout:
         if timeout:
-            timeout_str = '--timeout {}'.format(timeout)
+            timeout_str = "--timeout {}".format(timeout)
 
         # atomic
 
         # atomic
-        atomic_str = ''
+        atomic_str = ""
         if atomic:
         if atomic:
-            atomic_str = '--atomic'
+            atomic_str = "--atomic"
         # namespace
         # namespace
-        namespace_str = ''
+        namespace_str = ""
         if namespace:
             namespace_str = "--namespace {}".format(namespace)
 
         # version
         if namespace:
             namespace_str = "--namespace {}".format(namespace)
 
         # version
-        version_str = ''
-        if ':' in kdu_model:
-            parts = kdu_model.split(sep=':')
+        version_str = ""
+        if ":" in kdu_model:
+            parts = kdu_model.split(sep=":")
             if len(parts) == 2:
             if len(parts) == 2:
-                version_str = '--version {}'.format(parts[1])
+                version_str = "--version {}".format(parts[1])
                 kdu_model = parts[0]
 
         # generate a name for the release. Then, check if already exists
                 kdu_model = parts[0]
 
         # generate a name for the release. Then, check if already exists
@@ -370,7 +412,7 @@ class K8sHelmConnector(K8sConnector):
                 result = await self._status_kdu(
                     cluster_uuid=cluster_uuid,
                     kdu_instance=kdu_instance,
                 result = await self._status_kdu(
                     cluster_uuid=cluster_uuid,
                     kdu_instance=kdu_instance,
-                    show_error_log=False
+                    show_error_log=False,
                 )
                 if result is not None:
                     # instance already exists: generate a new one
                 )
                 if result is not None:
                     # instance already exists: generate a new one
@@ -379,17 +421,29 @@ class K8sHelmConnector(K8sConnector):
                 pass
 
         # helm repo install
                 pass
 
         # helm repo install
-        command = '{helm} install {atomic} --output yaml --kubeconfig={config} --home={dir} {params} {timeout} ' \
-                  '--name={name} {ns} {model} {ver}'.format(helm=self._helm_command, atomic=atomic_str,
-                                                            config=config_filename, dir=helm_dir, params=params_str,
-                                                            timeout=timeout_str, name=kdu_instance, ns=namespace_str,
-                                                            model=kdu_model, ver=version_str)
-        self.log.debug('installing: {}'.format(command))
+        command = (
+            "{helm} install {atomic} --output yaml --kubeconfig={config} --home={dir} "
+            "{params} {timeout} --name={name} {ns} {model} {ver}".format(
+                helm=self._helm_command,
+                atomic=atomic_str,
+                config=config_filename,
+                dir=helm_dir,
+                params=params_str,
+                timeout=timeout_str,
+                name=kdu_instance,
+                ns=namespace_str,
+                model=kdu_model,
+                ver=version_str,
+            )
+        )
+        self.log.debug("installing: {}".format(command))
 
         if atomic:
             # exec helm in a task
             exec_task = asyncio.ensure_future(
 
         if atomic:
             # exec helm in a task
             exec_task = asyncio.ensure_future(
-                coro_or_future=self._local_async_exec(command=command, raise_exception_on_error=False)
+                coro_or_future=self._local_async_exec(
+                    command=command, raise_exception_on_error=False
+                )
             )
 
             # write status in another task
             )
 
             # write status in another task
@@ -398,8 +452,8 @@ class K8sHelmConnector(K8sConnector):
                     cluster_uuid=cluster_uuid,
                     kdu_instance=kdu_instance,
                     db_dict=db_dict,
                     cluster_uuid=cluster_uuid,
                     kdu_instance=kdu_instance,
                     db_dict=db_dict,
-                    operation='install',
-                    run_once=False
+                    operation="install",
+                    run_once=False,
                 )
             )
 
                 )
             )
 
@@ -413,7 +467,9 @@ class K8sHelmConnector(K8sConnector):
 
         else:
 
 
         else:
 
-            output, rc = await self._local_async_exec(command=command, raise_exception_on_error=False)
+            output, rc = await self._local_async_exec(
+                command=command, raise_exception_on_error=False
+            )
 
         # remove temporal values yaml file
         if file_to_delete:
 
         # remove temporal values yaml file
         if file_to_delete:
@@ -424,23 +480,20 @@ class K8sHelmConnector(K8sConnector):
             cluster_uuid=cluster_uuid,
             kdu_instance=kdu_instance,
             db_dict=db_dict,
             cluster_uuid=cluster_uuid,
             kdu_instance=kdu_instance,
             db_dict=db_dict,
-            operation='install',
+            operation="install",
             run_once=True,
             run_once=True,
-            check_every=0
+            check_every=0,
         )
 
         if rc != 0:
         )
 
         if rc != 0:
-            msg = 'Error executing command: {}\nOutput: {}'.format(command, output)
+            msg = "Error executing command: {}\nOutput: {}".format(command, output)
             self.log.error(msg)
             raise K8sException(msg)
 
             self.log.error(msg)
             raise K8sException(msg)
 
-        self.log.debug('Returning kdu_instance {}'.format(kdu_instance))
+        self.log.debug("Returning kdu_instance {}".format(kdu_instance))
         return kdu_instance
 
         return kdu_instance
 
-    async def instances_list(
-            self,
-            cluster_uuid: str
-    ) -> list:
+    async def instances_list(self, cluster_uuid: str) -> list:
         """
         returns a list of deployed releases in a cluster
 
         """
         returns a list of deployed releases in a cluster
 
@@ -448,71 +501,90 @@ class K8sHelmConnector(K8sConnector):
         :return:
         """
 
         :return:
         """
 
-        self.log.debug('list releases for cluster {}'.format(cluster_uuid))
+        self.log.debug("list releases for cluster {}".format(cluster_uuid))
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
 
-        command = '{} --kubeconfig={} --home={} list --output yaml'\
-            .format(self._helm_command, config_filename, helm_dir)
+        command = "{} --kubeconfig={} --home={} list --output yaml".format(
+            self._helm_command, config_filename, helm_dir
+        )
 
 
-        output, rc = await self._local_async_exec(command=command, raise_exception_on_error=True)
+        output, _rc = await self._local_async_exec(
+            command=command, raise_exception_on_error=True
+        )
 
         if output and len(output) > 0:
 
         if output and len(output) > 0:
-            return yaml.load(output, Loader=yaml.SafeLoader).get('Releases')
+            return yaml.load(output, Loader=yaml.SafeLoader).get("Releases")
         else:
             return []
 
     async def upgrade(
         else:
             return []
 
     async def upgrade(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str,
-            kdu_model: str = None,
-            atomic: bool = True,
-            timeout: float = 300,
-            params: dict = None,
-            db_dict: dict = None
+        self,
+        cluster_uuid: str,
+        kdu_instance: str,
+        kdu_model: str = None,
+        atomic: bool = True,
+        timeout: float = 300,
+        params: dict = None,
+        db_dict: dict = None,
     ):
 
     ):
 
-        self.log.debug('upgrading {} in cluster {}'.format(kdu_model, cluster_uuid))
+        self.log.debug("upgrading {} in cluster {}".format(kdu_model, cluster_uuid))
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
         # params to str
         # params_str = K8sHelmConnector._params_to_set_option(params)
 
         # params to str
         # params_str = K8sHelmConnector._params_to_set_option(params)
-        params_str, file_to_delete = self._params_to_file_option(cluster_uuid=cluster_uuid, params=params)
+        params_str, file_to_delete = self._params_to_file_option(
+            cluster_uuid=cluster_uuid, params=params
+        )
 
 
-        timeout_str = ''
+        timeout_str = ""
         if timeout:
         if timeout:
-            timeout_str = '--timeout {}'.format(timeout)
+            timeout_str = "--timeout {}".format(timeout)
 
         # atomic
 
         # atomic
-        atomic_str = ''
+        atomic_str = ""
         if atomic:
         if atomic:
-            atomic_str = '--atomic'
+            atomic_str = "--atomic"
 
         # version
 
         # version
-        version_str = ''
-        if kdu_model and ':' in kdu_model:
-            parts = kdu_model.split(sep=':')
+        version_str = ""
+        if kdu_model and ":" in kdu_model:
+            parts = kdu_model.split(sep=":")
             if len(parts) == 2:
             if len(parts) == 2:
-                version_str = '--version {}'.format(parts[1])
+                version_str = "--version {}".format(parts[1])
                 kdu_model = parts[0]
 
         # helm repo upgrade
                 kdu_model = parts[0]
 
         # helm repo upgrade
-        command = '{} upgrade {} --output yaml --kubeconfig={} --home={} {} {} {} {} {}'\
-            .format(self._helm_command, atomic_str, config_filename, helm_dir,
-                    params_str, timeout_str, kdu_instance, kdu_model, version_str)
-        self.log.debug('upgrading: {}'.format(command))
+        command = (
+            "{} upgrade {} --output yaml --kubeconfig={} " "--home={} {} {} {} {} {}"
+        ).format(
+            self._helm_command,
+            atomic_str,
+            config_filename,
+            helm_dir,
+            params_str,
+            timeout_str,
+            kdu_instance,
+            kdu_model,
+            version_str,
+        )
+        self.log.debug("upgrading: {}".format(command))
 
         if atomic:
 
             # exec helm in a task
             exec_task = asyncio.ensure_future(
 
         if atomic:
 
             # exec helm in a task
             exec_task = asyncio.ensure_future(
-                coro_or_future=self._local_async_exec(command=command, raise_exception_on_error=False)
+                coro_or_future=self._local_async_exec(
+                    command=command, raise_exception_on_error=False
+                )
             )
             # write status in another task
             status_task = asyncio.ensure_future(
             )
             # write status in another task
             status_task = asyncio.ensure_future(
@@ -520,8 +592,8 @@ class K8sHelmConnector(K8sConnector):
                     cluster_uuid=cluster_uuid,
                     kdu_instance=kdu_instance,
                     db_dict=db_dict,
                     cluster_uuid=cluster_uuid,
                     kdu_instance=kdu_instance,
                     db_dict=db_dict,
-                    operation='upgrade',
-                    run_once=False
+                    operation="upgrade",
+                    run_once=False,
                 )
             )
 
                 )
             )
 
@@ -534,7 +606,9 @@ class K8sHelmConnector(K8sConnector):
 
         else:
 
 
         else:
 
-            output, rc = await self._local_async_exec(command=command, raise_exception_on_error=False)
+            output, rc = await self._local_async_exec(
+                command=command, raise_exception_on_error=False
+            )
 
         # remove temporal values yaml file
         if file_to_delete:
 
         # remove temporal values yaml file
         if file_to_delete:
@@ -545,46 +619,51 @@ class K8sHelmConnector(K8sConnector):
             cluster_uuid=cluster_uuid,
             kdu_instance=kdu_instance,
             db_dict=db_dict,
             cluster_uuid=cluster_uuid,
             kdu_instance=kdu_instance,
             db_dict=db_dict,
-            operation='upgrade',
+            operation="upgrade",
             run_once=True,
             run_once=True,
-            check_every=0
+            check_every=0,
         )
 
         if rc != 0:
         )
 
         if rc != 0:
-            msg = 'Error executing command: {}\nOutput: {}'.format(command, output)
+            msg = "Error executing command: {}\nOutput: {}".format(command, output)
             self.log.error(msg)
             raise K8sException(msg)
 
         # return new revision number
             self.log.error(msg)
             raise K8sException(msg)
 
         # return new revision number
-        instance = await self.get_instance_info(cluster_uuid=cluster_uuid, kdu_instance=kdu_instance)
+        instance = await self.get_instance_info(
+            cluster_uuid=cluster_uuid, kdu_instance=kdu_instance
+        )
         if instance:
         if instance:
-            revision = int(instance.get('Revision'))
-            self.log.debug('New revision: {}'.format(revision))
+            revision = int(instance.get("Revision"))
+            self.log.debug("New revision: {}".format(revision))
             return revision
         else:
             return 0
 
     async def rollback(
             return revision
         else:
             return 0
 
     async def rollback(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str,
-            revision=0,
-            db_dict: dict = None
+        self, cluster_uuid: str, kdu_instance: str, revision=0, db_dict: dict = None
     ):
 
     ):
 
-        self.log.debug('rollback kdu_instance {} to revision {} from cluster {}'
-                   .format(kdu_instance, revision, cluster_uuid))
+        self.log.debug(
+            "rollback kdu_instance {} to revision {} from cluster {}".format(
+                kdu_instance, revision, cluster_uuid
+            )
+        )
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
 
-        command = '{} rollback --kubeconfig={} --home={} {} {} --wait'\
-            .format(self._helm_command, config_filename, helm_dir, kdu_instance, revision)
+        command = "{} rollback --kubeconfig={} --home={} {} {} --wait".format(
+            self._helm_command, config_filename, helm_dir, kdu_instance, revision
+        )
 
         # exec helm in a task
         exec_task = asyncio.ensure_future(
 
         # exec helm in a task
         exec_task = asyncio.ensure_future(
-            coro_or_future=self._local_async_exec(command=command, raise_exception_on_error=False)
+            coro_or_future=self._local_async_exec(
+                command=command, raise_exception_on_error=False
+            )
         )
         # write status in another task
         status_task = asyncio.ensure_future(
         )
         # write status in another task
         status_task = asyncio.ensure_future(
@@ -592,8 +671,8 @@ class K8sHelmConnector(K8sConnector):
                 cluster_uuid=cluster_uuid,
                 kdu_instance=kdu_instance,
                 db_dict=db_dict,
                 cluster_uuid=cluster_uuid,
                 kdu_instance=kdu_instance,
                 db_dict=db_dict,
-                operation='rollback',
-                run_once=False
+                operation="rollback",
+                run_once=False,
             )
         )
 
             )
         )
 
@@ -610,49 +689,56 @@ class K8sHelmConnector(K8sConnector):
             cluster_uuid=cluster_uuid,
             kdu_instance=kdu_instance,
             db_dict=db_dict,
             cluster_uuid=cluster_uuid,
             kdu_instance=kdu_instance,
             db_dict=db_dict,
-            operation='rollback',
+            operation="rollback",
             run_once=True,
             run_once=True,
-            check_every=0
+            check_every=0,
         )
 
         if rc != 0:
         )
 
         if rc != 0:
-            msg = 'Error executing command: {}\nOutput: {}'.format(command, output)
+            msg = "Error executing command: {}\nOutput: {}".format(command, output)
             self.log.error(msg)
             raise K8sException(msg)
 
         # return new revision number
             self.log.error(msg)
             raise K8sException(msg)
 
         # return new revision number
-        instance = await self.get_instance_info(cluster_uuid=cluster_uuid, kdu_instance=kdu_instance)
+        instance = await self.get_instance_info(
+            cluster_uuid=cluster_uuid, kdu_instance=kdu_instance
+        )
         if instance:
         if instance:
-            revision = int(instance.get('Revision'))
-            self.log.debug('New revision: {}'.format(revision))
+            revision = int(instance.get("Revision"))
+            self.log.debug("New revision: {}".format(revision))
             return revision
         else:
             return 0
 
             return revision
         else:
             return 0
 
-    async def uninstall(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str
-    ):
+    async def uninstall(self, cluster_uuid: str, kdu_instance: str):
         """
         """
-        Removes an existing KDU instance. It would implicitly use the `delete` call (this call would happen
-        after all _terminate-config-primitive_ of the VNF are invoked).
+        Removes an existing KDU instance. It would implicitly use the `delete` call
+        (this call would happen after all _terminate-config-primitive_ of the VNF
+        are invoked).
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance to be deleted
         :return: True if successful
         """
 
 
         :param cluster_uuid: UUID of a K8s cluster known by OSM
         :param kdu_instance: unique name for the KDU instance to be deleted
         :return: True if successful
         """
 
-        self.log.debug('uninstall kdu_instance {} from cluster {}'.format(kdu_instance, cluster_uuid))
+        self.log.debug(
+            "uninstall kdu_instance {} from cluster {}".format(
+                kdu_instance, cluster_uuid
+            )
+        )
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
 
-        command = '{} --kubeconfig={} --home={} delete --purge {}'\
-            .format(self._helm_command, config_filename, helm_dir, kdu_instance)
+        command = "{} --kubeconfig={} --home={} delete --purge {}".format(
+            self._helm_command, config_filename, helm_dir, kdu_instance
+        )
 
 
-        output, rc = await self._local_async_exec(command=command, raise_exception_on_error=True)
+        output, _rc = await self._local_async_exec(
+            command=command, raise_exception_on_error=True
+        )
 
         return self._output_to_table(output)
 
 
         return self._output_to_table(output)
 
@@ -676,62 +762,70 @@ class K8sHelmConnector(K8sConnector):
 
         :return: Returns the output of the action
         """
 
         :return: Returns the output of the action
         """
-        raise K8sException("KDUs deployed with Helm don't support actions "
-                           "different from rollback, upgrade and status")
+        raise K8sException(
+            "KDUs deployed with Helm don't support actions "
+            "different from rollback, upgrade and status"
+        )
 
 
-    async def inspect_kdu(
-            self,
-            kdu_model: str,
-            repo_url: str = None
-    ) -> str:
+    async def inspect_kdu(self, kdu_model: str, repo_url: str = None) -> str:
 
 
-        self.log.debug('inspect kdu_model {} from (optional) repo: {}'.format(kdu_model, repo_url))
+        self.log.debug(
+            "inspect kdu_model {} from (optional) repo: {}".format(kdu_model, repo_url)
+        )
 
 
-        return await self._exec_inspect_comand(inspect_command='', kdu_model=kdu_model, repo_url=repo_url)
+        return await self._exec_inspect_comand(
+            inspect_command="", kdu_model=kdu_model, repo_url=repo_url
+        )
 
 
-    async def values_kdu(
-            self,
-            kdu_model: str,
-            repo_url: str = None
-    ) -> str:
+    async def values_kdu(self, kdu_model: str, repo_url: str = None) -> str:
 
 
-        self.log.debug('inspect kdu_model values {} from (optional) repo: {}'.format(kdu_model, repo_url))
+        self.log.debug(
+            "inspect kdu_model values {} from (optional) repo: {}".format(
+                kdu_model, repo_url
+            )
+        )
 
 
-        return await self._exec_inspect_comand(inspect_command='values', kdu_model=kdu_model, repo_url=repo_url)
+        return await self._exec_inspect_comand(
+            inspect_command="values", kdu_model=kdu_model, repo_url=repo_url
+        )
 
 
-    async def help_kdu(
-            self,
-            kdu_model: str,
-            repo_url: str = None
-    ) -> str:
+    async def help_kdu(self, kdu_model: str, repo_url: str = None) -> str:
 
 
-        self.log.debug('inspect kdu_model {} readme.md from repo: {}'.format(kdu_model, repo_url))
+        self.log.debug(
+            "inspect kdu_model {} readme.md from repo: {}".format(kdu_model, repo_url)
+        )
 
 
-        return await self._exec_inspect_comand(inspect_command='readme', kdu_model=kdu_model, repo_url=repo_url)
+        return await self._exec_inspect_comand(
+            inspect_command="readme", kdu_model=kdu_model, repo_url=repo_url
+        )
 
 
-    async def status_kdu(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str
-    ) -> str:
+    async def status_kdu(self, cluster_uuid: str, kdu_instance: str) -> str:
 
         # call internal function
         return await self._status_kdu(
             cluster_uuid=cluster_uuid,
             kdu_instance=kdu_instance,
             show_error_log=True,
 
         # call internal function
         return await self._status_kdu(
             cluster_uuid=cluster_uuid,
             kdu_instance=kdu_instance,
             show_error_log=True,
-            return_text=True
+            return_text=True,
         )
 
     async def synchronize_repos(self, cluster_uuid: str):
 
         self.log.debug("syncronize repos for cluster helm-id: {}",)
         try:
         )
 
     async def synchronize_repos(self, cluster_uuid: str):
 
         self.log.debug("syncronize repos for cluster helm-id: {}",)
         try:
-            update_repos_timeout = 300 # max timeout to sync a single repos, more than this is too much
-            db_k8scluster = self.db.get_one("k8sclusters", {"_admin.helm-chart.id": cluster_uuid})
+            update_repos_timeout = (
+                300  # max timeout to sync a single repos, more than this is too much
+            )
+            db_k8scluster = self.db.get_one(
+                "k8sclusters", {"_admin.helm-chart.id": cluster_uuid}
+            )
             if db_k8scluster:
             if db_k8scluster:
-                nbi_repo_list = db_k8scluster.get("_admin").get("helm_chart_repos") or []
-                cluster_repo_dict = db_k8scluster.get("_admin").get("helm_charts_added") or {}
+                nbi_repo_list = (
+                    db_k8scluster.get("_admin").get("helm_chart_repos") or []
+                )
+                cluster_repo_dict = (
+                    db_k8scluster.get("_admin").get("helm_charts_added") or {}
+                )
                 # elements that must be deleted
                 deleted_repo_list = []
                 added_repo_dict = {}
                 # elements that must be deleted
                 deleted_repo_list = []
                 added_repo_dict = {}
@@ -739,103 +833,144 @@ class K8sHelmConnector(K8sConnector):
                 self.log.debug("helm_charts_added: {}".format(cluster_repo_dict))
 
                 # obtain repos to add: registered by nbi but not added
                 self.log.debug("helm_charts_added: {}".format(cluster_repo_dict))
 
                 # obtain repos to add: registered by nbi but not added
-                repos_to_add = [repo for repo in nbi_repo_list if not cluster_repo_dict.get(repo)]
+                repos_to_add = [
+                    repo for repo in nbi_repo_list if not cluster_repo_dict.get(repo)
+                ]
 
                 # obtain repos to delete: added by cluster but not in nbi list
 
                 # obtain repos to delete: added by cluster but not in nbi list
-                repos_to_delete = [repo for repo in cluster_repo_dict.keys() if repo not in nbi_repo_list]
-
-                # delete repos: must delete first then add because there may be different repos with same name but
+                repos_to_delete = [
+                    repo
+                    for repo in cluster_repo_dict.keys()
+                    if repo not in nbi_repo_list
+                ]
+
+                # delete repos: must delete first then add because there may be
+                # different repos with same name but
                 # different id and url
                 self.log.debug("repos to delete: {}".format(repos_to_delete))
                 for repo_id in repos_to_delete:
                     # try to delete repos
                     try:
                 # different id and url
                 self.log.debug("repos to delete: {}".format(repos_to_delete))
                 for repo_id in repos_to_delete:
                     # try to delete repos
                     try:
-                        repo_delete_task = asyncio.ensure_future(self.repo_remove(cluster_uuid=cluster_uuid,
-                                                                                  name=cluster_repo_dict[repo_id]))
+                        repo_delete_task = asyncio.ensure_future(
+                            self.repo_remove(
+                                cluster_uuid=cluster_uuid,
+                                name=cluster_repo_dict[repo_id],
+                            )
+                        )
                         await asyncio.wait_for(repo_delete_task, update_repos_timeout)
                     except Exception as e:
                         await asyncio.wait_for(repo_delete_task, update_repos_timeout)
                     except Exception as e:
-                        self.warning("Error deleting repo, id: {}, name: {}, err_msg: {}".format(repo_id,
-                                cluster_repo_dict[repo_id], str(e)))
-                    # always add to the list of to_delete if there is an error because if is not there deleting raises error
+                        self.warning(
+                            "Error deleting repo, id: {}, name: {}, err_msg: {}".format(
+                                repo_id, cluster_repo_dict[repo_id], str(e)
+                            )
+                        )
+                    # always add to the list of to_delete if there is an error
+                    # because if is not there
+                    # deleting raises error
                     deleted_repo_list.append(repo_id)
 
                 # add repos
                 self.log.debug("repos to add: {}".format(repos_to_add))
                     deleted_repo_list.append(repo_id)
 
                 # add repos
                 self.log.debug("repos to add: {}".format(repos_to_add))
-                add_task_list = []
                 for repo_id in repos_to_add:
                     # obtain the repo data from the db
                 for repo_id in repos_to_add:
                     # obtain the repo data from the db
-                    # if there is an error getting the repo in the database we will ignore this repo and continue
-                    # because there is a possible race condition where the repo has been deleted while processing
+                    # if there is an error getting the repo in the database we will
+                    # ignore this repo and continue
+                    # because there is a possible race condition where the repo has
+                    # been deleted while processing
                     db_repo = self.db.get_one("k8srepos", {"_id": repo_id})
                     db_repo = self.db.get_one("k8srepos", {"_id": repo_id})
-                    self.log.debug("obtained repo: id, {}, name: {}, url: {}".format(repo_id, db_repo["name"], db_repo["url"]))
+                    self.log.debug(
+                        "obtained repo: id, {}, name: {}, url: {}".format(
+                            repo_id, db_repo["name"], db_repo["url"]
+                        )
+                    )
                     try:
                     try:
-                        repo_add_task = asyncio.ensure_future(self.repo_add(cluster_uuid=cluster_uuid,
-                                                         name=db_repo["name"], url=db_repo["url"],
-                                                         repo_type="chart"))
+                        repo_add_task = asyncio.ensure_future(
+                            self.repo_add(
+                                cluster_uuid=cluster_uuid,
+                                name=db_repo["name"],
+                                url=db_repo["url"],
+                                repo_type="chart",
+                            )
+                        )
                         await asyncio.wait_for(repo_add_task, update_repos_timeout)
                         added_repo_dict[repo_id] = db_repo["name"]
                         await asyncio.wait_for(repo_add_task, update_repos_timeout)
                         added_repo_dict[repo_id] = db_repo["name"]
-                        self.log.debug("added repo: id, {}, name: {}".format(repo_id, db_repo["name"]))
+                        self.log.debug(
+                            "added repo: id, {}, name: {}".format(
+                                repo_id, db_repo["name"]
+                            )
+                        )
                     except Exception as e:
                     except Exception as e:
-                        # deal with error adding repo, adding a repo that already exists does not raise any error
-                        # will not raise error because a wrong repos added by anyone could prevent instantiating any ns
-                        self.log.error("Error adding repo id: {}, err_msg: {} ".format(repo_id, repr(e)))
+                        # deal with error adding repo, adding a repo that already
+                        # exists does not raise any error
+                        # will not raise error because a wrong repos added by
+                        # anyone could prevent instantiating any ns
+                        self.log.error(
+                            "Error adding repo id: {}, err_msg: {} ".format(
+                                repo_id, repr(e)
+                            )
+                        )
 
                 return deleted_repo_list, added_repo_dict
 
 
                 return deleted_repo_list, added_repo_dict
 
-            else: # else db_k8scluster does not exist
-                raise K8sException("k8cluster with helm-id : {} not found".format(cluster_uuid))
+            else:  # else db_k8scluster does not exist
+                raise K8sException(
+                    "k8cluster with helm-id : {} not found".format(cluster_uuid)
+                )
 
         except Exception as e:
             self.log.error("Error synchronizing repos: {}".format(str(e)))
             raise K8sException("Error synchronizing repos")
 
     """
 
         except Exception as e:
             self.log.error("Error synchronizing repos: {}".format(str(e)))
             raise K8sException("Error synchronizing repos")
 
     """
-    ##################################################################################################
-    ########################################## P R I V A T E #########################################
-    ##################################################################################################
+    ####################################################################################
+    ################################### P R I V A T E ##################################
+    ####################################################################################
     """
 
     async def _exec_inspect_comand(
     """
 
     async def _exec_inspect_comand(
-            self,
-            inspect_command: str,
-            kdu_model: str,
-            repo_url: str = None
+        self, inspect_command: str, kdu_model: str, repo_url: str = None
     ):
 
     ):
 
-        repo_str = ''
+        repo_str = ""
         if repo_url:
         if repo_url:
-            repo_str = ' --repo {}'.format(repo_url)
-            idx = kdu_model.find('/')
+            repo_str = " --repo {}".format(repo_url)
+            idx = kdu_model.find("/")
             if idx >= 0:
                 idx += 1
                 kdu_model = kdu_model[idx:]
 
             if idx >= 0:
                 idx += 1
                 kdu_model = kdu_model[idx:]
 
-        inspect_command = '{} inspect {} {}{}'.format(self._helm_command, inspect_command, kdu_model, repo_str)
-        output, rc = await self._local_async_exec(command=inspect_command, encode_utf8=True)
+        inspect_command = "{} inspect {} {}{}".format(
+            self._helm_command, inspect_command, kdu_model, repo_str
+        )
+        output, _rc = await self._local_async_exec(
+            command=inspect_command, encode_utf8=True
+        )
 
         return output
 
     async def _status_kdu(
 
         return output
 
     async def _status_kdu(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str,
-            show_error_log: bool = False,
-            return_text: bool = False
+        self,
+        cluster_uuid: str,
+        kdu_instance: str,
+        show_error_log: bool = False,
+        return_text: bool = False,
     ):
 
     ):
 
-        self.log.debug('status of kdu_instance {}'.format(kdu_instance))
+        self.log.debug("status of kdu_instance {}".format(kdu_instance))
 
         # config filename
 
         # config filename
-        kube_dir, helm_dir, config_filename, cluster_dir = \
-            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+        _kube_dir, helm_dir, config_filename, _cluster_dir = self._get_paths(
+            cluster_name=cluster_uuid, create_if_not_exist=True
+        )
 
 
-        command = '{} --kubeconfig={} --home={} status {} --output yaml'\
-            .format(self._helm_command, config_filename, helm_dir, kdu_instance)
+        command = "{} --kubeconfig={} --home={} status {} --output yaml".format(
+            self._helm_command, config_filename, helm_dir, kdu_instance
+        )
 
         output, rc = await self._local_async_exec(
             command=command,
             raise_exception_on_error=True,
 
         output, rc = await self._local_async_exec(
             command=command,
             raise_exception_on_error=True,
-            show_error_log=show_error_log
+            show_error_log=show_error_log,
         )
 
         if return_text:
         )
 
         if return_text:
@@ -848,111 +983,106 @@ class K8sHelmConnector(K8sConnector):
 
         # remove field 'notes'
         try:
 
         # remove field 'notes'
         try:
-            del data.get('info').get('status')['notes']
+            del data.get("info").get("status")["notes"]
         except KeyError:
             pass
 
         # parse field 'resources'
         try:
         except KeyError:
             pass
 
         # parse field 'resources'
         try:
-            resources = str(data.get('info').get('status').get('resources'))
+            resources = str(data.get("info").get("status").get("resources"))
             resource_table = self._output_to_table(resources)
             resource_table = self._output_to_table(resources)
-            data.get('info').get('status')['resources'] = resource_table
-        except Exception as e:
+            data.get("info").get("status")["resources"] = resource_table
+        except Exception:
             pass
 
         return data
 
             pass
 
         return data
 
-    async def get_instance_info(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str
-    ):
+    async def get_instance_info(self, cluster_uuid: str, kdu_instance: str):
         instances = await self.instances_list(cluster_uuid=cluster_uuid)
         for instance in instances:
         instances = await self.instances_list(cluster_uuid=cluster_uuid)
         for instance in instances:
-            if instance.get('Name') == kdu_instance:
+            if instance.get("Name") == kdu_instance:
                 return instance
                 return instance
-        self.log.debug('Instance {} not found'.format(kdu_instance))
+        self.log.debug("Instance {} not found".format(kdu_instance))
         return None
 
     @staticmethod
         return None
 
     @staticmethod
-    def _generate_release_name(
-            chart_name: str
-    ):
+    def _generate_release_name(chart_name: str):
         # check embeded chart (file or dir)
         # check embeded chart (file or dir)
-        if chart_name.startswith('/'):
+        if chart_name.startswith("/"):
             # extract file or directory name
             # extract file or directory name
-            chart_name = chart_name[chart_name.rfind('/')+1:]
+            chart_name = chart_name[chart_name.rfind("/") + 1 :]
         # check URL
         # check URL
-        elif '://' in chart_name:
+        elif "://" in chart_name:
             # extract last portion of URL
             # extract last portion of URL
-            chart_name = chart_name[chart_name.rfind('/')+1:]
+            chart_name = chart_name[chart_name.rfind("/") + 1 :]
 
 
-        name = ''
+        name = ""
         for c in chart_name:
             if c.isalpha() or c.isnumeric():
                 name += c
             else:
         for c in chart_name:
             if c.isalpha() or c.isnumeric():
                 name += c
             else:
-                name += '-'
+                name += "-"
         if len(name) > 35:
             name = name[0:35]
 
         # if does not start with alpha character, prefix 'a'
         if not name[0].isalpha():
         if len(name) > 35:
             name = name[0:35]
 
         # if does not start with alpha character, prefix 'a'
         if not name[0].isalpha():
-            name = 'a' + name
+            name = "a" + name
 
 
-        name += '-'
+        name += "-"
 
         def get_random_number():
             r = random.randrange(start=1, stop=99999999)
             s = str(r)
 
         def get_random_number():
             r = random.randrange(start=1, stop=99999999)
             s = str(r)
-            s = s.rjust(10, '0')
+            s = s.rjust(10, "0")
             return s
 
         name = name + get_random_number()
         return name.lower()
 
     async def _store_status(
             return s
 
         name = name + get_random_number()
         return name.lower()
 
     async def _store_status(
-            self,
-            cluster_uuid: str,
-            operation: str,
-            kdu_instance: str,
-            check_every: float = 10,
-            db_dict: dict = None,
-            run_once: bool = False
+        self,
+        cluster_uuid: str,
+        operation: str,
+        kdu_instance: str,
+        check_every: float = 10,
+        db_dict: dict = None,
+        run_once: bool = False,
     ):
         while True:
             try:
                 await asyncio.sleep(check_every)
     ):
         while True:
             try:
                 await asyncio.sleep(check_every)
-                detailed_status = await self.status_kdu(cluster_uuid=cluster_uuid, kdu_instance=kdu_instance)
-                status = detailed_status.get('info').get('Description')
-                self.log.debug('STATUS:\n{}'.format(status))
-                self.log.debug('DETAILED STATUS:\n{}'.format(detailed_status))
+                detailed_status = await self.status_kdu(
+                    cluster_uuid=cluster_uuid, kdu_instance=kdu_instance
+                )
+                status = detailed_status.get("info").get("Description")
+                self.log.debug("STATUS:\n{}".format(status))
+                self.log.debug("DETAILED STATUS:\n{}".format(detailed_status))
                 # write status to db
                 result = await self.write_app_status_to_db(
                     db_dict=db_dict,
                     status=str(status),
                     detailed_status=str(detailed_status),
                 # write status to db
                 result = await self.write_app_status_to_db(
                     db_dict=db_dict,
                     status=str(status),
                     detailed_status=str(detailed_status),
-                    operation=operation)
+                    operation=operation,
+                )
                 if not result:
                 if not result:
-                    self.log.info('Error writing in database. Task exiting...')
+                    self.log.info("Error writing in database. Task exiting...")
                     return
             except asyncio.CancelledError:
                     return
             except asyncio.CancelledError:
-                self.log.debug('Task cancelled')
+                self.log.debug("Task cancelled")
                 return
             except Exception as e:
                 return
             except Exception as e:
-                self.log.debug('_store_status exception: {}'.format(str(e)))
+                self.log.debug("_store_status exception: {}".format(str(e)))
                 pass
             finally:
                 if run_once:
                     return
 
                 pass
             finally:
                 if run_once:
                     return
 
-    async def _is_install_completed(
-            self,
-            cluster_uuid: str,
-            kdu_instance: str
-    ) -> bool:
+    async def _is_install_completed(self, cluster_uuid: str, kdu_instance: str) -> bool:
 
 
-        status = await self._status_kdu(cluster_uuid=cluster_uuid, kdu_instance=kdu_instance, return_text=False)
+        status = await self._status_kdu(
+            cluster_uuid=cluster_uuid, kdu_instance=kdu_instance, return_text=False
+        )
 
         # extract info.status.resources-> str
         # format:
 
         # extract info.status.resources-> str
         # format:
@@ -961,7 +1091,7 @@ class K8sHelmConnector(K8sConnector):
         #       halting-horse-mongodb   0/1     1            0           0s
         #       halting-petit-mongodb   1/1     1            0           0s
         # blank line
         #       halting-horse-mongodb   0/1     1            0           0s
         #       halting-petit-mongodb   1/1     1            0           0s
         # blank line
-        resources = K8sHelmConnector._get_deep(status, ('info', 'status', 'resources'))
+        resources = K8sHelmConnector._get_deep(status, ("info", "status", "resources"))
 
         # convert to table
         resources = K8sHelmConnector._output_to_table(resources)
 
         # convert to table
         resources = K8sHelmConnector._output_to_table(resources)
@@ -973,26 +1103,26 @@ class K8sHelmConnector(K8sConnector):
                 line1 = resources[index]
                 index += 1
                 # find '==>' in column 0
                 line1 = resources[index]
                 index += 1
                 # find '==>' in column 0
-                if line1[0] == '==>':
+                if line1[0] == "==>":
                     line2 = resources[index]
                     index += 1
                     # find READY in column 1
                     line2 = resources[index]
                     index += 1
                     # find READY in column 1
-                    if line2[1] == 'READY':
+                    if line2[1] == "READY":
                         # read next lines
                         line3 = resources[index]
                         index += 1
                         while len(line3) > 1 and index < num_lines:
                             ready_value = line3[1]
                         # read next lines
                         line3 = resources[index]
                         index += 1
                         while len(line3) > 1 and index < num_lines:
                             ready_value = line3[1]
-                            parts = ready_value.split(sep='/')
+                            parts = ready_value.split(sep="/")
                             current = int(parts[0])
                             total = int(parts[1])
                             if current < total:
                             current = int(parts[0])
                             total = int(parts[1])
                             if current < total:
-                                self.log.debug('NOT READY:\n    {}'.format(line3))
+                                self.log.debug("NOT READY:\n    {}".format(line3))
                                 ready = False
                             line3 = resources[index]
                             index += 1
 
                                 ready = False
                             line3 = resources[index]
                             index += 1
 
-            except Exception as e:
+            except Exception:
                 pass
 
         return ready
                 pass
 
         return ready
@@ -1008,7 +1138,7 @@ class K8sHelmConnector(K8sConnector):
                     return None
                 else:
                     target = value
                     return None
                 else:
                     target = value
-        except Exception as e:
+        except Exception:
             pass
         return value
 
             pass
         return value
 
@@ -1017,11 +1147,11 @@ class K8sHelmConnector(K8sConnector):
     def _find_in_lines(p_lines: list, p_key: str) -> str:
         for line in p_lines:
             try:
     def _find_in_lines(p_lines: list, p_key: str) -> str:
         for line in p_lines:
             try:
-                if line.startswith(p_key + ':'):
-                    parts = line.split(':')
+                if line.startswith(p_key + ":"):
+                    parts = line.split(":")
                     the_value = parts[1].strip()
                     return the_value
                     the_value = parts[1].strip()
                     return the_value
-            except Exception as e:
+            except Exception:
                 # ignore it
                 pass
         return None
                 # ignore it
                 pass
         return None
@@ -1031,46 +1161,45 @@ class K8sHelmConnector(K8sConnector):
     def _params_to_file_option(self, cluster_uuid: str, params: dict) -> (str, str):
 
         if params and len(params) > 0:
     def _params_to_file_option(self, cluster_uuid: str, params: dict) -> (str, str):
 
         if params and len(params) > 0:
-            kube_dir, helm_dir, config_filename, cluster_dir = \
-                self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
+            self._get_paths(cluster_name=cluster_uuid, create_if_not_exist=True)
 
             def get_random_number():
                 r = random.randrange(start=1, stop=99999999)
                 s = str(r)
                 while len(s) < 10:
 
             def get_random_number():
                 r = random.randrange(start=1, stop=99999999)
                 s = str(r)
                 while len(s) < 10:
-                    s = '0' + s
+                    s = "0" + s
                 return s
 
             params2 = dict()
             for key in params:
                 value = params.get(key)
                 return s
 
             params2 = dict()
             for key in params:
                 value = params.get(key)
-                if '!!yaml' in str(value):
+                if "!!yaml" in str(value):
                     value = yaml.load(value[7:])
                 params2[key] = value
 
                     value = yaml.load(value[7:])
                 params2[key] = value
 
-            values_file = get_random_number() + '.yaml'
-            with open(values_file, 'w') as stream:
+            values_file = get_random_number() + ".yaml"
+            with open(values_file, "w") as stream:
                 yaml.dump(params2, stream, indent=4, default_flow_style=False)
 
                 yaml.dump(params2, stream, indent=4, default_flow_style=False)
 
-            return '-f {}'.format(values_file), values_file
+            return "-f {}".format(values_file), values_file
 
 
-        return '', None
+        return "", None
 
     # params for use in --set option
     @staticmethod
     def _params_to_set_option(params: dict) -> str:
 
     # params for use in --set option
     @staticmethod
     def _params_to_set_option(params: dict) -> str:
-        params_str = ''
+        params_str = ""
         if params and len(params) > 0:
             start = True
             for key in params:
                 value = params.get(key, None)
                 if value is not None:
                     if start:
         if params and len(params) > 0:
             start = True
             for key in params:
                 value = params.get(key, None)
                 if value is not None:
                     if start:
-                        params_str += '--set '
+                        params_str += "--set "
                         start = False
                     else:
                         start = False
                     else:
-                        params_str += ','
-                    params_str += '{}={}'.format(key, value)
+                        params_str += ","
+                    params_str += "{}={}".format(key, value)
         return params_str
 
     @staticmethod
         return params_str
 
     @staticmethod
@@ -1088,17 +1217,19 @@ class K8sHelmConnector(K8sConnector):
         output_table = list()
         lines = output.splitlines(keepends=False)
         for line in lines:
         output_table = list()
         lines = output.splitlines(keepends=False)
         for line in lines:
-            line = line.replace('\t', ' ')
+            line = line.replace("\t", " ")
             line_list = list()
             output_table.append(line_list)
             line_list = list()
             output_table.append(line_list)
-            cells = line.split(sep=' ')
+            cells = line.split(sep=" ")
             for cell in cells:
                 cell = cell.strip()
                 if len(cell) > 0:
                     line_list.append(cell)
         return output_table
 
             for cell in cells:
                 cell = cell.strip()
                 if len(cell) > 0:
                     line_list.append(cell)
         return output_table
 
-    def _get_paths(self, cluster_name: str, create_if_not_exist: bool = False) -> (str, str, str, str):
+    def _get_paths(
+        self, cluster_name: str, create_if_not_exist: bool = False
+    ) -> (str, str, str, str):
         """
         Returns kube and helm directories
 
         """
         Returns kube and helm directories
 
@@ -1113,81 +1244,78 @@ class K8sHelmConnector(K8sConnector):
             base = base[:-1]
 
         # base dir for cluster
             base = base[:-1]
 
         # base dir for cluster
-        cluster_dir = base + '/' + cluster_name
+        cluster_dir = base + "/" + cluster_name
         if create_if_not_exist and not os.path.exists(cluster_dir):
         if create_if_not_exist and not os.path.exists(cluster_dir):
-            self.log.debug('Creating dir {}'.format(cluster_dir))
+            self.log.debug("Creating dir {}".format(cluster_dir))
             os.makedirs(cluster_dir)
         if not os.path.exists(cluster_dir):
             os.makedirs(cluster_dir)
         if not os.path.exists(cluster_dir):
-            msg = 'Base cluster dir {} does not exist'.format(cluster_dir)
+            msg = "Base cluster dir {} does not exist".format(cluster_dir)
             self.log.error(msg)
             raise K8sException(msg)
 
         # kube dir
             self.log.error(msg)
             raise K8sException(msg)
 
         # kube dir
-        kube_dir = cluster_dir + '/' + '.kube'
+        kube_dir = cluster_dir + "/" + ".kube"
         if create_if_not_exist and not os.path.exists(kube_dir):
         if create_if_not_exist and not os.path.exists(kube_dir):
-            self.log.debug('Creating dir {}'.format(kube_dir))
+            self.log.debug("Creating dir {}".format(kube_dir))
             os.makedirs(kube_dir)
         if not os.path.exists(kube_dir):
             os.makedirs(kube_dir)
         if not os.path.exists(kube_dir):
-            msg = 'Kube config dir {} does not exist'.format(kube_dir)
+            msg = "Kube config dir {} does not exist".format(kube_dir)
             self.log.error(msg)
             raise K8sException(msg)
 
         # helm home dir
             self.log.error(msg)
             raise K8sException(msg)
 
         # helm home dir
-        helm_dir = cluster_dir + '/' + '.helm'
+        helm_dir = cluster_dir + "/" + ".helm"
         if create_if_not_exist and not os.path.exists(helm_dir):
         if create_if_not_exist and not os.path.exists(helm_dir):
-            self.log.debug('Creating dir {}'.format(helm_dir))
+            self.log.debug("Creating dir {}".format(helm_dir))
             os.makedirs(helm_dir)
         if not os.path.exists(helm_dir):
             os.makedirs(helm_dir)
         if not os.path.exists(helm_dir):
-            msg = 'Helm config dir {} does not exist'.format(helm_dir)
+            msg = "Helm config dir {} does not exist".format(helm_dir)
             self.log.error(msg)
             raise K8sException(msg)
 
             self.log.error(msg)
             raise K8sException(msg)
 
-        config_filename = kube_dir + '/config'
+        config_filename = kube_dir + "/config"
         return kube_dir, helm_dir, config_filename, cluster_dir
 
     @staticmethod
         return kube_dir, helm_dir, config_filename, cluster_dir
 
     @staticmethod
-    def _remove_multiple_spaces(str):
-        str = str.strip()
-        while '  ' in str:
-            str = str.replace('  ', ' ')
-        return str
-
-    def _local_exec(
-            self,
-            command: str
-    ) -> (str, int):
+    def _remove_multiple_spaces(strobj):
+        strobj = strobj.strip()
+        while "  " in strobj:
+            strobj = strobj.replace("  ", " ")
+        return strobj
+
+    def _local_exec(self, command: str) -> (str, int):
         command = K8sHelmConnector._remove_multiple_spaces(command)
         command = K8sHelmConnector._remove_multiple_spaces(command)
-        self.log.debug('Executing sync local command: {}'.format(command))
+        self.log.debug("Executing sync local command: {}".format(command))
         # raise exception if fails
         # raise exception if fails
-        output = ''
+        output = ""
         try:
         try:
-            output = subprocess.check_output(command, shell=True, universal_newlines=True)
+            output = subprocess.check_output(
+                command, shell=True, universal_newlines=True
+            )
             return_code = 0
             self.log.debug(output)
             return_code = 0
             self.log.debug(output)
-        except Exception as e:
+        except Exception:
             return_code = 1
 
         return output, return_code
 
     async def _local_async_exec(
             return_code = 1
 
         return output, return_code
 
     async def _local_async_exec(
-            self,
-            command: str,
-            raise_exception_on_error: bool = False,
-            show_error_log: bool = True,
-            encode_utf8: bool = False
+        self,
+        command: str,
+        raise_exception_on_error: bool = False,
+        show_error_log: bool = True,
+        encode_utf8: bool = False,
     ) -> (str, int):
 
         command = K8sHelmConnector._remove_multiple_spaces(command)
     ) -> (str, int):
 
         command = K8sHelmConnector._remove_multiple_spaces(command)
-        self.log.debug('Executing async local command: {}'.format(command))
+        self.log.debug("Executing async local command: {}".format(command))
 
         # split command
 
         # split command
-        command = command.split(sep=' ')
+        command = command.split(sep=" ")
 
         try:
             process = await asyncio.create_subprocess_exec(
 
         try:
             process = await asyncio.create_subprocess_exec(
-                *command,
-                stdout=asyncio.subprocess.PIPE,
-                stderr=asyncio.subprocess.PIPE
+                *command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
             )
 
             # wait for command terminate
             )
 
             # wait for command terminate
@@ -1195,25 +1323,27 @@ class K8sHelmConnector(K8sConnector):
 
             return_code = process.returncode
 
 
             return_code = process.returncode
 
-            output = ''
+            output = ""
             if stdout:
             if stdout:
-                output = stdout.decode('utf-8').strip()
+                output = stdout.decode("utf-8").strip()
                 # output = stdout.decode()
             if stderr:
                 # output = stdout.decode()
             if stderr:
-                output = stderr.decode('utf-8').strip()
+                output = stderr.decode("utf-8").strip()
                 # output = stderr.decode()
 
             if return_code != 0 and show_error_log:
                 # output = stderr.decode()
 
             if return_code != 0 and show_error_log:
-                self.log.debug('Return code (FAIL): {}\nOutput:\n{}'.format(return_code, output))
+                self.log.debug(
+                    "Return code (FAIL): {}\nOutput:\n{}".format(return_code, output)
+                )
             else:
             else:
-                self.log.debug('Return code: {}'.format(return_code))
+                self.log.debug("Return code: {}".format(return_code))
 
             if raise_exception_on_error and return_code != 0:
                 raise K8sException(output)
 
             if encode_utf8:
 
             if raise_exception_on_error and return_code != 0:
                 raise K8sException(output)
 
             if encode_utf8:
-                output = output.encode('utf-8').strip()
-                output = str(output).replace('\\n', '\n')
+                output = output.encode("utf-8").strip()
+                output = str(output).replace("\\n", "\n")
 
             return output, return_code
 
 
             return output, return_code
 
@@ -1222,21 +1352,19 @@ class K8sHelmConnector(K8sConnector):
         except K8sException:
             raise
         except Exception as e:
         except K8sException:
             raise
         except Exception as e:
-            msg = 'Exception executing command: {} -> {}'.format(command, e)
+            msg = "Exception executing command: {} -> {}".format(command, e)
             self.log.error(msg)
             if raise_exception_on_error:
                 raise K8sException(e) from e
             else:
             self.log.error(msg)
             if raise_exception_on_error:
                 raise K8sException(e) from e
             else:
-                return '', -1
+                return "", -1
 
     def _check_file_exists(self, filename: str, exception_if_not_exists: bool = False):
         # self.log.debug('Checking if file {} exists...'.format(filename))
         if os.path.exists(filename):
             return True
         else:
 
     def _check_file_exists(self, filename: str, exception_if_not_exists: bool = False):
         # self.log.debug('Checking if file {} exists...'.format(filename))
         if os.path.exists(filename):
             return True
         else:
-            msg = 'File {} does not exist'.format(filename)
+            msg = "File {} does not exist".format(filename)
             if exception_if_not_exists:
                 # self.log.error(msg)
                 raise K8sException(msg)
             if exception_if_not_exists:
                 # self.log.error(msg)
                 raise K8sException(msg)
-
-
index e01fa0b..7a3bf27 100644 (file)
 
 import asyncio
 import concurrent
 
 import asyncio
 import concurrent
-from .exceptions import NotImplemented
+import os
+import uuid
 
 
-import io
 import juju
 import juju
-# from juju.bundle import BundleHandler
 from juju.controller import Controller
 from juju.controller import Controller
-from juju.model import Model
-from juju.errors import JujuAPIError, JujuError
 from n2vc.exceptions import K8sException
 from n2vc.exceptions import K8sException
-
 from n2vc.k8s_conn import K8sConnector
 from n2vc.k8s_conn import K8sConnector
+import yaml
 
 
-import os
+from .exceptions import MethodNotImplemented
+
+
+# from juju.bundle import BundleHandler
 # import re
 # import ssl
 # from .vnf import N2VC
 # import re
 # import ssl
 # from .vnf import N2VC
-
-import uuid
-import yaml
-
-
 class K8sJujuConnector(K8sConnector):
 class K8sJujuConnector(K8sConnector):
-
     def __init__(
     def __init__(
-            self,
-            fs: object,
-            db: object,
-            kubectl_command: str = '/usr/bin/kubectl',
-            juju_command: str = '/usr/bin/juju',
-            log: object = None,
-            on_update_db=None,
+        self,
+        fs: object,
+        db: object,
+        kubectl_command: str = "/usr/bin/kubectl",
+        juju_command: str = "/usr/bin/juju",
+        log: object = None,
+        on_update_db=None,
     ):
         """
 
     ):
         """
 
@@ -56,14 +50,11 @@ class K8sJujuConnector(K8sConnector):
 
         # parent class
         K8sConnector.__init__(
 
         # parent class
         K8sConnector.__init__(
-            self,
-            db,
-            log=log,
-            on_update_db=on_update_db,
+            self, db, log=log, on_update_db=on_update_db,
         )
 
         self.fs = fs
         )
 
         self.fs = fs
-        self.log.debug('Initializing K8S Juju connector')
+        self.log.debug("Initializing K8S Juju connector")
 
         self.authenticated = False
         self.models = {}
 
         self.authenticated = False
         self.models = {}
@@ -71,23 +62,27 @@ class K8sJujuConnector(K8sConnector):
         self.juju_command = juju_command
         self.juju_secret = ""
 
         self.juju_command = juju_command
         self.juju_secret = ""
 
-        self.log.debug('K8S Juju connector initialized')
+        self.log.debug("K8S Juju connector initialized")
 
     """Initialization"""
 
     """Initialization"""
+
     async def init_env(
         self,
         k8s_creds: str,
     async def init_env(
         self,
         k8s_creds: str,
-        namespace: str = 'kube-system',
+        namespace: str = "kube-system",
         reuse_cluster_uuid: str = None,
     ) -> (str, bool):
         """
         It prepares a given K8s cluster environment to run Juju bundles.
 
         reuse_cluster_uuid: str = None,
     ) -> (str, bool):
         """
         It prepares a given K8s cluster environment to run Juju bundles.
 
-        :param k8s_creds: credentials to access a given K8s cluster, i.e. a valid '.kube/config'
-        :param namespace: optional namespace to be used for juju. By default, 'kube-system' will be used
+        :param k8s_creds: credentials to access a given K8s cluster, i.e. a valid
+            '.kube/config'
+        :param namespace: optional namespace to be used for juju. By default,
+            'kube-system' will be used
         :param reuse_cluster_uuid: existing cluster uuid for reuse
         :param reuse_cluster_uuid: existing cluster uuid for reuse
-        :return: uuid of the K8s cluster and True if connector has installed some software in the cluster
-        (on error, an exception will be raised)
+        :return: uuid of the K8s cluster and True if connector has installed some
+            software in the cluster
+            (on error, an exception will be raised)
         """
 
         """Bootstrapping
         """
 
         """Bootstrapping
@@ -155,38 +150,34 @@ class K8sJujuConnector(K8sConnector):
             # Parse ~/.local/share/juju/controllers.yaml
             # controllers.testing.api-endpoints|ca-cert|uuid
             self.log.debug("Getting controller endpoints")
             # Parse ~/.local/share/juju/controllers.yaml
             # controllers.testing.api-endpoints|ca-cert|uuid
             self.log.debug("Getting controller endpoints")
-            with open(os.path.expanduser(
-                "~/.local/share/juju/controllers.yaml"
-            )) as f:
+            with open(os.path.expanduser("~/.local/share/juju/controllers.yaml")) as f:
                 controllers = yaml.load(f, Loader=yaml.Loader)
                 controllers = yaml.load(f, Loader=yaml.Loader)
-                controller = controllers['controllers'][cluster_uuid]
-                endpoints = controller['api-endpoints']
+                controller = controllers["controllers"][cluster_uuid]
+                endpoints = controller["api-endpoints"]
                 self.juju_endpoint = endpoints[0]
                 self.juju_endpoint = endpoints[0]
-                self.juju_ca_cert = controller['ca-cert']
+                self.juju_ca_cert = controller["ca-cert"]
 
             # Parse ~/.local/share/juju/accounts
             # controllers.testing.user|password
             self.log.debug("Getting accounts")
 
             # Parse ~/.local/share/juju/accounts
             # controllers.testing.user|password
             self.log.debug("Getting accounts")
-            with open(os.path.expanduser(
-                "~/.local/share/juju/accounts.yaml"
-            )) as f:
+            with open(os.path.expanduser("~/.local/share/juju/accounts.yaml")) as f:
                 controllers = yaml.load(f, Loader=yaml.Loader)
                 controllers = yaml.load(f, Loader=yaml.Loader)
-                controller = controllers['controllers'][cluster_uuid]
+                controller = controllers["controllers"][cluster_uuid]
 
 
-                self.juju_user = controller['user']
-                self.juju_secret = controller['password']
+                self.juju_user = controller["user"]
+                self.juju_secret = controller["password"]
 
             # raise Exception("EOL")
 
             self.juju_public_key = None
 
             config = {
 
             # raise Exception("EOL")
 
             self.juju_public_key = None
 
             config = {
-                'endpoint': self.juju_endpoint,
-                'username': self.juju_user,
-                'secret': self.juju_secret,
-                'cacert': self.juju_ca_cert,
-                'namespace': namespace,
-                'loadbalancer': loadbalancer,
+                "endpoint": self.juju_endpoint,
+                "username": self.juju_user,
+                "secret": self.juju_secret,
+                "cacert": self.juju_ca_cert,
+                "namespace": namespace,
+                "loadbalancer": loadbalancer,
             }
 
             # Store the cluster configuration so it
             }
 
             # Store the cluster configuration so it
@@ -200,10 +191,10 @@ class K8sJujuConnector(K8sConnector):
 
             config = self.get_config(cluster_uuid)
 
 
             config = self.get_config(cluster_uuid)
 
-            self.juju_endpoint = config['endpoint']
-            self.juju_user = config['username']
-            self.juju_secret = config['secret']
-            self.juju_ca_cert = config['cacert']
+            self.juju_endpoint = config["endpoint"]
+            self.juju_user = config["username"]
+            self.juju_secret = config["secret"]
+            self.juju_ca_cert = config["cacert"]
             self.juju_public_key = None
 
         # Login to the k8s cluster
             self.juju_public_key = None
 
         # Login to the k8s cluster
@@ -211,52 +202,44 @@ class K8sJujuConnector(K8sConnector):
             await self.login(cluster_uuid)
 
         # We're creating a new cluster
             await self.login(cluster_uuid)
 
         # We're creating a new cluster
-        #print("Getting model {}".format(self.get_namespace(cluster_uuid), cluster_uuid=cluster_uuid))
-        #model = await self.get_model(
+        # print("Getting model {}".format(self.get_namespace(cluster_uuid),
+        #    cluster_uuid=cluster_uuid))
+        # model = await self.get_model(
         #    self.get_namespace(cluster_uuid),
         #    cluster_uuid=cluster_uuid
         #    self.get_namespace(cluster_uuid),
         #    cluster_uuid=cluster_uuid
-        #)
+        # )
 
 
-        ## Disconnect from the model
-        #if model and model.is_connected():
+        # Disconnect from the model
+        # if model and model.is_connected():
         #    await model.disconnect()
 
         return cluster_uuid, True
 
     """Repo Management"""
         #    await model.disconnect()
 
         return cluster_uuid, True
 
     """Repo Management"""
+
     async def repo_add(
     async def repo_add(
-        self,
-        name: str,
-        url: str,
-        type: str = "charm",
+        self, name: str, url: str, _type: str = "charm",
     ):
     ):
-        raise NotImplemented()
+        raise MethodNotImplemented()
 
     async def repo_list(self):
 
     async def repo_list(self):
-        raise NotImplemented()
+        raise MethodNotImplemented()
 
     async def repo_remove(
 
     async def repo_remove(
-        self,
-        name: str,
+        self, name: str,
     ):
     ):
-        raise NotImplemented()
+        raise MethodNotImplemented()
 
 
-    async def synchronize_repos(
-        self,
-        cluster_uuid: str,
-        name: str
-    ):
+    async def synchronize_repos(self, cluster_uuid: str, name: str):
         """
         Returns None as currently add_repo is not implemented
         """
         return None
 
     """Reset"""
         """
         Returns None as currently add_repo is not implemented
         """
         return None
 
     """Reset"""
+
     async def reset(
     async def reset(
-            self,
-            cluster_uuid: str,
-            force: bool = False,
-            uninstall_sw: bool = False
+        self, cluster_uuid: str, force: bool = False, uninstall_sw: bool = False
     ) -> bool:
         """Reset a cluster
 
     ) -> bool:
         """Reset a cluster
 
@@ -275,10 +258,7 @@ class K8sJujuConnector(K8sConnector):
                 namespace = self.get_namespace(cluster_uuid)
                 if await self.has_model(namespace):
                     self.log.debug("[reset] Destroying model")
                 namespace = self.get_namespace(cluster_uuid)
                 if await self.has_model(namespace):
                     self.log.debug("[reset] Destroying model")
-                    await self.controller.destroy_model(
-                        namespace,
-                        destroy_storage=True
-                    )
+                    await self.controller.destroy_model(namespace, destroy_storage=True)
 
                 # Disconnect from the controller
                 self.log.debug("[reset] Disconnecting controller")
 
                 # Disconnect from the controller
                 self.log.debug("[reset] Disconnecting controller")
@@ -308,7 +288,7 @@ class K8sJujuConnector(K8sConnector):
         params: dict = None,
         db_dict: dict = None,
         kdu_name: str = None,
         params: dict = None,
         db_dict: dict = None,
         kdu_name: str = None,
-        namespace: str = None
+        namespace: str = None,
     ) -> bool:
         """Install a bundle
 
     ) -> bool:
         """Install a bundle
 
@@ -350,7 +330,8 @@ class K8sJujuConnector(K8sConnector):
             "Juju bundle that models the KDU, in any of the following ways:
                 - <juju-repo>/<juju-bundle>
                 - <juju-bundle folder under k8s_models folder in the package>
             "Juju bundle that models the KDU, in any of the following ways:
                 - <juju-repo>/<juju-bundle>
                 - <juju-bundle folder under k8s_models folder in the package>
-                - <juju-bundle tgz file (w/ or w/o extension) under k8s_models folder in the package>
+                - <juju-bundle tgz file (w/ or w/o extension) under k8s_models folder
+                    in the package>
                 - <URL_where_to_fetch_juju_bundle>
             """
 
                 - <URL_where_to_fetch_juju_bundle>
             """
 
@@ -389,17 +370,17 @@ class K8sJujuConnector(K8sConnector):
                         self.log.debug("Waiting for all units to be active...")
                         await model.block_until(
                             lambda: all(
                         self.log.debug("Waiting for all units to be active...")
                         await model.block_until(
                             lambda: all(
-                                unit.agent_status == 'idle'
-                                and application.status in ['active', 'unknown']
-                                and unit.workload_status in [
-                                    'active', 'unknown'
-                                ] for unit in application.units
+                                unit.agent_status == "idle"
+                                and application.status in ["active", "unknown"]
+                                and unit.workload_status in ["active", "unknown"]
+                                for unit in application.units
                             ),
                             ),
-                            timeout=timeout
+                            timeout=timeout,
                         )
                         self.log.debug("All units active.")
 
                         )
                         self.log.debug("All units active.")
 
-                    except concurrent.futures._base.TimeoutError:    # TODO use asyncio.TimeoutError
+                    # TODO use asyncio.TimeoutError
+                    except concurrent.futures._base.TimeoutError:
                         os.chdir(previous_workdir)
                         self.log.debug("[install] Timeout exceeded; resetting cluster")
                         await self.reset(cluster_uuid)
                         os.chdir(previous_workdir)
                         self.log.debug("[install] Timeout exceeded; resetting cluster")
                         await self.reset(cluster_uuid)
@@ -415,10 +396,7 @@ class K8sJujuConnector(K8sConnector):
             return kdu_instance
         raise Exception("Unable to install")
 
             return kdu_instance
         raise Exception("Unable to install")
 
-    async def instances_list(
-            self,
-            cluster_uuid: str
-    ) -> list:
+    async def instances_list(self, cluster_uuid: str) -> list:
         """
         returns a list of deployed releases in a cluster
 
         """
         returns a list of deployed releases in a cluster
 
@@ -461,7 +439,7 @@ class K8sJujuConnector(K8sConnector):
         namespace = self.get_namespace(cluster_uuid)
         model = await self.get_model(namespace, cluster_uuid=cluster_uuid)
 
         namespace = self.get_namespace(cluster_uuid)
         model = await self.get_model(namespace, cluster_uuid=cluster_uuid)
 
-        with open(kdu_model, 'r') as f:
+        with open(kdu_model, "r") as f:
             bundle = yaml.safe_load(f)
 
             """
             bundle = yaml.safe_load(f)
 
             """
@@ -483,31 +461,29 @@ class K8sJujuConnector(K8sConnector):
             }
             """
             # TODO: This should be returned in an agreed-upon format
             }
             """
             # TODO: This should be returned in an agreed-upon format
-            for name in bundle['applications']:
+            for name in bundle["applications"]:
                 self.log.debug(model.applications)
                 application = model.applications[name]
                 self.log.debug(application)
 
                 self.log.debug(model.applications)
                 application = model.applications[name]
                 self.log.debug(application)
 
-                path = bundle['applications'][name]['charm']
+                path = bundle["applications"][name]["charm"]
 
                 try:
                     await application.upgrade_charm(switch=path)
                 except juju.errors.JujuError as ex:
 
                 try:
                     await application.upgrade_charm(switch=path)
                 except juju.errors.JujuError as ex:
-                    if 'already running charm' in str(ex):
+                    if "already running charm" in str(ex):
                         # We're already running this version
                         pass
 
         await model.disconnect()
 
         return True
                         # We're already running this version
                         pass
 
         await model.disconnect()
 
         return True
-        raise NotImplemented()
+        raise MethodNotImplemented()
 
     """Rollback"""
 
     """Rollback"""
+
     async def rollback(
     async def rollback(
-        self,
-        cluster_uuid: str,
-        kdu_instance: str,
-        revision: int = 0,
+        self, cluster_uuid: str, kdu_instance: str, revision: int = 0,
     ) -> str:
         """Rollback a model
 
     ) -> str:
         """Rollback a model
 
@@ -519,14 +495,11 @@ class K8sJujuConnector(K8sConnector):
         :return: If successful, returns the revision of active KDU instance,
                  or raises an exception
         """
         :return: If successful, returns the revision of active KDU instance,
                  or raises an exception
         """
-        raise NotImplemented()
+        raise MethodNotImplemented()
 
     """Deletion"""
 
     """Deletion"""
-    async def uninstall(
-        self,
-        cluster_uuid: str,
-        kdu_instance: str
-    ) -> bool:
+
+    async def uninstall(self, cluster_uuid: str, kdu_instance: str) -> bool:
         """Uninstall a KDU instance
 
         :param cluster_uuid str: The UUID of the cluster
         """Uninstall a KDU instance
 
         :param cluster_uuid str: The UUID of the cluster
@@ -572,11 +545,15 @@ class K8sJujuConnector(K8sConnector):
             await self.login(cluster_uuid)
 
         if not params or "application-name" not in params:
             await self.login(cluster_uuid)
 
         if not params or "application-name" not in params:
-            raise K8sException("Missing application-name argument, \
-                                argument needed for K8s actions")
+            raise K8sException(
+                "Missing application-name argument, \
+                                argument needed for K8s actions"
+            )
         try:
         try:
-            self.log.debug("[exec_primitive] Getting model "
-                           "kdu_instance: {}".format(kdu_instance))
+            self.log.debug(
+                "[exec_primitive] Getting model "
+                "kdu_instance: {}".format(kdu_instance)
+            )
 
             model = await self.get_model(kdu_instance, cluster_uuid)
 
 
             model = await self.get_model(kdu_instance, cluster_uuid)
 
@@ -607,7 +584,9 @@ class K8sJujuConnector(K8sConnector):
             )
 
             if status != "completed":
             )
 
             if status != "completed":
-                raise K8sException("status is not completed: {} output: {}".format(status, output))
+                raise K8sException(
+                    "status is not completed: {} output: {}".format(status, output)
+                )
 
             return output
 
 
             return output
 
@@ -617,10 +596,8 @@ class K8sJujuConnector(K8sConnector):
             raise K8sException(message=error_msg)
 
     """Introspection"""
             raise K8sException(message=error_msg)
 
     """Introspection"""
-    async def inspect_kdu(
-        self,
-        kdu_model: str,
-    ) -> dict:
+
+    async def inspect_kdu(self, kdu_model: str,) -> dict:
         """Inspect a KDU
 
         Inspects a bundle and returns a dictionary of config parameters and
         """Inspect a KDU
 
         Inspects a bundle and returns a dictionary of config parameters and
@@ -633,7 +610,7 @@ class K8sJujuConnector(K8sConnector):
         """
 
         kdu = {}
         """
 
         kdu = {}
-        with open(kdu_model, 'r') as f:
+        with open(kdu_model, "r") as f:
             bundle = yaml.safe_load(f)
 
             """
             bundle = yaml.safe_load(f)
 
             """
@@ -655,14 +632,11 @@ class K8sJujuConnector(K8sConnector):
             }
             """
             # TODO: This should be returned in an agreed-upon format
             }
             """
             # TODO: This should be returned in an agreed-upon format
-            kdu = bundle['applications']
+            kdu = bundle["applications"]
 
         return kdu
 
 
         return kdu
 
-    async def help_kdu(
-        self,
-        kdu_model: str,
-    ) -> str:
+    async def help_kdu(self, kdu_model: str,) -> str:
         """View the README
 
         If available, returns the README of the bundle.
         """View the README
 
         If available, returns the README of the bundle.
@@ -673,21 +647,17 @@ class K8sJujuConnector(K8sConnector):
         """
         readme = None
 
         """
         readme = None
 
-        files = ['README', 'README.txt', 'README.md']
+        files = ["README", "README.txt", "README.md"]
         path = os.path.dirname(kdu_model)
         for file in os.listdir(path):
             if file in files:
         path = os.path.dirname(kdu_model)
         for file in os.listdir(path):
             if file in files:
-                with open(file, 'r') as f:
+                with open(file, "r") as f:
                     readme = f.read()
                     break
 
         return readme
 
                     readme = f.read()
                     break
 
         return readme
 
-    async def status_kdu(
-        self,
-        cluster_uuid: str,
-        kdu_instance: str,
-    ) -> dict:
+    async def status_kdu(self, cluster_uuid: str, kdu_instance: str,) -> dict:
         """Get the status of the KDU
 
         Get the current status of the KDU instance.
         """Get the status of the KDU
 
         Get the current status of the KDU instance.
@@ -700,7 +670,9 @@ class K8sJujuConnector(K8sConnector):
         """
         status = {}
 
         """
         status = {}
 
-        model = await self.get_model(self.get_namespace(cluster_uuid), cluster_uuid=cluster_uuid)
+        model = await self.get_model(
+            self.get_namespace(cluster_uuid), cluster_uuid=cluster_uuid
+        )
 
         # model = await self.get_model_by_uuid(cluster_uuid)
         if model:
 
         # model = await self.get_model_by_uuid(cluster_uuid)
         if model:
@@ -709,9 +681,7 @@ class K8sJujuConnector(K8sConnector):
 
             for name in model_status.applications:
                 application = model_status.applications[name]
 
             for name in model_status.applications:
                 application = model_status.applications[name]
-                status[name] = {
-                    'status': application['status']['status']
-                }
+                status[name] = {"status": application["status"]["status"]}
 
             if model.is_connected():
                 await model.disconnect()
 
             if model.is_connected():
                 await model.disconnect()
@@ -719,11 +689,7 @@ class K8sJujuConnector(K8sConnector):
         return status
 
     # Private methods
         return status
 
     # Private methods
-    async def add_k8s(
-        self,
-        cloud_name: str,
-        credentials: str,
-    ) -> bool:
+    async def add_k8s(self, cloud_name: str, credentials: str,) -> bool:
         """Add a k8s cloud to Juju
 
         Adds a Kubernetes cloud to Juju, so it can be bootstrapped with a
         """Add a k8s cloud to Juju
 
         Adds a Kubernetes cloud to Juju, so it can be bootstrapped with a
@@ -751,7 +717,7 @@ class K8sJujuConnector(K8sConnector):
         await process.stdin.drain()
         process.stdin.close()
 
         await process.stdin.drain()
         process.stdin.close()
 
-        stdout, stderr = await process.communicate()
+        _stdout, stderr = await process.communicate()
 
         return_code = process.returncode
 
 
         return_code = process.returncode
 
@@ -762,11 +728,7 @@ class K8sJujuConnector(K8sConnector):
 
         return True
 
 
         return True
 
-    async def add_model(
-        self,
-        model_name: str,
-        cluster_uuid: str,
-    ) -> juju.model.Model:
+    async def add_model(self, model_name: str, cluster_uuid: str,) -> juju.model.Model:
         """Adds a model to the controller
 
         Adds a new model to the Juju controller
         """Adds a model to the controller
 
         Adds a new model to the Juju controller
@@ -778,11 +740,12 @@ class K8sJujuConnector(K8sConnector):
         if not self.authenticated:
             await self.login(cluster_uuid)
 
         if not self.authenticated:
             await self.login(cluster_uuid)
 
-        self.log.debug("Adding model '{}' to cluster_uuid '{}'".format(model_name, cluster_uuid))
+        self.log.debug(
+            "Adding model '{}' to cluster_uuid '{}'".format(model_name, cluster_uuid)
+        )
         try:
             model = await self.controller.add_model(
         try:
             model = await self.controller.add_model(
-                model_name,
-                config={'authorized-keys': self.juju_public_key}
+                model_name, config={"authorized-keys": self.juju_public_key}
             )
         except Exception as ex:
             self.log.debug(ex)
             )
         except Exception as ex:
             self.log.debug(ex)
@@ -792,10 +755,7 @@ class K8sJujuConnector(K8sConnector):
         return model
 
     async def bootstrap(
         return model
 
     async def bootstrap(
-        self,
-        cloud_name: str,
-        cluster_uuid: str,
-        loadbalancer: bool
+        self, cloud_name: str, cluster_uuid: str, loadbalancer: bool
     ) -> bool:
         """Bootstrap a Kubernetes controller
 
     ) -> bool:
         """Bootstrap a Kubernetes controller
 
@@ -811,35 +771,38 @@ class K8sJujuConnector(K8sConnector):
             cmd = [self.juju_command, "bootstrap", cloud_name, cluster_uuid]
         else:
             """
             cmd = [self.juju_command, "bootstrap", cloud_name, cluster_uuid]
         else:
             """
-            For public clusters, specify that the controller service is using a LoadBalancer.
+            For public clusters, specify that the controller service is using a
+            LoadBalancer.
             """
             """
-            cmd = [self.juju_command, "bootstrap", cloud_name, cluster_uuid, "--config", "controller-service-type=loadbalancer"]
-
-        self.log.debug("Bootstrapping controller {} in cloud {}".format(
-            cluster_uuid, cloud_name
-        ))
+            cmd = [
+                self.juju_command,
+                "bootstrap",
+                cloud_name,
+                cluster_uuid,
+                "--config",
+                "controller-service-type=loadbalancer",
+            ]
+
+        self.log.debug(
+            "Bootstrapping controller {} in cloud {}".format(cluster_uuid, cloud_name)
+        )
 
         process = await asyncio.create_subprocess_exec(
 
         process = await asyncio.create_subprocess_exec(
-            *cmd,
-            stdout=asyncio.subprocess.PIPE,
-            stderr=asyncio.subprocess.PIPE,
+            *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
         )
 
         )
 
-        stdout, stderr = await process.communicate()
+        _stdout, stderr = await process.communicate()
 
         return_code = process.returncode
 
         if return_code > 0:
             #
 
         return_code = process.returncode
 
         if return_code > 0:
             #
-            if b'already exists' not in stderr:
+            if b"already exists" not in stderr:
                 raise Exception(stderr)
 
         return True
 
                 raise Exception(stderr)
 
         return True
 
-    async def destroy_controller(
-        self,
-        cluster_uuid: str
-    ) -> bool:
+    async def destroy_controller(self, cluster_uuid: str) -> bool:
         """Destroy a Kubernetes controller
 
         Destroy an existing Kubernetes controller.
         """Destroy a Kubernetes controller
 
         Destroy an existing Kubernetes controller.
@@ -853,28 +816,23 @@ class K8sJujuConnector(K8sConnector):
             "--destroy-all-models",
             "--destroy-storage",
             "-y",
             "--destroy-all-models",
             "--destroy-storage",
             "-y",
-            cluster_uuid
+            cluster_uuid,
         ]
 
         process = await asyncio.create_subprocess_exec(
         ]
 
         process = await asyncio.create_subprocess_exec(
-            *cmd,
-            stdout=asyncio.subprocess.PIPE,
-            stderr=asyncio.subprocess.PIPE,
+            *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
         )
 
         )
 
-        stdout, stderr = await process.communicate()
+        _stdout, stderr = await process.communicate()
 
         return_code = process.returncode
 
         if return_code > 0:
             #
 
         return_code = process.returncode
 
         if return_code > 0:
             #
-            if 'already exists' not in stderr:
+            if "already exists" not in stderr:
                 raise Exception(stderr)
 
                 raise Exception(stderr)
 
-    def get_config(
-        self,
-        cluster_uuid: str,
-    ) -> dict:
+    def get_config(self, cluster_uuid: str,) -> dict:
         """Get the cluster configuration
 
         Gets the configuration of the cluster
         """Get the cluster configuration
 
         Gets the configuration of the cluster
@@ -884,21 +842,15 @@ class K8sJujuConnector(K8sConnector):
         """
         cluster_config = "{}/{}.yaml".format(self.fs.path, cluster_uuid)
         if os.path.exists(cluster_config):
         """
         cluster_config = "{}/{}.yaml".format(self.fs.path, cluster_uuid)
         if os.path.exists(cluster_config):
-            with open(cluster_config, 'r') as f:
+            with open(cluster_config, "r") as f:
                 config = yaml.safe_load(f.read())
                 return config
         else:
             raise Exception(
                 config = yaml.safe_load(f.read())
                 return config
         else:
             raise Exception(
-                "Unable to locate configuration for cluster {}".format(
-                    cluster_uuid
-                )
+                "Unable to locate configuration for cluster {}".format(cluster_uuid)
             )
 
             )
 
-    async def get_model(
-        self,
-        model_name: str,
-        cluster_uuid: str,
-    ) -> juju.model.Model:
+    async def get_model(self, model_name: str, cluster_uuid: str,) -> juju.model.Model:
         """Get a model from the Juju Controller.
 
         Note: Model objects returned must call disconnected() before it goes
         """Get a model from the Juju Controller.
 
         Note: Model objects returned must call disconnected() before it goes
@@ -914,15 +866,10 @@ class K8sJujuConnector(K8sConnector):
         models = await self.controller.list_models()
         if model_name in models:
             self.log.debug("Found model: {}".format(model_name))
         models = await self.controller.list_models()
         if model_name in models:
             self.log.debug("Found model: {}".format(model_name))
-            model = await self.controller.get_model(
-                model_name
-            )
+            model = await self.controller.get_model(model_name)
         return model
 
         return model
 
-    def get_namespace(
-        self,
-        cluster_uuid: str,
-    ) -> str:
+    def get_namespace(self, cluster_uuid: str,) -> str:
         """Get the namespace UUID
         Gets the namespace's unique name
 
         """Get the namespace UUID
         Gets the namespace's unique name
 
@@ -932,18 +879,15 @@ class K8sJujuConnector(K8sConnector):
         config = self.get_config(cluster_uuid)
 
         # Make sure the name is in the config
         config = self.get_config(cluster_uuid)
 
         # Make sure the name is in the config
-        if 'namespace' not in config:
+        if "namespace" not in config:
             raise Exception("Namespace not found.")
 
         # TODO: We want to make sure this is unique to the cluster, in case
         # the cluster is being reused.
         # Consider pre/appending the cluster id to the namespace string
             raise Exception("Namespace not found.")
 
         # TODO: We want to make sure this is unique to the cluster, in case
         # the cluster is being reused.
         # Consider pre/appending the cluster id to the namespace string
-        return config['namespace']
+        return config["namespace"]
 
 
-    async def has_model(
-        self,
-        model_name: str
-    ) -> bool:
+    async def has_model(self, model_name: str) -> bool:
         """Check if a model exists in the controller
 
         Checks to see if a model exists in the connected Juju controller.
         """Check if a model exists in the controller
 
         Checks to see if a model exists in the connected Juju controller.
@@ -957,10 +901,7 @@ class K8sJujuConnector(K8sConnector):
             return True
         return False
 
             return True
         return False
 
-    def is_local_k8s(
-        self,
-        credentials: str,
-    ) -> bool:
+    def is_local_k8s(self, credentials: str,) -> bool:
         """Check if a cluster is local
 
         Checks if a cluster is running in the local host
         """Check if a cluster is local
 
         Checks if a cluster is running in the local host
@@ -973,9 +914,9 @@ class K8sJujuConnector(K8sConnector):
             host_ip = os.getenv("OSMLCM_VCA_APIPROXY")
 
         if creds and host_ip:
             host_ip = os.getenv("OSMLCM_VCA_APIPROXY")
 
         if creds and host_ip:
-            for cluster in creds['clusters']:
-                if 'server' in cluster['cluster']:
-                    if host_ip in cluster['cluster']['server']:
+            for cluster in creds["clusters"]:
+                if "server" in cluster["cluster"]:
+                    if host_ip in cluster["cluster"]["server"]:
                         return True
 
         return False
                         return True
 
         return False
@@ -991,10 +932,10 @@ class K8sJujuConnector(K8sConnector):
         # Test: Make sure we have the credentials loaded
         config = self.get_config(cluster_uuid)
 
         # Test: Make sure we have the credentials loaded
         config = self.get_config(cluster_uuid)
 
-        self.juju_endpoint = config['endpoint']
-        self.juju_user = config['username']
-        self.juju_secret = config['secret']
-        self.juju_ca_cert = config['cacert']
+        self.juju_endpoint = config["endpoint"]
+        self.juju_user = config["username"]
+        self.juju_secret = config["secret"]
+        self.juju_ca_cert = config["cacert"]
         self.juju_public_key = None
 
         self.controller = Controller()
         self.juju_public_key = None
 
         self.controller = Controller()
@@ -1002,9 +943,7 @@ class K8sJujuConnector(K8sConnector):
         if self.juju_secret:
             self.log.debug(
                 "Connecting to controller... ws://{} as {}/{}".format(
         if self.juju_secret:
             self.log.debug(
                 "Connecting to controller... ws://{} as {}/{}".format(
-                    self.juju_endpoint,
-                    self.juju_user,
-                    self.juju_secret,
+                    self.juju_endpoint, self.juju_user, self.juju_secret,
                 )
             )
             try:
                 )
             )
             try:
@@ -1035,18 +974,13 @@ class K8sJujuConnector(K8sConnector):
             await self.models[model].disconnect()
 
         if self.controller:
             await self.models[model].disconnect()
 
         if self.controller:
-            self.log.debug("Disconnecting controller {}".format(
-                self.controller
-            ))
+            self.log.debug("Disconnecting controller {}".format(self.controller))
             await self.controller.disconnect()
             self.controller = None
 
         self.authenticated = False
 
             await self.controller.disconnect()
             self.controller = None
 
         self.authenticated = False
 
-    async def remove_cloud(
-        self,
-        cloud_name: str,
-    ) -> bool:
+    async def remove_cloud(self, cloud_name: str,) -> bool:
         """Remove a k8s cloud from Juju
 
         Removes a Kubernetes cloud from Juju.
         """Remove a k8s cloud from Juju
 
         Removes a Kubernetes cloud from Juju.
@@ -1059,12 +993,10 @@ class K8sJujuConnector(K8sConnector):
         # Remove the bootstrapped controller
         cmd = [self.juju_command, "remove-k8s", "--client", cloud_name]
         process = await asyncio.create_subprocess_exec(
         # Remove the bootstrapped controller
         cmd = [self.juju_command, "remove-k8s", "--client", cloud_name]
         process = await asyncio.create_subprocess_exec(
-            *cmd,
-            stdout=asyncio.subprocess.PIPE,
-            stderr=asyncio.subprocess.PIPE,
+            *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
         )
 
         )
 
-        stdout, stderr = await process.communicate()
+        _stdout, stderr = await process.communicate()
 
         return_code = process.returncode
 
 
         return_code = process.returncode
 
@@ -1074,12 +1006,10 @@ class K8sJujuConnector(K8sConnector):
         # Remove the cloud from the local config
         cmd = [self.juju_command, "remove-cloud", "--client", cloud_name]
         process = await asyncio.create_subprocess_exec(
         # Remove the cloud from the local config
         cmd = [self.juju_command, "remove-cloud", "--client", cloud_name]
         process = await asyncio.create_subprocess_exec(
-            *cmd,
-            stdout=asyncio.subprocess.PIPE,
-            stderr=asyncio.subprocess.PIPE,
+            *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
         )
 
         )
 
-        stdout, stderr = await process.communicate()
+        _stdout, stderr = await process.communicate()
 
         return_code = process.returncode
 
 
         return_code = process.returncode
 
@@ -1088,11 +1018,7 @@ class K8sJujuConnector(K8sConnector):
 
         return True
 
 
         return True
 
-    async def set_config(
-        self,
-        cluster_uuid: str,
-        config: dict,
-    ) -> bool:
+    async def set_config(self, cluster_uuid: str, config: dict,) -> bool:
         """Save the cluster configuration
 
         Saves the cluster information to the file store
         """Save the cluster configuration
 
         Saves the cluster information to the file store
@@ -1105,7 +1031,7 @@ class K8sJujuConnector(K8sConnector):
         cluster_config = "{}/{}.yaml".format(self.fs.path, cluster_uuid)
         if not os.path.exists(cluster_config):
             self.log.debug("Writing config to {}".format(cluster_config))
         cluster_config = "{}/{}.yaml".format(self.fs.path, cluster_uuid)
         if not os.path.exists(cluster_config):
             self.log.debug("Writing config to {}".format(cluster_config))
-            with open(cluster_config, 'w') as f:
+            with open(cluster_config, "w") as f:
                 f.write(yaml.dump(config, Dumper=yaml.Dumper))
 
         return True
                 f.write(yaml.dump(config, Dumper=yaml.Dumper))
 
         return True
index 87a645d..d588a1d 100644 (file)
 ##
 
 
 ##
 
 
-import logging
 import asyncio
 import asyncio
-import time
-import inspect
 import datetime
 import datetime
-import threading    # only for logging purposes (not for using threads)
+import inspect
+import logging
+import threading  # only for logging purposes (not for using threads)
+import time
 
 
 class Loggable:
 
 
 class Loggable:
+    def __init__(self, log, log_to_console: bool = False, prefix: str = ""):
 
 
-    def __init__(
-            self,
-            log,
-            log_to_console: bool = False,
-            prefix: str = ''
-    ):
-
-        self._last_log_time = None   # used for time increment in logging
+        self._last_log_time = None  # used for time increment in logging
         self._log_to_console = log_to_console
         self._prefix = prefix
         if log is not None:
         self._log_to_console = log_to_console
         self._prefix = prefix
         if log is not None:
@@ -47,21 +41,21 @@ class Loggable:
             self.log = logging.getLogger(__name__)
 
     def debug(self, msg: str):
             self.log = logging.getLogger(__name__)
 
     def debug(self, msg: str):
-        self._log_msg(log_level='DEBUG', msg=msg)
+        self._log_msg(log_level="DEBUG", msg=msg)
 
     def info(self, msg: str):
 
     def info(self, msg: str):
-        self._log_msg(log_level='INFO', msg=msg)
+        self._log_msg(log_level="INFO", msg=msg)
 
     def warning(self, msg: str):
 
     def warning(self, msg: str):
-        self._log_msg(log_level='WARNING', msg=msg)
+        self._log_msg(log_level="WARNING", msg=msg)
 
     def error(self, msg: str):
 
     def error(self, msg: str):
-        self._log_msg(log_level='ERROR', msg=msg)
+        self._log_msg(log_level="ERROR", msg=msg)
 
     def critical(self, msg: str):
 
     def critical(self, msg: str):
-        self._log_msg(log_level='CRITICAL', msg=msg)
+        self._log_msg(log_level="CRITICAL", msg=msg)
 
 
-    ##################################################################################################
+    ####################################################################################
 
     def _log_msg(self, log_level: str, msg: str):
         """Generic log method"""
 
     def _log_msg(self, log_level: str, msg: str):
         """Generic log method"""
@@ -72,41 +66,41 @@ class Loggable:
             level=3,
             include_path=False,
             include_thread=False,
             level=3,
             include_path=False,
             include_thread=False,
-            include_coroutine=True
+            include_coroutine=True,
         )
         if self._log_to_console:
             print(msg)
         else:
             if self.log is not None:
         )
         if self._log_to_console:
             print(msg)
         else:
             if self.log is not None:
-                if log_level == 'DEBUG':
+                if log_level == "DEBUG":
                     self.log.debug(msg)
                     self.log.debug(msg)
-                elif log_level == 'INFO':
+                elif log_level == "INFO":
                     self.log.info(msg)
                     self.log.info(msg)
-                elif log_level == 'WARNING':
+                elif log_level == "WARNING":
                     self.log.warning(msg)
                     self.log.warning(msg)
-                elif log_level == 'ERROR':
+                elif log_level == "ERROR":
                     self.log.error(msg)
                     self.log.error(msg)
-                elif log_level == 'CRITICAL':
+                elif log_level == "CRITICAL":
                     self.log.critical(msg)
 
     def _format_log(
                     self.log.critical(msg)
 
     def _format_log(
-            self,
-            log_level: str,
-            msg: str = '',
-            obj: object = None,
-            level: int = None,
-            include_path: bool = False,
-            include_thread: bool = False,
-            include_coroutine: bool = True
+        self,
+        log_level: str,
+        msg: str = "",
+        obj: object = None,
+        level: int = None,
+        include_path: bool = False,
+        include_thread: bool = False,
+        include_coroutine: bool = True,
     ) -> str:
 
         # time increment from last log
         now = time.perf_counter()
         if self._last_log_time is None:
     ) -> str:
 
         # time increment from last log
         now = time.perf_counter()
         if self._last_log_time is None:
-            time_str = ' (+0.000)'
+            time_str = " (+0.000)"
         else:
             diff = round(now - self._last_log_time, 3)
         else:
             diff = round(now - self._last_log_time, 3)
-            time_str = ' (+{})'.format(diff)
+            time_str = " (+{})".format(diff)
         self._last_log_time = now
 
         if level is None:
         self._last_log_time = now
 
         if level is None:
@@ -119,49 +113,69 @@ class Loggable:
         lineno = fi.lineno
         # filename without path
         if not include_path:
         lineno = fi.lineno
         # filename without path
         if not include_path:
-            i = filename.rfind('/')
+            i = filename.rfind("/")
             if i > 0:
             if i > 0:
-                filename = filename[i+1:]
+                filename = filename[i + 1 :]
 
         # datetime
 
         # datetime
-        dt = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
+        dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
         dt = dt + time_str
         # dt = time_str       # logger already shows datetime
 
         # current thread
         if include_thread:
         dt = dt + time_str
         # dt = time_str       # logger already shows datetime
 
         # current thread
         if include_thread:
-            thread_name = 'th:{}'.format(threading.current_thread().getName())
+            thread_name = "th:{}".format(threading.current_thread().getName())
         else:
         else:
-            thread_name = ''
+            thread_name = ""
 
         # current coroutine
 
 
         # current coroutine
 
-        coroutine_id = ''
+        coroutine_id = ""
         if include_coroutine:
             try:
                 if asyncio.Task.current_task() is not None:
         if include_coroutine:
             try:
                 if asyncio.Task.current_task() is not None:
+
                     def print_cor_name(c):
                         import inspect
                     def print_cor_name(c):
                         import inspect
+
                         try:
                             for m in inspect.getmembers(c):
                         try:
                             for m in inspect.getmembers(c):
-                                if m[0] == '__name__':
+                                if m[0] == "__name__":
                                     return m[1]
                         except Exception:
                             pass
                                     return m[1]
                         except Exception:
                             pass
+
                     coro = asyncio.Task.current_task()._coro
                     coro = asyncio.Task.current_task()._coro
-                    coroutine_id = 'coro-{} {}()'.format(hex(id(coro))[2:], print_cor_name(coro))
+                    coroutine_id = "coro-{} {}()".format(
+                        hex(id(coro))[2:], print_cor_name(coro)
+                    )
             except Exception:
             except Exception:
-                coroutine_id = ''
+                coroutine_id = ""
 
         # classname
         if obj is not None:
             obj_type = obj.__class__.__name__  # type: str
 
         # classname
         if obj is not None:
             obj_type = obj.__class__.__name__  # type: str
-            log_msg = \
-                '{} {} {} {} {}::{}.{}():{}\n{}'\
-                .format(self._prefix, dt, thread_name, coroutine_id, filename, obj_type, func, lineno, str(msg))
+            log_msg = "{} {} {} {} {}::{}.{}():{}\n{}".format(
+                self._prefix,
+                dt,
+                thread_name,
+                coroutine_id,
+                filename,
+                obj_type,
+                func,
+                lineno,
+                str(msg),
+            )
         else:
         else:
-            log_msg = \
-                '{} {} {} {} {}::{}():{}\n{}'\
-                .format(self._prefix, dt, thread_name, coroutine_id, filename, func, lineno, str(msg))
+            log_msg = "{} {} {} {} {}::{}():{}\n{}".format(
+                self._prefix,
+                dt,
+                thread_name,
+                coroutine_id,
+                filename,
+                func,
+                lineno,
+                str(msg),
+            )
 
         return log_msg
 
         return log_msg
index 6819335..c0bb558 100644 (file)
 
 import abc
 import asyncio
 
 import abc
 import asyncio
+from enum import Enum
+from http import HTTPStatus
 import os
 import os
-import subprocess
 import shlex
 import shlex
+import subprocess
 import time
 import time
-from enum import Enum
-from http import HTTPStatus
-from n2vc.loggable import Loggable
+
 from n2vc.exceptions import N2VCBadArgumentsException
 from n2vc.exceptions import N2VCBadArgumentsException
+from osm_common.dbmongo import DbException
 import yaml
 
 import yaml
 
-from osm_common.dbmongo import DbException
+from n2vc.loggable import Loggable
 
 
 class N2VCDeploymentStatus(Enum):
 
 
 class N2VCDeploymentStatus(Enum):
-    PENDING = 'pending'
-    RUNNING = 'running'
-    COMPLETED = 'completed'
-    FAILED = 'failed'
-    UNKNOWN = 'unknown'
+    PENDING = "pending"
+    RUNNING = "running"
+    COMPLETED = "completed"
+    FAILED = "failed"
+    UNKNOWN = "unknown"
 
 
 class N2VCConnector(abc.ABC, Loggable):
 
 
 class N2VCConnector(abc.ABC, Loggable):
@@ -51,35 +52,39 @@ class N2VCConnector(abc.ABC, Loggable):
     """
 
     """
     """
 
     """
-    ##################################################################################################
-    ########################################## P U B L I C ###########################################
-    ##################################################################################################
+    ####################################################################################
+    ################################### P U B L I C ####################################
+    ####################################################################################
     """
 
     def __init__(
     """
 
     def __init__(
-            self,
-            db: object,
-            fs: object,
-            log: object,
-            loop: object,
-            url: str,
-            username: str,
-            vca_config: dict,
-            on_update_db=None
+        self,
+        db: object,
+        fs: object,
+        log: object,
+        loop: object,
+        url: str,
+        username: str,
+        vca_config: dict,
+        on_update_db=None,
     ):
         """Initialize N2VC abstract connector. It defines de API for VCA connectors
 
         :param object db: Mongo object managing the MongoDB (repo common DbBase)
     ):
         """Initialize N2VC abstract connector. It defines de API for VCA connectors
 
         :param object db: Mongo object managing the MongoDB (repo common DbBase)
-        :param object fs: FileSystem object managing the package artifacts (repo common FsBase)
+        :param object fs: FileSystem object managing the package artifacts (repo common
+            FsBase)
         :param object log: the logging object to log to
         :param object loop: the loop to use for asyncio (default current thread loop)
         :param object log: the logging object to log to
         :param object loop: the loop to use for asyncio (default current thread loop)
-        :param str url: a string that how to connect to the VCA (if needed, IP and port can be obtained from there)
+        :param str url: a string that how to connect to the VCA (if needed, IP and port
+            can be obtained from there)
         :param str username: the username to authenticate with VCA
         :param str username: the username to authenticate with VCA
-        :param dict vca_config: Additional parameters for the specific VCA. For example, for juju it will contain:
+        :param dict vca_config: Additional parameters for the specific VCA. For example,
+            for juju it will contain:
             secret: The password to authenticate with
             public_key: The contents of the juju public SSH key
             ca_cert str: The CA certificate used to authenticate
             secret: The password to authenticate with
             public_key: The contents of the juju public SSH key
             ca_cert str: The CA certificate used to authenticate
-        :param on_update_db: callback called when n2vc connector updates database. Received arguments:
+        :param on_update_db: callback called when n2vc connector updates database.
+            Received arguments:
             table: e.g. "nsrs"
             filter: e.g. {_id: <nsd-id> }
             path: e.g. "_admin.deployed.VCA.3."
             table: e.g. "nsrs"
             filter: e.g. {_id: <nsd-id> }
             path: e.g. "_admin.deployed.VCA.3."
@@ -87,17 +92,26 @@ class N2VCConnector(abc.ABC, Loggable):
         """
 
         # parent class
         """
 
         # parent class
-        Loggable.__init__(self, log=log, log_to_console=True, prefix='\nN2VC')
+        Loggable.__init__(self, log=log, log_to_console=True, prefix="\nN2VC")
 
         # check arguments
         if db is None:
 
         # check arguments
         if db is None:
-            raise N2VCBadArgumentsException('Argument db is mandatory', ['db'])
+            raise N2VCBadArgumentsException("Argument db is mandatory", ["db"])
         if fs is None:
         if fs is None:
-            raise N2VCBadArgumentsException('Argument fs is mandatory', ['fs'])
-
-        self.log.info('url={}, username={}, vca_config={}'.format(
-            url, username, {k: v for k, v in vca_config.items() if k not in ("host", "port", "user", "secret",
-                                                                             "public_key", "ca_cert")}))
+            raise N2VCBadArgumentsException("Argument fs is mandatory", ["fs"])
+
+        self.log.info(
+            "url={}, username={}, vca_config={}".format(
+                url,
+                username,
+                {
+                    k: v
+                    for k, v in vca_config.items()
+                    if k
+                    not in ("host", "port", "user", "secret", "public_key", "ca_cert")
+                },
+            )
+        )
 
         # store arguments into self
         self.db = db
 
         # store arguments into self
         self.db = db
@@ -125,21 +139,19 @@ class N2VCConnector(abc.ABC, Loggable):
     def get_public_key(self) -> str:
         """Get the VCA ssh-public-key
 
     def get_public_key(self) -> str:
         """Get the VCA ssh-public-key
 
-        Returns the SSH public key from local mahine, to be injected into virtual machines to
-        be managed by the VCA.
+        Returns the SSH public key from local mahine, to be injected into virtual
+        machines to be managed by the VCA.
         First run, a ssh keypair will be created.
         The public key is injected into a VM so that we can provision the
         First run, a ssh keypair will be created.
         The public key is injected into a VM so that we can provision the
-        machine with Juju, after which Juju will communicate with the VM 
+        machine with Juju, after which Juju will communicate with the VM
         directly via the juju agent.
         """
 
         directly via the juju agent.
         """
 
-        public_key = ''
-
         # Find the path where we expect our key lives (~/.ssh)
         # Find the path where we expect our key lives (~/.ssh)
-        homedir = os.environ.get('HOME')
+        homedir = os.environ.get("HOME")
         if not homedir:
         if not homedir:
-            self.warning('No HOME environment variable, using /tmp')
-            homedir = '/tmp'
+            self.warning("No HOME environment variable, using /tmp")
+            homedir = "/tmp"
         sshdir = "{}/.ssh".format(homedir)
         if not os.path.exists(sshdir):
             os.mkdir(sshdir)
         sshdir = "{}/.ssh".format(homedir)
         if not os.path.exists(sshdir):
             os.mkdir(sshdir)
@@ -150,9 +162,7 @@ class N2VCConnector(abc.ABC, Loggable):
         # If we don't have a key generated, then we have to generate it using ssh-keygen
         if not os.path.exists(self.private_key_path):
             cmd = "ssh-keygen -t {} -b {} -N '' -f {}".format(
         # If we don't have a key generated, then we have to generate it using ssh-keygen
         if not os.path.exists(self.private_key_path):
             cmd = "ssh-keygen -t {} -b {} -N '' -f {}".format(
-                "rsa",
-                "4096",
-                self.private_key_path
+                "rsa", "4096", self.private_key_path
             )
             # run command with arguments
             subprocess.check_output(shlex.split(cmd))
             )
             # run command with arguments
             subprocess.check_output(shlex.split(cmd))
@@ -170,20 +180,24 @@ class N2VCConnector(abc.ABC, Loggable):
         db_dict: dict,
         reuse_ee_id: str = None,
         progress_timeout: float = None,
         db_dict: dict,
         reuse_ee_id: str = None,
         progress_timeout: float = None,
-        total_timeout: float = None
+        total_timeout: float = None,
     ) -> (str, dict):
     ) -> (str, dict):
-        """Create an Execution Environment. Returns when it is created or raises an exception on failing
+        """Create an Execution Environment. Returns when it is created or raises an
+        exception on failing
 
         :param str namespace: Contains a dot separate string.
                     LCM will use: [<nsi-id>].<ns-id>.<vnf-id>.<vdu-id>[-<count>]
         :param dict db_dict: where to write to database when the status changes.
             It contains a dictionary with {collection: str, filter: {},  path: str},
 
         :param str namespace: Contains a dot separate string.
                     LCM will use: [<nsi-id>].<ns-id>.<vnf-id>.<vdu-id>[-<count>]
         :param dict db_dict: where to write to database when the status changes.
             It contains a dictionary with {collection: str, filter: {},  path: str},
-                e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
-        :param str reuse_ee_id: ee id from an older execution. It allows us to reuse an older environment
+                e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path:
+                "_admin.deployed.VCA.3"}
+        :param str reuse_ee_id: ee id from an older execution. It allows us to reuse an
+            older environment
         :param float progress_timeout:
         :param float total_timeout:
         :returns str, dict: id of the new execution environment and credentials for it
         :param float progress_timeout:
         :param float total_timeout:
         :returns str, dict: id of the new execution environment and credentials for it
-                    (credentials can contains hostname, username, etc depending on underlying cloud)
+                    (credentials can contains hostname, username, etc depending on
+                    underlying cloud)
         """
 
     @abc.abstractmethod
         """
 
     @abc.abstractmethod
@@ -193,17 +207,20 @@ class N2VCConnector(abc.ABC, Loggable):
         credentials: dict,
         db_dict: dict,
         progress_timeout: float = None,
         credentials: dict,
         db_dict: dict,
         progress_timeout: float = None,
-        total_timeout: float = None
+        total_timeout: float = None,
     ) -> str:
         """
         Register an existing execution environment at the VCA
 
         :param str namespace: same as create_execution_environment method
     ) -> str:
         """
         Register an existing execution environment at the VCA
 
         :param str namespace: same as create_execution_environment method
-        :param dict credentials: credentials to access the existing execution environment
-                    (it can contains hostname, username, path to private key, etc depending on underlying cloud)
+        :param dict credentials: credentials to access the existing execution
+            environment
+            (it can contains hostname, username, path to private key, etc depending on
+            underlying cloud)
         :param dict db_dict: where to write to database when the status changes.
             It contains a dictionary with {collection: str, filter: {},  path: str},
         :param dict db_dict: where to write to database when the status changes.
             It contains a dictionary with {collection: str, filter: {},  path: str},
-                e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
+                e.g. {collection: "nsrs", filter:
+                    {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
         :param float progress_timeout:
         :param float total_timeout:
         :returns str: id of the execution environment
         :param float progress_timeout:
         :param float total_timeout:
         :returns str: id of the execution environment
@@ -216,19 +233,22 @@ class N2VCConnector(abc.ABC, Loggable):
         artifact_path: str,
         db_dict: dict,
         progress_timeout: float = None,
         artifact_path: str,
         db_dict: dict,
         progress_timeout: float = None,
-        total_timeout: float = None
+        total_timeout: float = None,
     ):
         """
         Install the software inside the execution environment identified by ee_id
 
     ):
         """
         Install the software inside the execution environment identified by ee_id
 
-        :param str ee_id: the id of the execution environment returned by create_execution_environment
-                        or register_execution_environment
-        :param str artifact_path: where to locate the artifacts (parent folder) using the self.fs
-            the final artifact path will be a combination of this artifact_path and additional string from
-            the config_dict (e.g. charm name)
+        :param str ee_id: the id of the execution environment returned by
+            create_execution_environment or register_execution_environment
+        :param str artifact_path: where to locate the artifacts (parent folder) using
+            the self.fs
+            the final artifact path will be a combination of this artifact_path and
+            additional string from the config_dict (e.g. charm name)
         :param dict db_dict: where to write into database when the status changes.
         :param dict db_dict: where to write into database when the status changes.
-                        It contains a dict with {collection: <str>, filter: {},  path: <str>},
-                            e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
+                        It contains a dict with
+                            {collection: <str>, filter: {},  path: <str>},
+                            e.g. {collection: "nsrs", filter:
+                                {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
         :param float progress_timeout:
         :param float total_timeout:
         """
         :param float progress_timeout:
         :param float total_timeout:
         """
@@ -239,34 +259,34 @@ class N2VCConnector(abc.ABC, Loggable):
         ee_id: str,
         db_dict: dict,
         progress_timeout: float = None,
         ee_id: str,
         db_dict: dict,
         progress_timeout: float = None,
-        total_timeout: float = None
+        total_timeout: float = None,
     ) -> str:
         """
     ) -> str:
         """
-        Generate a priv/pub key pair in the execution environment and return the public key
+        Generate a priv/pub key pair in the execution environment and return the public
+        key
 
 
-        :param str ee_id: the id of the execution environment returned by create_execution_environment
-                        or register_execution_environment
+        :param str ee_id: the id of the execution environment returned by
+            create_execution_environment or register_execution_environment
         :param dict db_dict: where to write into database when the status changes.
         :param dict db_dict: where to write into database when the status changes.
-                        It contains a dict with {collection: <str>, filter: {},  path: <str>},
-                            e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
+                        It contains a dict with
+                            {collection: <str>, filter: {},  path: <str>},
+                            e.g. {collection: "nsrs", filter:
+                                {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
         :param float progress_timeout:
         :param float total_timeout:
         :returns: public key of the execution environment
         :param float progress_timeout:
         :param float total_timeout:
         :returns: public key of the execution environment
-                    For the case of juju proxy charm ssh-layered, it is the one returned by 'get-ssh-public-key'
-                    primitive.
+                    For the case of juju proxy charm ssh-layered, it is the one
+                    returned by 'get-ssh-public-key' primitive.
                     It raises a N2VC exception if fails
         """
 
     @abc.abstractmethod
     async def add_relation(
                     It raises a N2VC exception if fails
         """
 
     @abc.abstractmethod
     async def add_relation(
-        self,
-        ee_id_1: str,
-        ee_id_2: str,
-        endpoint_1: str,
-        endpoint_2: str
+        self, ee_id_1: str, ee_id_2: str, endpoint_1: str, endpoint_2: str
     ):
         """
     ):
         """
-        Add a relation between two Execution Environments (using their associated endpoints).
+        Add a relation between two Execution Environments (using their associated
+        endpoints).
 
         :param str ee_id_1: The id of the first execution environment
         :param str ee_id_2: The id of the second execution environment
 
         :param str ee_id_1: The id of the first execution environment
         :param str ee_id_2: The id of the second execution environment
@@ -276,49 +296,43 @@ class N2VCConnector(abc.ABC, Loggable):
 
     # TODO
     @abc.abstractmethod
 
     # TODO
     @abc.abstractmethod
-    async def remove_relation(
-        self
-    ):
+    async def remove_relation(self):
         """
         """
 
     # TODO
     @abc.abstractmethod
         """
         """
 
     # TODO
     @abc.abstractmethod
-    async def deregister_execution_environments(
-        self
-    ):
+    async def deregister_execution_environments(self):
         """
         """
 
     @abc.abstractmethod
     async def delete_namespace(
         """
         """
 
     @abc.abstractmethod
     async def delete_namespace(
-        self,
-        namespace: str,
-        db_dict: dict = None,
-        total_timeout: float = None
+        self, namespace: str, db_dict: dict = None, total_timeout: float = None
     ):
         """
         Remove a network scenario and its execution environments
         :param namespace: [<nsi-id>].<ns-id>
         :param dict db_dict: where to write into database when the status changes.
     ):
         """
         Remove a network scenario and its execution environments
         :param namespace: [<nsi-id>].<ns-id>
         :param dict db_dict: where to write into database when the status changes.
-                        It contains a dict with {collection: <str>, filter: {},  path: <str>},
-                            e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
+                        It contains a dict with
+                            {collection: <str>, filter: {},  path: <str>},
+                            e.g. {collection: "nsrs", filter:
+                                {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
         :param float total_timeout:
         """
 
     @abc.abstractmethod
     async def delete_execution_environment(
         :param float total_timeout:
         """
 
     @abc.abstractmethod
     async def delete_execution_environment(
-        self,
-        ee_id: str,
-        db_dict: dict = None,
-        total_timeout: float = None
+        self, ee_id: str, db_dict: dict = None, total_timeout: float = None
     ):
         """
         Delete an execution environment
         :param str ee_id: id of the execution environment to delete
         :param dict db_dict: where to write into database when the status changes.
     ):
         """
         Delete an execution environment
         :param str ee_id: id of the execution environment to delete
         :param dict db_dict: where to write into database when the status changes.
-                        It contains a dict with {collection: <str>, filter: {},  path: <str>},
-                            e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
+                        It contains a dict with
+                            {collection: <str>, filter: {},  path: <str>},
+                            e.g. {collection: "nsrs", filter:
+                                {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
         :param float total_timeout:
         """
 
         :param float total_timeout:
         """
 
@@ -330,18 +344,22 @@ class N2VCConnector(abc.ABC, Loggable):
         params_dict: dict,
         db_dict: dict = None,
         progress_timeout: float = None,
         params_dict: dict,
         db_dict: dict = None,
         progress_timeout: float = None,
-        total_timeout: float = None
+        total_timeout: float = None,
     ) -> str:
         """
         Execute a primitive in the execution environment
 
     ) -> str:
         """
         Execute a primitive in the execution environment
 
-        :param str ee_id: the one returned by create_execution_environment or register_execution_environment
-        :param str primitive_name: must be one defined in the software. There is one called 'config',
-            where, for the proxy case, the 'credentials' of VM are provided
+        :param str ee_id: the one returned by create_execution_environment or
+            register_execution_environment
+        :param str primitive_name: must be one defined in the software. There is one
+            called 'config', where, for the proxy case, the 'credentials' of VM are
+            provided
         :param dict params_dict: parameters of the action
         :param dict db_dict: where to write into database when the status changes.
         :param dict params_dict: parameters of the action
         :param dict db_dict: where to write into database when the status changes.
-                        It contains a dict with {collection: <str>, filter: {},  path: <str>},
-                            e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
+                        It contains a dict with
+                            {collection: <str>, filter: {},  path: <str>},
+                            e.g. {collection: "nsrs", filter:
+                                {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
         :param float progress_timeout:
         :param float total_timeout:
         :returns str: primitive result, if ok. It raises exceptions in case of fail
         :param float progress_timeout:
         :param float total_timeout:
         :returns str: primitive result, if ok. It raises exceptions in case of fail
@@ -353,9 +371,9 @@ class N2VCConnector(abc.ABC, Loggable):
         """
 
     """
         """
 
     """
-    ##################################################################################################
-    ########################################## P R I V A T E #########################################
-    ##################################################################################################
+    ####################################################################################
+    ################################### P R I V A T E ##################################
+    ####################################################################################
     """
 
     def _get_namespace_components(self, namespace: str) -> (str, str, str, str, str):
     """
 
     def _get_namespace_components(self, namespace: str) -> (str, str, str, str, str):
@@ -368,10 +386,12 @@ class N2VCConnector(abc.ABC, Loggable):
 
         # check parameters
         if namespace is None or len(namespace) == 0:
 
         # check parameters
         if namespace is None or len(namespace) == 0:
-            raise N2VCBadArgumentsException('Argument namespace is mandatory', ['namespace'])
+            raise N2VCBadArgumentsException(
+                "Argument namespace is mandatory", ["namespace"]
+            )
 
         # split namespace components
 
         # split namespace components
-        parts = namespace.split('.')
+        parts = namespace.split(".")
         nsi_id = None
         ns_id = None
         vnf_id = None
         nsi_id = None
         ns_id = None
         vnf_id = None
@@ -385,7 +405,7 @@ class N2VCConnector(abc.ABC, Loggable):
             vnf_id = parts[2]
         if len(parts) > 3 and len(parts[3]) > 0:
             vdu_id = parts[3]
             vnf_id = parts[2]
         if len(parts) > 3 and len(parts[3]) > 0:
             vdu_id = parts[3]
-            vdu_parts = parts[3].split('-')
+            vdu_parts = parts[3].split("-")
             if len(vdu_parts) > 1:
                 vdu_id = vdu_parts[0]
                 vdu_count = vdu_parts[1]
             if len(vdu_parts) > 1:
                 vdu_id = vdu_parts[0]
                 vdu_count = vdu_parts[1]
@@ -393,79 +413,85 @@ class N2VCConnector(abc.ABC, Loggable):
         return nsi_id, ns_id, vnf_id, vdu_id, vdu_count
 
     async def write_app_status_to_db(
         return nsi_id, ns_id, vnf_id, vdu_id, vdu_count
 
     async def write_app_status_to_db(
-            self,
-            db_dict: dict,
-            status: N2VCDeploymentStatus,
-            detailed_status: str,
-            vca_status: str,
-            entity_type: str
+        self,
+        db_dict: dict,
+        status: N2VCDeploymentStatus,
+        detailed_status: str,
+        vca_status: str,
+        entity_type: str,
     ):
         if not db_dict:
     ):
         if not db_dict:
-            self.log.debug('No db_dict => No database write')
+            self.log.debug("No db_dict => No database write")
             return
 
             return
 
-        # self.log.debug('status={} / detailed-status={} / VCA-status={} / entity_type={}'
-        #            .format(str(status.value), detailed_status, vca_status, entity_type))
+        # self.log.debug('status={} / detailed-status={} / VCA-status={}/entity_type={}'
+        #          .format(str(status.value), detailed_status, vca_status, entity_type))
 
         try:
 
 
         try:
 
-            the_table = db_dict['collection']
-            the_filter = db_dict['filter']
-            the_path = db_dict['path']
-            if not the_path[-1] == '.':
-                the_path = the_path + '.'
+            the_table = db_dict["collection"]
+            the_filter = db_dict["filter"]
+            the_path = db_dict["path"]
+            if not the_path[-1] == ".":
+                the_path = the_path + "."
             update_dict = {
             update_dict = {
-                the_path + 'status': str(status.value),
-                the_path + 'detailed-status': detailed_status,
-                the_path + 'VCA-status': vca_status,
-                the_path + 'entity-type': entity_type,
-                the_path + 'status-time': str(time.time()),
+                the_path + "status": str(status.value),
+                the_path + "detailed-status": detailed_status,
+                the_path + "VCA-status": vca_status,
+                the_path + "entity-type": entity_type,
+                the_path + "status-time": str(time.time()),
             }
 
             self.db.set_one(
                 table=the_table,
                 q_filter=the_filter,
                 update_dict=update_dict,
             }
 
             self.db.set_one(
                 table=the_table,
                 q_filter=the_filter,
                 update_dict=update_dict,
-                fail_on_empty=True
+                fail_on_empty=True,
             )
 
             # database callback
             if self.on_update_db:
                 if asyncio.iscoroutinefunction(self.on_update_db):
             )
 
             # database callback
             if self.on_update_db:
                 if asyncio.iscoroutinefunction(self.on_update_db):
-                    await self.on_update_db(the_table, the_filter, the_path, update_dict)
+                    await self.on_update_db(
+                        the_table, the_filter, the_path, update_dict
+                    )
                 else:
                     self.on_update_db(the_table, the_filter, the_path, update_dict)
 
         except DbException as e:
             if e.http_code == HTTPStatus.NOT_FOUND:
                 else:
                     self.on_update_db(the_table, the_filter, the_path, update_dict)
 
         except DbException as e:
             if e.http_code == HTTPStatus.NOT_FOUND:
-                self.log.error('NOT_FOUND error: Exception writing status to database: {}'.format(e))
+                self.log.error(
+                    "NOT_FOUND error: Exception writing status to database: {}".format(
+                        e
+                    )
+                )
             else:
             else:
-                self.log.info('Exception writing status to database: {}'.format(e))
+                self.log.info("Exception writing status to database: {}".format(e))
 
 
 
 
-def juju_status_2_osm_status(type: str, status: str) -> N2VCDeploymentStatus:
-    if type == 'application' or type == 'unit':
-        if status in ['waiting', 'maintenance']:
+def juju_status_2_osm_status(statustype: str, status: str) -> N2VCDeploymentStatus:
+    if statustype == "application" or statustype == "unit":
+        if status in ["waiting", "maintenance"]:
             return N2VCDeploymentStatus.RUNNING
             return N2VCDeploymentStatus.RUNNING
-        if status in ['error']:
-                return N2VCDeploymentStatus.FAILED
-        elif status in ['active']:
+        if status in ["error"]:
+            return N2VCDeploymentStatus.FAILED
+        elif status in ["active"]:
             return N2VCDeploymentStatus.COMPLETED
             return N2VCDeploymentStatus.COMPLETED
-        elif status in ['blocked']:
+        elif status in ["blocked"]:
             return N2VCDeploymentStatus.RUNNING
         else:
             return N2VCDeploymentStatus.UNKNOWN
             return N2VCDeploymentStatus.RUNNING
         else:
             return N2VCDeploymentStatus.UNKNOWN
-    elif type == 'action':
-        if status in ['running']:
+    elif statustype == "action":
+        if status in ["running"]:
             return N2VCDeploymentStatus.RUNNING
             return N2VCDeploymentStatus.RUNNING
-        elif status in ['completed']:
+        elif status in ["completed"]:
             return N2VCDeploymentStatus.COMPLETED
         else:
             return N2VCDeploymentStatus.UNKNOWN
             return N2VCDeploymentStatus.COMPLETED
         else:
             return N2VCDeploymentStatus.UNKNOWN
-    elif type == 'machine':
-        if status in ['pending']:
+    elif statustype == "machine":
+        if status in ["pending"]:
             return N2VCDeploymentStatus.PENDING
             return N2VCDeploymentStatus.PENDING
-        elif status in ['started']:
+        elif status in ["started"]:
             return N2VCDeploymentStatus.COMPLETED
         else:
             return N2VCDeploymentStatus.UNKNOWN
             return N2VCDeploymentStatus.COMPLETED
         else:
             return N2VCDeploymentStatus.UNKNOWN
@@ -479,12 +505,12 @@ def obj_to_yaml(obj: object) -> str:
     # split lines
     lines = dump_text.splitlines()
     # remove !!python/object tags
     # split lines
     lines = dump_text.splitlines()
     # remove !!python/object tags
-    yaml_text = ''
+    yaml_text = ""
     for line in lines:
     for line in lines:
-        index = line.find('!!python/object')
+        index = line.find("!!python/object")
         if index >= 0:
             line = line[:index]
         if index >= 0:
             line = line[:index]
-        yaml_text += line + '\n'
+        yaml_text += line + "\n"
     return yaml_text
 
 
     return yaml_text
 
 
index f48838d..0696e20 100644 (file)
 # contact with: nfvlabs@tid.es
 ##
 
 # contact with: nfvlabs@tid.es
 ##
 
-import logging
-import os
 import asyncio
 import asyncio
-import time
 import base64
 import binascii
 import base64
 import binascii
+import logging
+import os
 import re
 import re
+import time
 
 
-from n2vc.n2vc_conn import N2VCConnector
-from n2vc.n2vc_conn import obj_to_dict, obj_to_yaml
-from n2vc.exceptions \
-    import N2VCBadArgumentsException, N2VCException, N2VCConnectionException, \
-    N2VCExecutionException, N2VCInvalidCertificate, N2VCNotFound
-from n2vc.juju_observer import JujuModelObserver
-
-from juju.controller import Controller
-from juju.model import Model
-from juju.application import Application
 from juju.action import Action
 from juju.action import Action
-from juju.machine import Machine
+from juju.application import Application
 from juju.client import client
 from juju.client import client
+from juju.controller import Controller
 from juju.errors import JujuAPIError
 from juju.errors import JujuAPIError
-
+from juju.machine import Machine
+from juju.model import Model
+from n2vc.exceptions import (
+    N2VCBadArgumentsException,
+    N2VCException,
+    N2VCConnectionException,
+    N2VCExecutionException,
+    N2VCInvalidCertificate,
+    N2VCNotFound,
+    MethodNotImplemented,
+)
+from n2vc.juju_observer import JujuModelObserver
+from n2vc.n2vc_conn import N2VCConnector
+from n2vc.n2vc_conn import obj_to_dict, obj_to_yaml
 from n2vc.provisioner import SSHProvisioner
 
 
 class N2VCJujuConnector(N2VCConnector):
 
     """
 from n2vc.provisioner import SSHProvisioner
 
 
 class N2VCJujuConnector(N2VCConnector):
 
     """
-    ##################################################################################################
-    ########################################## P U B L I C ###########################################
-    ##################################################################################################
+    ####################################################################################
+    ################################### P U B L I C ####################################
+    ####################################################################################
     """
 
     BUILT_IN_CLOUDS = ["localhost", "microk8s"]
     """
 
     BUILT_IN_CLOUDS = ["localhost", "microk8s"]
@@ -62,10 +66,10 @@ class N2VCJujuConnector(N2VCConnector):
         fs: object,
         log: object = None,
         loop: object = None,
         fs: object,
         log: object = None,
         loop: object = None,
-        url: str = '127.0.0.1:17070',
-        username: str = 'admin',
+        url: str = "127.0.0.1:17070",
+        username: str = "admin",
         vca_config: dict = None,
         vca_config: dict = None,
-        on_update_db=None
+        on_update_db=None,
     ):
         """Initialize juju N2VC connector
         """
     ):
         """Initialize juju N2VC connector
         """
@@ -80,15 +84,15 @@ class N2VCJujuConnector(N2VCConnector):
             url=url,
             username=username,
             vca_config=vca_config,
             url=url,
             username=username,
             vca_config=vca_config,
-            on_update_db=on_update_db
+            on_update_db=on_update_db,
         )
 
         # silence websocket traffic log
         )
 
         # silence websocket traffic log
-        logging.getLogger('websockets.protocol').setLevel(logging.INFO)
-        logging.getLogger('juju.client.connection').setLevel(logging.WARN)
-        logging.getLogger('model').setLevel(logging.WARN)
+        logging.getLogger("websockets.protocol").setLevel(logging.INFO)
+        logging.getLogger("juju.client.connection").setLevel(logging.WARN)
+        logging.getLogger("model").setLevel(logging.WARN)
 
 
-        self.log.info('Initializing N2VC juju connector...')
+        self.log.info("Initializing N2VC juju connector...")
 
         """
         ##############################################################
 
         """
         ##############################################################
@@ -98,33 +102,43 @@ class N2VCJujuConnector(N2VCConnector):
 
         # juju URL
         if url is None:
 
         # juju URL
         if url is None:
-            raise N2VCBadArgumentsException('Argument url is mandatory', ['url'])
-        url_parts = url.split(':')
+            raise N2VCBadArgumentsException("Argument url is mandatory", ["url"])
+        url_parts = url.split(":")
         if len(url_parts) != 2:
         if len(url_parts) != 2:
-            raise N2VCBadArgumentsException('Argument url: bad format (localhost:port) -> {}'.format(url), ['url'])
+            raise N2VCBadArgumentsException(
+                "Argument url: bad format (localhost:port) -> {}".format(url), ["url"]
+            )
         self.hostname = url_parts[0]
         try:
             self.port = int(url_parts[1])
         except ValueError:
         self.hostname = url_parts[0]
         try:
             self.port = int(url_parts[1])
         except ValueError:
-            raise N2VCBadArgumentsException('url port must be a number -> {}'.format(url), ['url'])
+            raise N2VCBadArgumentsException(
+                "url port must be a number -> {}".format(url), ["url"]
+            )
 
         # juju USERNAME
         if username is None:
 
         # juju USERNAME
         if username is None:
-            raise N2VCBadArgumentsException('Argument username is mandatory', ['username'])
+            raise N2VCBadArgumentsException(
+                "Argument username is mandatory", ["username"]
+            )
 
         # juju CONFIGURATION
         if vca_config is None:
 
         # juju CONFIGURATION
         if vca_config is None:
-            raise N2VCBadArgumentsException('Argument vca_config is mandatory', ['vca_config'])
+            raise N2VCBadArgumentsException(
+                "Argument vca_config is mandatory", ["vca_config"]
+            )
 
 
-        if 'secret' in vca_config:
-            self.secret = vca_config['secret']
+        if "secret" in vca_config:
+            self.secret = vca_config["secret"]
         else:
         else:
-            raise N2VCBadArgumentsException('Argument vca_config.secret is mandatory', ['vca_config.secret'])
+            raise N2VCBadArgumentsException(
+                "Argument vca_config.secret is mandatory", ["vca_config.secret"]
+            )
 
         # pubkey of juju client in osm machine: ~/.local/share/juju/ssh/juju_id_rsa.pub
         # if exists, it will be written in lcm container: _create_juju_public_key()
 
         # pubkey of juju client in osm machine: ~/.local/share/juju/ssh/juju_id_rsa.pub
         # if exists, it will be written in lcm container: _create_juju_public_key()
-        if 'public_key' in vca_config:
-            self.public_key = vca_config['public_key']
+        if "public_key" in vca_config:
+            self.public_key = vca_config["public_key"]
         else:
             self.public_key = None
 
         else:
             self.public_key = None
 
@@ -139,52 +153,57 @@ class N2VCJujuConnector(N2VCConnector):
             try:
                 cacert = base64.b64decode(b64string).decode("utf-8")
 
             try:
                 cacert = base64.b64decode(b64string).decode("utf-8")
 
-                cacert = re.sub(
-                    r'\\n',
-                    r'\n',
-                    cacert,
-                )
+                cacert = re.sub(r"\\n", r"\n", cacert,)
             except binascii.Error as e:
                 self.log.debug("Caught binascii.Error: {}".format(e))
                 raise N2VCInvalidCertificate(message="Invalid CA Certificate")
 
             return cacert
 
             except binascii.Error as e:
                 self.log.debug("Caught binascii.Error: {}".format(e))
                 raise N2VCInvalidCertificate(message="Invalid CA Certificate")
 
             return cacert
 
-        self.ca_cert = vca_config.get('ca_cert')
+        self.ca_cert = vca_config.get("ca_cert")
         if self.ca_cert:
         if self.ca_cert:
-            self.ca_cert = base64_to_cacert(vca_config['ca_cert'])
+            self.ca_cert = base64_to_cacert(vca_config["ca_cert"])
 
 
-        if 'api_proxy' in vca_config:
-            self.api_proxy = vca_config['api_proxy']
-            self.log.debug('api_proxy for native charms configured: {}'.format(self.api_proxy))
+        if "api_proxy" in vca_config:
+            self.api_proxy = vca_config["api_proxy"]
+            self.log.debug(
+                "api_proxy for native charms configured: {}".format(self.api_proxy)
+            )
         else:
         else:
-            self.warning('api_proxy is not configured. Support for native charms is disabled')
+            self.warning(
+                "api_proxy is not configured. Support for native charms is disabled"
+            )
 
 
-        if 'enable_os_upgrade' in vca_config:
-            self.enable_os_upgrade = vca_config['enable_os_upgrade']
+        if "enable_os_upgrade" in vca_config:
+            self.enable_os_upgrade = vca_config["enable_os_upgrade"]
         else:
             self.enable_os_upgrade = True
 
         else:
             self.enable_os_upgrade = True
 
-        if 'apt_mirror' in vca_config:
-            self.apt_mirror = vca_config['apt_mirror']
+        if "apt_mirror" in vca_config:
+            self.apt_mirror = vca_config["apt_mirror"]
         else:
             self.apt_mirror = None
 
         else:
             self.apt_mirror = None
 
-        self.cloud = vca_config.get('cloud')
+        self.cloud = vca_config.get("cloud")
         # self.log.debug('Arguments have been checked')
 
         # juju data
         # self.log.debug('Arguments have been checked')
 
         # juju data
-        self.controller = None         # it will be filled when connect to juju
-        self.juju_models = {}          # model objects for every model_name
-        self.juju_observers = {}       # model observers for every model_name
-        self._connecting = False       # while connecting to juju (to avoid duplicate connections)
-        self._authenticated = False    # it will be True when juju connection be stablished
-        self._creating_model = False   # True during model creation
-
-        # create juju pub key file in lcm container at ./local/share/juju/ssh/juju_id_rsa.pub
+        self.controller = None  # it will be filled when connect to juju
+        self.juju_models = {}  # model objects for every model_name
+        self.juju_observers = {}  # model observers for every model_name
+        self._connecting = (
+            False  # while connecting to juju (to avoid duplicate connections)
+        )
+        self._authenticated = (
+            False  # it will be True when juju connection be stablished
+        )
+        self._creating_model = False  # True during model creation
+
+        # create juju pub key file in lcm container at
+        # ./local/share/juju/ssh/juju_id_rsa.pub
         self._create_juju_public_key()
 
         self._create_juju_public_key()
 
-        self.log.info('N2VC juju connector initialized')
+        self.log.info("N2VC juju connector initialized")
 
     async def get_status(self, namespace: str, yaml_format: bool = True):
 
 
     async def get_status(self, namespace: str, yaml_format: bool = True):
 
@@ -193,13 +212,15 @@ class N2VCJujuConnector(N2VCConnector):
         if not self._authenticated:
             await self._juju_login()
 
         if not self._authenticated:
             await self._juju_login()
 
-        nsi_id, ns_id, vnf_id, vdu_id, vdu_count = self._get_namespace_components(namespace=namespace)
+        _nsi_id, ns_id, _vnf_id, _vdu_id, _vdu_count = self._get_namespace_components(
+            namespace=namespace
+        )
         # model name is ns_id
         model_name = ns_id
         if model_name is None:
         # model name is ns_id
         model_name = ns_id
         if model_name is None:
-            msg = 'Namespace {} not valid'.format(namespace)
+            msg = "Namespace {} not valid".format(namespace)
             self.log.error(msg)
             self.log.error(msg)
-            raise N2VCBadArgumentsException(msg, ['namespace'])
+            raise N2VCBadArgumentsException(msg, ["namespace"])
 
         # get juju model (create model if needed)
         model = await self._juju_get_model(model_name=model_name)
 
         # get juju model (create model if needed)
         model = await self._juju_get_model(model_name=model_name)
@@ -217,26 +238,41 @@ class N2VCJujuConnector(N2VCConnector):
         db_dict: dict,
         reuse_ee_id: str = None,
         progress_timeout: float = None,
         db_dict: dict,
         reuse_ee_id: str = None,
         progress_timeout: float = None,
-        total_timeout: float = None
+        total_timeout: float = None,
     ) -> (str, dict):
 
     ) -> (str, dict):
 
-        self.log.info('Creating execution environment. namespace: {}, reuse_ee_id: {}'.format(namespace, reuse_ee_id))
+        self.log.info(
+            "Creating execution environment. namespace: {}, reuse_ee_id: {}".format(
+                namespace, reuse_ee_id
+            )
+        )
 
         if not self._authenticated:
             await self._juju_login()
 
         machine_id = None
         if reuse_ee_id:
 
         if not self._authenticated:
             await self._juju_login()
 
         machine_id = None
         if reuse_ee_id:
-            model_name, application_name, machine_id = self._get_ee_id_components(ee_id=reuse_ee_id)
+            model_name, application_name, machine_id = self._get_ee_id_components(
+                ee_id=reuse_ee_id
+            )
         else:
         else:
-            nsi_id, ns_id, vnf_id, vdu_id, vdu_count = self._get_namespace_components(namespace=namespace)
+            (
+                _nsi_id,
+                ns_id,
+                _vnf_id,
+                _vdu_id,
+                _vdu_count,
+            ) = self._get_namespace_components(namespace=namespace)
             # model name is ns_id
             model_name = ns_id
             # application name
             application_name = self._get_application_name(namespace=namespace)
 
             # model name is ns_id
             model_name = ns_id
             # application name
             application_name = self._get_application_name(namespace=namespace)
 
-        self.log.debug('model name: {}, application name:  {}, machine_id: {}'
-                   .format(model_name, application_name, machine_id))
+        self.log.debug(
+            "model name: {}, application name:  {}, machine_id: {}".format(
+                model_name, application_name, machine_id
+            )
+        )
 
         # create or reuse a new juju machine
         try:
 
         # create or reuse a new juju machine
         try:
@@ -246,10 +282,10 @@ class N2VCJujuConnector(N2VCConnector):
                 machine_id=machine_id,
                 db_dict=db_dict,
                 progress_timeout=progress_timeout,
                 machine_id=machine_id,
                 db_dict=db_dict,
                 progress_timeout=progress_timeout,
-                total_timeout=total_timeout
+                total_timeout=total_timeout,
             )
         except Exception as e:
             )
         except Exception as e:
-            message = 'Error creating machine on juju: {}'.format(e)
+            message = "Error creating machine on juju: {}".format(e)
             self.log.error(message)
             raise N2VCException(message=message)
 
             self.log.error(message)
             raise N2VCException(message=message)
 
@@ -257,15 +293,19 @@ class N2VCJujuConnector(N2VCConnector):
         ee_id = N2VCJujuConnector._build_ee_id(
             model_name=model_name,
             application_name=application_name,
         ee_id = N2VCJujuConnector._build_ee_id(
             model_name=model_name,
             application_name=application_name,
-            machine_id=str(machine.entity_id)
+            machine_id=str(machine.entity_id),
         )
         )
-        self.log.debug('ee_id: {}'.format(ee_id))
+        self.log.debug("ee_id: {}".format(ee_id))
 
         # new machine credentials
         credentials = dict()
 
         # new machine credentials
         credentials = dict()
-        credentials['hostname'] = machine.dns_name
+        credentials["hostname"] = machine.dns_name
 
 
-        self.log.info('Execution environment created. ee_id: {}, credentials: {}'.format(ee_id, credentials))
+        self.log.info(
+            "Execution environment created. ee_id: {}, credentials: {}".format(
+                ee_id, credentials
+            )
+        )
 
         return ee_id, credentials
 
 
         return ee_id, credentials
 
@@ -275,31 +315,43 @@ class N2VCJujuConnector(N2VCConnector):
         credentials: dict,
         db_dict: dict,
         progress_timeout: float = None,
         credentials: dict,
         db_dict: dict,
         progress_timeout: float = None,
-        total_timeout: float = None
+        total_timeout: float = None,
     ) -> str:
 
         if not self._authenticated:
             await self._juju_login()
 
     ) -> str:
 
         if not self._authenticated:
             await self._juju_login()
 
-        self.log.info('Registering execution environment. namespace={}, credentials={}'.format(namespace, credentials))
+        self.log.info(
+            "Registering execution environment. namespace={}, credentials={}".format(
+                namespace, credentials
+            )
+        )
 
         if credentials is None:
 
         if credentials is None:
-            raise N2VCBadArgumentsException(message='credentials are mandatory', bad_args=['credentials'])
-        if credentials.get('hostname'):
-            hostname = credentials['hostname']
+            raise N2VCBadArgumentsException(
+                message="credentials are mandatory", bad_args=["credentials"]
+            )
+        if credentials.get("hostname"):
+            hostname = credentials["hostname"]
         else:
         else:
-            raise N2VCBadArgumentsException(message='hostname is mandatory', bad_args=['credentials.hostname'])
-        if credentials.get('username'):
-            username = credentials['username']
+            raise N2VCBadArgumentsException(
+                message="hostname is mandatory", bad_args=["credentials.hostname"]
+            )
+        if credentials.get("username"):
+            username = credentials["username"]
         else:
         else:
-            raise N2VCBadArgumentsException(message='username is mandatory', bad_args=['credentials.username'])
-        if 'private_key_path' in credentials:
-            private_key_path = credentials['private_key_path']
+            raise N2VCBadArgumentsException(
+                message="username is mandatory", bad_args=["credentials.username"]
+            )
+        if "private_key_path" in credentials:
+            private_key_path = credentials["private_key_path"]
         else:
             # if not passed as argument, use generated private key path
             private_key_path = self.private_key_path
 
         else:
             # if not passed as argument, use generated private key path
             private_key_path = self.private_key_path
 
-        nsi_id, ns_id, vnf_id, vdu_id, vdu_count = self._get_namespace_components(namespace=namespace)
+        _nsi_id, ns_id, _vnf_id, _vdu_id, _vdu_count = self._get_namespace_components(
+            namespace=namespace
+        )
 
         # model name
         model_name = ns_id
 
         # model name
         model_name = ns_id
@@ -315,22 +367,24 @@ class N2VCJujuConnector(N2VCConnector):
                 private_key_path=private_key_path,
                 db_dict=db_dict,
                 progress_timeout=progress_timeout,
                 private_key_path=private_key_path,
                 db_dict=db_dict,
                 progress_timeout=progress_timeout,
-                total_timeout=total_timeout
+                total_timeout=total_timeout,
             )
         except Exception as e:
             )
         except Exception as e:
-            self.log.error('Error registering machine: {}'.format(e))
-            raise N2VCException(message='Error registering machine on juju: {}'.format(e))
+            self.log.error("Error registering machine: {}".format(e))
+            raise N2VCException(
+                message="Error registering machine on juju: {}".format(e)
+            )
 
 
-        self.log.info('Machine registered: {}'.format(machine_id))
+        self.log.info("Machine registered: {}".format(machine_id))
 
         # id for the execution environment
         ee_id = N2VCJujuConnector._build_ee_id(
             model_name=model_name,
             application_name=application_name,
 
         # id for the execution environment
         ee_id = N2VCJujuConnector._build_ee_id(
             model_name=model_name,
             application_name=application_name,
-            machine_id=str(machine_id)
+            machine_id=str(machine_id),
         )
 
         )
 
-        self.log.info('Execution environment registered. ee_id: {}'.format(ee_id))
+        self.log.info("Execution environment registered. ee_id: {}".format(ee_id))
 
         return ee_id
 
 
         return ee_id
 
@@ -344,45 +398,65 @@ class N2VCJujuConnector(N2VCConnector):
         config: dict = None,
     ):
 
         config: dict = None,
     ):
 
-        self.log.info('Installing configuration sw on ee_id: {}, artifact path: {}, db_dict: {}'
-                  .format(ee_id, artifact_path, db_dict))
+        self.log.info(
+            (
+                "Installing configuration sw on ee_id: {}, "
+                "artifact path: {}, db_dict: {}"
+            ).format(ee_id, artifact_path, db_dict)
+        )
 
         if not self._authenticated:
             await self._juju_login()
 
         # check arguments
         if ee_id is None or len(ee_id) == 0:
 
         if not self._authenticated:
             await self._juju_login()
 
         # check arguments
         if ee_id is None or len(ee_id) == 0:
-            raise N2VCBadArgumentsException(message='ee_id is mandatory', bad_args=['ee_id'])
+            raise N2VCBadArgumentsException(
+                message="ee_id is mandatory", bad_args=["ee_id"]
+            )
         if artifact_path is None or len(artifact_path) == 0:
         if artifact_path is None or len(artifact_path) == 0:
-            raise N2VCBadArgumentsException(message='artifact_path is mandatory', bad_args=['artifact_path'])
+            raise N2VCBadArgumentsException(
+                message="artifact_path is mandatory", bad_args=["artifact_path"]
+            )
         if db_dict is None:
         if db_dict is None:
-            raise N2VCBadArgumentsException(message='db_dict is mandatory', bad_args=['db_dict'])
+            raise N2VCBadArgumentsException(
+                message="db_dict is mandatory", bad_args=["db_dict"]
+            )
 
         try:
 
         try:
-            model_name, application_name, machine_id = N2VCJujuConnector._get_ee_id_components(ee_id=ee_id)
-            self.log.debug('model: {}, application: {}, machine: {}'.format(model_name, application_name, machine_id))
-        except Exception as e:
+            (
+                model_name,
+                application_name,
+                machine_id,
+            ) = N2VCJujuConnector._get_ee_id_components(ee_id=ee_id)
+            self.log.debug(
+                "model: {}, application: {}, machine: {}".format(
+                    model_name, application_name, machine_id
+                )
+            )
+        except Exception:
             raise N2VCBadArgumentsException(
             raise N2VCBadArgumentsException(
-                message='ee_id={} is not a valid execution environment id'.format(ee_id),
-                bad_args=['ee_id']
+                message="ee_id={} is not a valid execution environment id".format(
+                    ee_id
+                ),
+                bad_args=["ee_id"],
             )
 
         # remove // in charm path
             )
 
         # remove // in charm path
-        while artifact_path.find('//') >= 0:
-            artifact_path = artifact_path.replace('//', '/')
+        while artifact_path.find("//") >= 0:
+            artifact_path = artifact_path.replace("//", "/")
 
         # check charm path
         if not self.fs.file_exists(artifact_path, mode="dir"):
 
         # check charm path
         if not self.fs.file_exists(artifact_path, mode="dir"):
-            msg = 'artifact path does not exist: {}'.format(artifact_path)
-            raise N2VCBadArgumentsException(message=msg, bad_args=['artifact_path'])
+            msg = "artifact path does not exist: {}".format(artifact_path)
+            raise N2VCBadArgumentsException(message=msg, bad_args=["artifact_path"])
 
 
-        if artifact_path.startswith('/'):
+        if artifact_path.startswith("/"):
             full_path = self.fs.path + artifact_path
         else:
             full_path = self.fs.path + artifact_path
         else:
-            full_path = self.fs.path + '/' + artifact_path
+            full_path = self.fs.path + "/" + artifact_path
 
         try:
 
         try:
-            application, retries = await self._juju_deploy_charm(
+            await self._juju_deploy_charm(
                 model_name=model_name,
                 application_name=application_name,
                 charm_path=full_path,
                 model_name=model_name,
                 application_name=application_name,
                 charm_path=full_path,
@@ -390,39 +464,59 @@ class N2VCJujuConnector(N2VCConnector):
                 db_dict=db_dict,
                 progress_timeout=progress_timeout,
                 total_timeout=total_timeout,
                 db_dict=db_dict,
                 progress_timeout=progress_timeout,
                 total_timeout=total_timeout,
-                config=config
+                config=config,
             )
         except Exception as e:
             )
         except Exception as e:
-            raise N2VCException(message='Error desploying charm into ee={} : {}'.format(ee_id, e))
+            raise N2VCException(
+                message="Error desploying charm into ee={} : {}".format(ee_id, e)
+            )