From baacc3018ab5fc2f003545fd85b0c45abe8150c0 Mon Sep 17 00:00:00 2001 From: Adam Israel Date: Sun, 1 Dec 2019 12:41:39 -0500 Subject: [PATCH] Add Juju/k8s support Adds support for Juju/k8s-based workloads Change-Id: I65a4aeccf4a51cd62361ab269356390caed717be Signed-off-by: Adam Israel --- Dockerfile.local | 7 +++++- osm_lcm/ns.py | 38 ++++++++++++++++++++++++--------- osm_lcm/vim_sdn.py | 53 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 77 insertions(+), 21 deletions(-) diff --git a/Dockerfile.local b/Dockerfile.local index 7898a84..2043879 100644 --- a/Dockerfile.local +++ b/Dockerfile.local @@ -18,7 +18,7 @@ FROM ubuntu:16.04 # Set the working directory to /app WORKDIR /app/LCM -RUN apt-get update && apt-get install -y curl \ +RUN apt-get update && apt-get install -y curl xz-utils \ && apt-get update && apt-get install -y apt-transport-https \ && curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - \ && echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list \ @@ -29,6 +29,10 @@ RUN curl https://get.helm.sh/helm-v2.15.2-linux-amd64.tar.gz --output helm-v2.15 && mv linux-amd64/helm /usr/local/bin/helm \ && rm -r linux-amd64/ +RUN curl -L https://launchpad.net/juju/2.7/2.7.0/+download/juju-2.7.0-k8s.tar.xz --output juju-2.7.0-k8s.tar.xz \ + && tar -xvf juju-2.7.0-k8s.tar.xz \ + && mv juju /usr/local/bin/juju + RUN apt-get update && apt-get install -y git tox python3 \ python3-pip python3-aiohttp python3-jinja2 \ && python3 -m pip install pip --upgrade \ @@ -93,6 +97,7 @@ ENV OSMLCM_MESSAGE_PORT 9092 # k8s ENV OSMLCM_VCA_HELMPATH /usr/local/bin/helm ENV OSMLCM_VCA_KUBECTLPATH /usr/bin/kubectl +ENV OSMLCM_VCA_JUJUPATH /usr/local/bin/juju # logs # ENV OSMLCM_GLOBAL_LOGFILE /app/log/lcm.log diff --git a/osm_lcm/ns.py b/osm_lcm/ns.py index f66c23a..67926c4 100644 --- a/osm_lcm/ns.py +++ b/osm_lcm/ns.py @@ -26,6 +26,7 @@ from jinja2 import Environment, Template, meta, TemplateError, TemplateNotFound, from osm_lcm import ROclient from osm_lcm.lcm_utils import LcmException, LcmExceptionNoMgmtIP, LcmBase, deep_get from n2vc.k8s_helm_conn import K8sHelmConnector +from n2vc.k8s_juju_conn import K8sJujuConnector from osm_common.dbbase import DbException from osm_common.fsbase import FsException @@ -125,6 +126,15 @@ class NsLcm(LcmBase): on_update_db=None, ) + self.k8sclusterjuju = K8sJujuConnector( + kubectl_command=self.vca_config.get("kubectlpath"), + juju_command=self.vca_config.get("jujupath"), + fs=self.fs, + log=self.logger, + db=self.db, + on_update_db=None, + ) + # create RO client self.RO = ROclient.ROClient(self.loop, **self.ro_config) @@ -1540,8 +1550,10 @@ class NsLcm(LcmBase): params=desc_params, db_dict=db_dict, timeout=3600) ) else: - # TODO juju-bundle connector in place - pass + task = self.k8sclusterjuju.install(cluster_uuid=cluster_uuid, kdu_model=kdumodel, + atomic=True, params=desc_params, + db_dict=db_dict, timeout=600) + pending_tasks[task] = "_admin.deployed.K8s.{}.".format(index) index += 1 if not pending_tasks: @@ -1984,8 +1996,9 @@ class NsLcm(LcmBase): self.k8sclusterhelm.uninstall(cluster_uuid=kdu.get("k8scluster-uuid"), kdu_instance=kdu_instance)) elif kdu.get("k8scluster-type") == "juju": - # TODO Juju connector needed - continue + task_delete_kdu_instance = asyncio.ensure_future( + self.k8sclusterjuju.uninstall(cluster_uuid=kdu.get("k8scluster-uuid"), + kdu_instance=kdu_instance)) else: self.error(logging_text + "Unknown k8s deployment type {}". format(kdu.get("k8scluster-type"))) @@ -2366,8 +2379,12 @@ class NsLcm(LcmBase): params=desc_params, db_dict=db_dict, timeout=300) elif kdu.get("k8scluster-type") == "juju": - # TODO Juju connector needed - pass + output = await self.k8sclusterjuju.upgrade(cluster_uuid=kdu.get("k8scluster-uuid"), + kdu_instance=kdu.get("kdu-instance"), + atomic=True, kdu_model=kdu_model, + params=desc_params, db_dict=db_dict, + timeout=300) + else: msg = "k8scluster-type not defined" raise LcmException(msg) @@ -2380,8 +2397,9 @@ class NsLcm(LcmBase): kdu_instance=kdu.get("kdu-instance"), db_dict=db_dict) elif kdu.get("k8scluster-type") == "juju": - # TODO Juju connector needed - pass + output = await self.k8sclusterjuju.rollback(cluster_uuid=kdu.get("k8scluster-uuid"), + kdu_instance=kdu.get("kdu-instance"), + db_dict=db_dict) else: msg = "k8scluster-type not defined" raise LcmException(msg) @@ -2391,8 +2409,8 @@ class NsLcm(LcmBase): output = await self.k8sclusterhelm.status_kdu(cluster_uuid=kdu.get("k8scluster-uuid"), kdu_instance=kdu.get("kdu-instance")) elif kdu.get("k8scluster-type") == "juju": - # TODO Juju connector needed - pass + output = await self.k8sclusterjuju.status_kdu(cluster_uuid=kdu.get("k8scluster-uuid"), + kdu_instance=kdu.get("kdu-instance")) else: msg = "k8scluster-type not defined" raise LcmException(msg) diff --git a/osm_lcm/vim_sdn.py b/osm_lcm/vim_sdn.py index 17da738..6ad89dc 100644 --- a/osm_lcm/vim_sdn.py +++ b/osm_lcm/vim_sdn.py @@ -23,6 +23,7 @@ import logging.handlers from osm_lcm import ROclient from osm_lcm.lcm_utils import LcmException, LcmBase, deep_get from n2vc.k8s_helm_conn import K8sHelmConnector +from n2vc.k8s_juju_conn import K8sJujuConnector from osm_common.dbbase import DbException from copy import deepcopy @@ -933,7 +934,7 @@ class K8sClusterLcm(LcmBase): self.fs = fs self.db = db - self.k8scluster = K8sHelmConnector( + self.helm_k8scluster = K8sHelmConnector( kubectl_command=self.vca_config.get("kubectlpath"), helm_command=self.vca_config.get("helmpath"), fs=self.fs, @@ -942,6 +943,15 @@ class K8sClusterLcm(LcmBase): on_update_db=None ) + self.juju_k8scluster = K8sJujuConnector( + kubectl_command=self.vca_config.get("kubectlpath"), + juju_command=self.vca_config.get("jujupath"), + fs=self.fs, + log=self.logger, + db=self.db, + on_update_db=None + ) + super().__init__(db, msg, fs, self.logger) async def create(self, k8scluster_content, order_id): @@ -961,6 +971,7 @@ class K8sClusterLcm(LcmBase): db_k8scluster = None db_k8scluster_update = {} + db_juju_k8scluster_update = {} exc = None operationState_HA = '' @@ -971,13 +982,20 @@ class K8sClusterLcm(LcmBase): db_k8scluster = self.db.get_one("k8sclusters", {"_id": k8scluster_id}) self.db.encrypt_decrypt_fields(db_k8scluster.get("credentials"), 'decrypt', ['password', 'secret'], schema_version=db_k8scluster["schema_version"], salt=db_k8scluster["_id"]) - # print(db_k8scluster.get("credentials")) - # print("\n\n\n FIN CREDENTIALS") - # print(yaml.safe_dump(db_k8scluster.get("credentials"))) - # print("\n\n\n FIN OUTPUT") - k8s_hc_id, uninstall_sw = await self.k8scluster.init_env(yaml.safe_dump(db_k8scluster.get("credentials"))) + + k8s_hc_id, uninstall_sw = await self.helm_k8scluster.init_env( + yaml.safe_dump(db_k8scluster.get("credentials")) + ) db_k8scluster_update["_admin.helm-chart.id"] = k8s_hc_id db_k8scluster_update["_admin.helm-chart.created"] = uninstall_sw + + # Juju/k8s cluster + k8s_jb_id, uninstall_sw = await self.juju_k8scluster.init_env( + yaml.safe_dump(db_k8scluster.get("credentials")) + ) + db_k8scluster_update["_admin.juju-bundle.id"] = k8s_jb_id + db_k8scluster_update["_admin.juju-bundle.created"] = uninstall_sw + step = "Getting the list of repos" self.logger.debug(logging_text + step) task_list = [] @@ -985,9 +1003,9 @@ class K8sClusterLcm(LcmBase): for repo in db_k8srepo_list: step = "Adding repo {} to cluster: {}".format(repo["name"], k8s_hc_id) self.logger.debug(logging_text + step) - task = asyncio.ensure_future(self.k8scluster.repo_add(cluster_uuid=k8s_hc_id, - name=repo["name"], url=repo["url"], - repo_type="chart")) + task = asyncio.ensure_future(self.helm_k8scluster.repo_add(cluster_uuid=k8s_hc_id, + name=repo["name"], url=repo["url"], + repo_type="chart")) task_list.append(task) if not repo["_admin"].get("cluster-inserted"): repo["_admin"]["cluster-inserted"] = [] @@ -1012,12 +1030,21 @@ class K8sClusterLcm(LcmBase): if exc and db_k8scluster: db_k8scluster_update["_admin.operationalState"] = "ERROR" db_k8scluster_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc) + + if db_juju_k8scluster_update: + db_juju_k8scluster_update["_admin.operationalState"] = "ERROR" + db_juju_k8scluster_update["_admin.detailed-status"] = "ERROR {}: {}".format(step, exc) + # Mark the k8scluster 'create' HA task as erroneous operationState_HA = 'FAILED' detailed_status_HA = "ERROR {}: {}".format(step, exc) try: if db_k8scluster_update: self.update_db_2("k8sclusters", k8scluster_id, db_k8scluster_update) + + if db_juju_k8scluster_update: + self.update_db_2("k8sclusters", k8scluster_id, db_juju_k8scluster_update) + # Register the K8scluster 'create' HA task either # succesful or erroneous, or do nothing (if legacy NBI) self.lcm_tasks.register_HA('k8scluster', 'create', op_id, @@ -1052,11 +1079,17 @@ class K8sClusterLcm(LcmBase): self.logger.debug(logging_text + step) db_k8scluster = self.db.get_one("k8sclusters", {"_id": k8scluster_id}) k8s_hc_id = deep_get(db_k8scluster, ("_admin", "helm-chart", "id")) + k8s_jb_id = deep_get(db_k8scluster, ("_admin", "juju-bundle", "id")) + uninstall_sw = deep_get(db_k8scluster, ("_admin", "helm-chart", "created")) cluster_removed = True if k8s_hc_id: uninstall_sw = uninstall_sw or False - cluster_removed = await self.k8scluster.reset(cluster_uuid=k8s_hc_id, uninstall_sw=uninstall_sw) + cluster_removed = await self.helm_k8scluster.reset(cluster_uuid=k8s_hc_id, uninstall_sw=uninstall_sw) + + if k8s_jb_id: + uninstall_sw = uninstall_sw or False + cluster_removed = await self.juju_k8scluster.reset(cluster_uuid=k8s_jb_id, uninstall_sw=uninstall_sw) if cluster_removed: step = "Removing k8scluster='{}' from db".format(k8scluster_id) -- 2.17.1