Destroy machines before destroying the model
[osm/N2VC.git] / n2vc / k8s_juju_conn.py
index 3acc10e..8520687 100644 (file)
@@ -69,6 +69,7 @@ class K8sJujuConnector(K8sConnector):
         self.models = {}
         self.log = logging.getLogger(__name__)
 
         self.models = {}
         self.log = logging.getLogger(__name__)
 
+        self.juju_command = juju_command
         self.juju_secret = ""
 
         self.info('K8S Juju connector initialized')
         self.juju_secret = ""
 
         self.info('K8S Juju connector initialized')
@@ -94,10 +95,6 @@ class K8sJujuConnector(K8sConnector):
         Bootstrapping cannot be done, by design, through the API. We need to
         use the CLI tools.
         """
         Bootstrapping cannot be done, by design, through the API. We need to
         use the CLI tools.
         """
-        # TODO: The path may change
-        jujudir = "/usr/local/bin"
-
-        self.k8scli = "{}/juju".format(jujudir)
 
         """
         WIP: Workflow
 
         """
         WIP: Workflow
@@ -126,32 +123,22 @@ class K8sJujuConnector(K8sConnector):
 
             cluster_uuid = str(uuid.uuid4())
 
 
             cluster_uuid = str(uuid.uuid4())
 
-            # Add k8s cloud to Juju (unless it's microk8s)
-
-            # Convert to a dict
-            # k8s_creds = yaml.safe_load(k8s_creds)
-
-            # Does the kubeconfig contain microk8s?
-            microk8s = self.is_microk8s_by_credentials(k8s_creds)
-
-            if not microk8s:
-                # Name the new k8s cloud
-                k8s_cloud = "{}-k8s".format(namespace)
+            # Is a local k8s cluster?
+            localk8s = self.is_local_k8s(k8s_creds)
 
 
-                print("Adding k8s cloud {}".format(k8s_cloud))
-                await self.add_k8s(k8s_cloud, k8s_creds)
+            # If the k8s is external, the juju controller needs a loadbalancer
+            loadbalancer = False if localk8s else True
 
 
-                # Bootstrap Juju controller
-                print("Bootstrapping...")
-                await self.bootstrap(k8s_cloud, cluster_uuid)
-                print("Bootstrap done.")
-            else:
-                # k8s_cloud = 'microk8s-test'
-                k8s_cloud = "{}-k8s".format(namespace)
+            # Name the new k8s cloud
+            k8s_cloud = "{}-k8s".format(namespace)
 
 
-                await self.add_k8s(k8s_cloud, k8s_creds)
+            print("Adding k8s cloud {}".format(k8s_cloud))
+            await self.add_k8s(k8s_cloud, k8s_creds)
 
 
-                await self.bootstrap(k8s_cloud, cluster_uuid)
+            # Bootstrap Juju controller
+            print("Bootstrapping...")
+            await self.bootstrap(k8s_cloud, cluster_uuid, loadbalancer)
+            print("Bootstrap done.")
 
             # Get the controller information
 
 
             # Get the controller information
 
@@ -194,7 +181,7 @@ class K8sJujuConnector(K8sConnector):
                 'secret': self.juju_secret,
                 'cacert': self.juju_ca_cert,
                 'namespace': namespace,
                 'secret': self.juju_secret,
                 'cacert': self.juju_ca_cert,
                 'namespace': namespace,
-                'microk8s': microk8s,
+                'loadbalancer': loadbalancer,
             }
 
             # Store the cluster configuration so it
             }
 
             # Store the cluster configuration so it
@@ -221,7 +208,7 @@ class K8sJujuConnector(K8sConnector):
         # We're creating a new cluster
         print("Getting model {}".format(self.get_namespace(cluster_uuid), cluster_uuid=cluster_uuid))
         model = await self.get_model(
         # We're creating a new cluster
         print("Getting model {}".format(self.get_namespace(cluster_uuid), cluster_uuid=cluster_uuid))
         model = await self.get_model(
-            self.get_namespace(cluster_uuid), 
+            self.get_namespace(cluster_uuid),
             cluster_uuid=cluster_uuid
         )
 
             cluster_uuid=cluster_uuid
         )
 
@@ -286,13 +273,6 @@ class K8sJujuConnector(K8sConnector):
                 print("[reset] Destroying controller")
                 await self.destroy_controller(cluster_uuid)
 
                 print("[reset] Destroying controller")
                 await self.destroy_controller(cluster_uuid)
 
-                """Remove the k8s cloud
-
-                Only remove the k8s cloud if it's not a microk8s cloud,
-                since microk8s is a built-in cloud type.
-                """
-                # microk8s = self.is_microk8s_by_cluster_uuid(cluster_uuid)
-                # if not microk8s:
                 print("[reset] Removing k8s cloud")
                 namespace = self.get_namespace(cluster_uuid)
                 k8s_cloud = "{}-k8s".format(namespace)
                 print("[reset] Removing k8s cloud")
                 namespace = self.get_namespace(cluster_uuid)
                 k8s_cloud = "{}-k8s".format(namespace)
@@ -330,16 +310,16 @@ class K8sJujuConnector(K8sConnector):
             await self.login(cluster_uuid)
 
         ##
             await self.login(cluster_uuid)
 
         ##
-        # Get or create the model, based on the namespace the cluster was
-        # instantiated with.
-        namespace = self.get_namespace(cluster_uuid)
-        namespace = "gitlab-demo"
-        self.log.debug("Checking for model named {}".format(namespace))
-        model = await self.get_model(namespace, cluster_uuid=cluster_uuid)
+        # Get or create the model, based on the NS 
+        # uuid.
+        model_name = db_dict["filter"]["_id"]
+
+        self.log.debug("Checking for model named {}".format(model_name))
+        model = await self.get_model(model_name, cluster_uuid=cluster_uuid)
         if not model:
             # Create the new model
         if not model:
             # Create the new model
-            self.log.debug("Adding model: {}".format(namespace))
-            model = await self.add_model(namespace, cluster_uuid=cluster_uuid)
+            self.log.debug("Adding model: {}".format(model_name))
+            model = await self.add_model(model_name, cluster_uuid=cluster_uuid)
 
         if model:
             # TODO: Instantiation parameters
 
         if model:
             # TODO: Instantiation parameters
@@ -668,8 +648,9 @@ class K8sJujuConnector(K8sConnector):
 
         :returns: True if successful, otherwise raises an exception.
         """
 
         :returns: True if successful, otherwise raises an exception.
         """
-        cmd = [self.k8scli, "add-k8s", "--local", cloud_name]
 
 
+        cmd = [self.juju_command, "add-k8s", "--local", cloud_name]
+        print(cmd)
         p = subprocess.run(
             cmd,
             stdout=subprocess.PIPE,
         p = subprocess.run(
             cmd,
             stdout=subprocess.PIPE,
@@ -711,7 +692,8 @@ class K8sJujuConnector(K8sConnector):
     async def bootstrap(
         self,
         cloud_name: str,
     async def bootstrap(
         self,
         cloud_name: str,
-        cluster_uuid: str
+        cluster_uuid: str,
+        loadbalancer: bool
     ) -> bool:
         """Bootstrap a Kubernetes controller
 
     ) -> bool:
         """Bootstrap a Kubernetes controller
 
@@ -719,9 +701,18 @@ class K8sJujuConnector(K8sConnector):
 
         :param cloud_name str: The name of the cloud.
         :param cluster_uuid str: The UUID of the cluster to bootstrap.
 
         :param cloud_name str: The name of the cloud.
         :param cluster_uuid str: The UUID of the cluster to bootstrap.
+        :param loadbalancer bool: If the controller should use loadbalancer or not.
         :returns: True upon success or raises an exception.
         """
         :returns: True upon success or raises an exception.
         """
-        cmd = [self.k8scli, "bootstrap", cloud_name, cluster_uuid]
+
+        if not loadbalancer:
+            cmd = [self.juju_command, "bootstrap", cloud_name, cluster_uuid]
+        else:
+            """
+            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"]
+
         print("Bootstrapping controller {} in cloud {}".format(
             cluster_uuid, cloud_name
         ))
         print("Bootstrapping controller {} in cloud {}".format(
             cluster_uuid, cloud_name
         ))
@@ -753,7 +744,7 @@ class K8sJujuConnector(K8sConnector):
         :returns: True upon success or raises an exception.
         """
         cmd = [
         :returns: True upon success or raises an exception.
         """
         cmd = [
-            self.k8scli,
+            self.juju_command,
             "destroy-controller",
             "--destroy-all-models",
             "--destroy-storage",
             "destroy-controller",
             "--destroy-all-models",
             "--destroy-storage",
@@ -861,36 +852,26 @@ class K8sJujuConnector(K8sConnector):
             return True
         return False
 
             return True
         return False
 
-    def is_microk8s_by_cluster_uuid(
-        self,
-        cluster_uuid: str,
-    ) -> bool:
-        """Check if a cluster is micro8s
-
-        Checks if a cluster is running microk8s
-
-        :param cluster_uuid str: The UUID of the cluster
-        :returns: A boolean if the cluster is running microk8s
-        """
-        config = self.get_config(cluster_uuid)
-        return config['microk8s']
-
-    def is_microk8s_by_credentials(
+    def is_local_k8s(
         self,
         credentials: str,
     ) -> bool:
         self,
         credentials: str,
     ) -> bool:
-        """Check if a cluster is micro8s
+        """Check if a cluster is local
 
 
-        Checks if a cluster is running microk8s
+        Checks if a cluster is running in the local host
 
         :param credentials dict: A dictionary containing the k8s credentials
 
         :param credentials dict: A dictionary containing the k8s credentials
-        :returns: A boolean if the cluster is running microk8s
+        :returns: A boolean if the cluster is running locally
         """
         creds = yaml.safe_load(credentials)
         """
         creds = yaml.safe_load(credentials)
-        if creds:
-            for context in creds['contexts']:
-                if 'microk8s' in context['name']:
-                    return True
+        if os.getenv("OSMLCM_VCA_APIPROXY"):
+            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']:
+                        return True
 
         return False
 
 
         return False
 
@@ -971,7 +952,7 @@ class K8sJujuConnector(K8sConnector):
         """
 
         # Remove the bootstrapped controller
         """
 
         # Remove the bootstrapped controller
-        cmd = [self.k8scli, "remove-k8s", "--client", cloud_name]
+        cmd = [self.juju_command, "remove-k8s", "--client", cloud_name]
         p = subprocess.run(
             cmd,
             stdout=subprocess.PIPE,
         p = subprocess.run(
             cmd,
             stdout=subprocess.PIPE,
@@ -984,7 +965,7 @@ class K8sJujuConnector(K8sConnector):
             raise Exception(p.stderr)
 
         # Remove the cloud from the local config
             raise Exception(p.stderr)
 
         # Remove the cloud from the local config
-        cmd = [self.k8scli, "remove-cloud", "--client", cloud_name]
+        cmd = [self.juju_command, "remove-cloud", "--client", cloud_name]
         p = subprocess.run(
             cmd,
             stdout=subprocess.PIPE,
         p = subprocess.run(
             cmd,
             stdout=subprocess.PIPE,
@@ -996,7 +977,6 @@ class K8sJujuConnector(K8sConnector):
         if retcode > 0:
             raise Exception(p.stderr)
 
         if retcode > 0:
             raise Exception(p.stderr)
 
-
         return True
 
     async def set_config(
         return True
 
     async def set_config(