Enhance: Enable O2 DMS by exposing k8s API endpoint 85/8285/2
authorZhang Rong(Jon) <rong.zhang@windriver.com>
Mon, 16 May 2022 07:55:20 +0000 (15:55 +0800)
committerZhang Rong(Jon) <rong.zhang@windriver.com>
Tue, 17 May 2022 02:59:07 +0000 (10:59 +0800)
1. Add profile query parameter for IMS and DMS API, if the parameter exists, return k8s profile information
2. Add an API of the download k8s config file

Issue-ID: INF-264
Signed-off-by: Zhang Rong(Jon) <rong.zhang@windriver.com>
Change-Id: I5cba1290b5b1b7103cf6f5f88f5998ef1dc8b8fd

13 files changed:
Dockerfile
Dockerfile.localtest
charts/templates/deployment.yaml
docker-compose.yml
o2dms/api/dms_dto.py
o2dms/api/dms_lcm_view.py
o2dms/api/dms_route.py
o2ims/adapter/orm.py
o2ims/domain/ocloud.py
o2ims/service/auditor/dms_handler.py
o2ims/views/ocloud_dto.py
o2ims/views/ocloud_route.py
o2ims/views/ocloud_view.py

index dc0adcb..84ebb52 100644 (file)
@@ -1,6 +1,6 @@
 FROM python:3.10-slim-buster
 
-RUN apt-get update; apt-get install -y git gcc
+RUN apt-get update && apt-get install -y git gcc procps vim curl
 
 # in case git repo is not accessable
 # RUN mkdir -p /cgtsclient
@@ -44,8 +44,6 @@ COPY configs/ /etc/o2/
 
 COPY tests/ /tests/
 
-RUN apt-get install -y procps vim curl
-
 RUN curl -O https://get.helm.sh/helm-v3.3.1-linux-amd64.tar.gz;
 RUN tar -zxvf helm-v3.3.1-linux-amd64.tar.gz; cp linux-amd64/helm /usr/local/bin
 
index b047113..3a3a7ea 100644 (file)
@@ -1,25 +1,21 @@
 FROM python:3.10-slim-buster
 
-RUN apt-get update; apt-get install -y git gcc
+RUN apt-get update && apt-get install -y git gcc \
+    vim curl procps
 
 # in case git repo is not accessable
-RUN mkdir -p /cgtsclient
+RUN mkdir -p /cgtsclient && mkdir -p /distcloud-client
 COPY temp/config /cgtsclient/
-RUN pip install -e cgtsclient/sysinv/cgts-client/cgts-client/
-
-RUN mkdir -p /distcloud-client
 COPY temp/distcloud-client /distcloud-client/
-RUN pip install -e /distcloud-client/distributedcloud-client
-# in case git repo is not accessable
 
+RUN pip install -e cgtsclient/sysinv/cgts-client/cgts-client/ \
+    && pip install -e /distcloud-client/distributedcloud-client
+# in case git repo is not accessable
 
-COPY requirements.txt /tmp/
-COPY constraints.txt /tmp/
-
-RUN  pip install -r /tmp/requirements.txt -c /tmp/constraints.txt
+COPY requirements.txt constraints.txt requirements-test.txt /tmp/
 
-COPY requirements-test.txt /tmp/
-RUN pip install -r /tmp/requirements-test.txt
+RUN pip install -r /tmp/requirements.txt -c /tmp/constraints.txt \
+    && pip install -r /tmp/requirements-test.txt
 
 
 RUN mkdir -p /src
@@ -45,9 +41,9 @@ COPY configs/ /etc/o2/
 # RUN pip install -e /src
 COPY tests/ /tests/
 
-RUN apt-get install -y procps vim
+#RUN apt-get install -y procps vim
 
-RUN apt-get install -y curl
+#RUN apt-get install -y curl
 RUN curl -O https://get.helm.sh/helm-v3.3.1-linux-amd64.tar.gz;
 RUN tar -zxvf helm-v3.3.1-linux-amd64.tar.gz; cp linux-amd64/helm /usr/local/bin
 
index a25f326..0f0b433 100644 (file)
@@ -109,8 +109,8 @@ spec:
           ports:
             - containerPort: 80
           env:
-            - name: API_HOST
-              value: api
+            - name: API_HOST_EXTERNAL_FLOATING
+              value: {{ .Values.ocloud.API_HOST_EXTERNAL_FLOATING }}
             - name: DB_HOST
               value: postgres
             - name: DB_PASSWORD
index 962d36d..ad3d857 100644 (file)
@@ -42,7 +42,7 @@ services:
     environment:
       - DB_HOST=postgres
       - DB_PASSWORD=o2ims123
-      - API_HOST=api
+      - API_HOST_EXTERNAL_FLOATING=${API_HOST_EXTERNAL_FLOATING}
       - REDIS_HOST=redis
       - PYTHONDONTWRITEBYTECODE=1
       - FLASK_APP=/o2app/entrypoints/flask_application.py
index 8b305e3..ae699f4 100644 (file)
@@ -19,6 +19,16 @@ logger = o2logging.get_logger(__name__)
 
 
 class DmsDTO:
+    profile = api_dms_lcm_v1.model("DMSGetDtoProfile", {
+        'cluster_api_endpoint': fields.String(
+            attributes='cluster_api_endpoint'),
+        'cluster_ca_cert': fields.String(attributes='cluster_ca_cert'),
+        'admin_user': fields.String(attributes='admin_user'),
+        'admin_client_cert': fields.String(attributes='admin_client_cert'),
+        'admin_client_key': fields.String(attributes='admin_client_key'),
+        'kube_config_file': fields.String(attributes='kube_config_file')
+    })
+
     dms_get = api_dms_lcm_v1.model(
         "DmsGetDto",
         {
@@ -30,6 +40,7 @@ class DmsDTO:
             'supportedLocations': fields.String,
             'capabilities': fields.String,
             'capacity': fields.String,
+            'profile': fields.Nested(profile, False, True),
         }
     )
 
index 3a634e4..208636a 100644 (file)
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-from sqlalchemy import select
+import string
+import random
+import yaml
+from datetime import datetime
+
+# from sqlalchemy import select
 from o2common.service import unit_of_work
-from o2ims.adapter.orm import deploymentmanager
+from o2ims.adapter.orm import deploymentmanager
 from o2common.helper import o2logging
+from o2common.config import config
 logger = o2logging.get_logger(__name__)
 
 
 def deployment_managers(uow: unit_of_work.AbstractUnitOfWork):
+    # with uow:
+    # res = uow.session.execute(select(deploymentmanager))
+    # return [dict(r) for r in res]
     with uow:
-        res = uow.session.execute(select(deploymentmanager))
-    return [dict(r) for r in res]
+        li = uow.deployment_managers.list()
+    return [r.serialize() for r in li]
 
 
 def deployment_manager_one(deploymentManagerId: str,
-                           uow: unit_of_work.AbstractUnitOfWork):
+                           uow: unit_of_work.AbstractUnitOfWork,
+                           profile: str = 'params'):
+    # with uow:
+    #     res = uow.session.execute(select(deploymentmanager).where(
+    #         deploymentmanager.c.deploymentManagerId == deploymentManagerId))
+    #     first = res.first()
+    # return None if first is None else dict(first)
+    # with uow:
+    # first = uow.deployment_managers.get(deploymentManagerId)
+    # return first.serialize() if first is not None else None
     with uow:
-        res = uow.session.execute(select(deploymentmanager).where(
-            deploymentmanager.c.deploymentManagerId == deploymentManagerId))
-        first = res.first()
-    return None if first is None else dict(first)
+        first = uow.deployment_managers.get(deploymentManagerId)
+        if first is None:
+            return first
+        result = first.serialize()
+
+    if "params" == profile:
+        pass
+    elif "file" == profile and result.hasattr("profile"):
+        p = result.pop("profile", None)
+        result["profile"] = _gen_kube_config(deploymentManagerId, p)
+    else:
+        result.pop("profile", None)
+
+    return result
+
+
+def _gen_kube_config(dmId: str, kubeconfig: dict) -> dict:
+
+    # KUBECONFIG environment variable
+    # reference:
+    # https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
+    data = {
+        'apiVersion': 'v1',
+        'clusters': [
+            {
+                'cluster': {
+                    'server':
+                    kubeconfig.pop('cluster_api_endpoint', None),
+                    'certificate-authority-data':
+                    kubeconfig.pop('cluster_ca_cert', None),
+                },
+                'name': 'inf-cluster'
+            }],
+        'contexts': [
+            {
+                'context': {
+                    'cluster': 'inf-cluster',
+                    'user': 'kubernetes-admin'
+                },
+                'name': 'kubernetes-admin@inf-cluster'
+            }
+        ],
+        'current-context': 'kubernetes-admin@inf-cluster',
+        'kind': 'Config',
+        'preferences': {},
+        'users': [
+            {
+                'name': kubeconfig.pop('admin_user', None),
+                'user': {
+                    'client-certificate-data':
+                    kubeconfig.pop('admin_client_cert', None),
+                    'client-key-data':
+                    kubeconfig.pop('admin_client_key', None),
+                }
+            }]
+    }
+
+    # Generate a random key for tmp kube config file
+    letters = string.ascii_uppercase
+    random_key = ''.join(random.choice(letters) for i in range(10))
+
+    # Get datetime of now as tag of the tmp file
+    current_time = datetime.now().strftime("%Y%m%d%H%M%S")
+    tmp_file_name = random_key + "_" + current_time
+
+    # write down the yaml file of kubectl into tmp folder
+    with open('/tmp/kubeconfig_' + tmp_file_name, 'w') as file:
+        yaml.dump(data, file)
+
+    kubeconfig["kube_config_file"] = config.get_api_url() + \
+        config.get_o2dms_api_base() + "/" + dmId + "/download/" + tmp_file_name
+
+    return kubeconfig
index 480d965..c92bdc1 100644 (file)
@@ -13,7 +13,9 @@
 #  limitations under the License.
 
 # from flask import jsonify
-from flask_restx import Resource
+from os.path import exists
+from flask import send_file
+from flask_restx import Resource, reqparse
 
 from o2dms.api.dms_dto import DmsDTO
 from o2dms.api import dms_lcm_view
@@ -31,6 +33,8 @@ def configure_api_route():
 # ----------  DeploymentManagers ---------- #
 @api_dms_lcm_v1.route("/<deploymentManagerID>")
 @api_dms_lcm_v1.param('deploymentManagerID', 'ID of the deployment manager')
+@api_dms_lcm_v1.param('profile', 'DMS profile',
+                      location='args')
 @api_dms_lcm_v1.response(404, 'Deployment manager not found')
 class DmsGetRouter(Resource):
 
@@ -43,9 +47,32 @@ class DmsGetRouter(Resource):
             deploymentManagerID
         ))
         bus = MessageBus.get_instance()
+
+        parser = reqparse.RequestParser()
+        parser.add_argument('profile', location='args')
+        args = parser.parse_args()
+
         result = dms_lcm_view.deployment_manager_one(
-            deploymentManagerID, bus.uow)
+            deploymentManagerID, bus.uow, args.profile)
         if result is not None:
             return result
         api_dms_lcm_v1.abort(404, "Deployment manager {} doesn't exist".format(
             deploymentManagerID))
+
+
+@api_dms_lcm_v1.route("/<deploymentManagerID>/download/<filename>")
+@api_dms_lcm_v1.param('deploymentManagerID',
+                      'ID of the deployment manager')
+@api_dms_lcm_v1.param('filename',
+                      'profile filename')
+@api_dms_lcm_v1.response(404, 'profile not found')
+class DeploymentManagerGetFileRouter(Resource):
+    def get(self, deploymentManagerID, filename):
+        path = "/tmp/kubeconfig_" + filename
+
+        if exists(path):
+            return send_file(path, as_attachment=True)
+        api_dms_lcm_v1.abort(
+            404,
+            "Deployment manager {}'s Kube config file doesn't exist".
+            format(deploymentManagerID))
index 45ec4d8..cb3a694 100644 (file)
@@ -132,6 +132,7 @@ deploymentmanager = Table(
     Column("supportedLocations", String(255)),
     Column("capabilities", String(255)),
     Column("capacity", String(255)),
+    Column("profile", Text())
     # Column("extensions", String(1024))
 )
 
index 1775aa2..8547f5d 100644 (file)
@@ -27,7 +27,7 @@ class DeploymentManager(AgRoot, Serializer):
     def __init__(self, id: str, name: str, ocloudid: str,
                  dmsendpoint: str, description: str = '',
                  supportedLocations: str = '', capabilities: str = '',
-                 capacity: str = '') -> None:
+                 capacity: str = '', profile: str = '') -> None:
         super().__init__()
         self.deploymentManagerId = id
         self.version_number = 0
@@ -38,8 +38,17 @@ class DeploymentManager(AgRoot, Serializer):
         self.supportedLocations = supportedLocations
         self.capabilities = capabilities
         self.capacity = capacity
+        self.profile = profile
         self.extensions = []
 
+    def serialize(self):
+        d = Serializer.serialize(self)
+
+        if 'profile' in d and d['profile'] != '':
+            d['profile'] = json.loads(d['profile'])
+
+        return d
+
 
 class ResourcePool(AgRoot, Serializer):
     def __init__(self, id: str, name: str, location: str,
index 9ef0a77..89811c6 100644 (file)
@@ -15,6 +15,9 @@
 # pylint: disable=unused-argument
 from __future__ import annotations
 
+import base64
+import json
+
 from o2ims.domain.stx_object import StxGenericModel
 # from dataclasses import asdict
 # from typing import List, Dict, Callable, Type
@@ -43,7 +46,7 @@ def update_dms(
     with uow:
         dms = uow.deployment_managers.get(stxobj.id)
         if not dms:
-            logger.info("add dms:" + stxobj.name
+            logger.info("add dms: " + stxobj.name
                         + " update_at: " + str(stxobj.updatetime)
                         + " id: " + str(stxobj.id)
                         + " hash: " + str(stxobj.hash))
@@ -56,7 +59,7 @@ def update_dms(
         else:
             localmodel = dms
             if is_outdated(localmodel, stxobj):
-                logger.info("update a dms:" + stxobj.name
+                logger.info("update a dms: " + stxobj.name
                             + " update_at: " + str(stxobj.updatetime)
                             + " id: " + str(stxobj.id)
                             + " hash: " + str(stxobj.hash))
@@ -83,9 +86,10 @@ def create_by(stxobj: StxGenericModel, parentid: str) -> DeploymentManager:
     supportedLocations = ''
     capabilities = ''
     capacity = ''
+    profile = _convert_content(stxobj.content)
     localmodel = DeploymentManager(
         stxobj.id, stxobj.name, ocloudid, dmsendpoint, description,
-        supportedLocations, capabilities, capacity)
+        supportedLocations, capabilities, capacity, profile)
     localmodel.createtime = stxobj.createtime
     localmodel.updatetime = stxobj.updatetime
     localmodel.hash = stxobj.hash
@@ -100,8 +104,38 @@ def update_by(target: DeploymentManager, stxobj: StxGenericModel,
     target.name = stxobj.name
     target.createtime = stxobj.createtime
     target.updatetime = stxobj.updatetime
-    # ocloud.content = stxobj.content
     target.hash = stxobj.hash
     target.oCloudId = parentid
     target.version_number = target.version_number + 1
+    target.profile = _convert_content(stxobj.content)
     target.events = []
+
+
+def _convert_content(stxobj_content: str):
+    # Convert api retrun content to dict object
+    content = json.loads(stxobj_content)
+    admin_user = content["admin_user"]
+    cluster_api_endpoint = content["cluster_api_endpoint"]
+    cluster_ca_cert = _b64_encode_str(content["cluster_ca_cert"])
+    admin_client_cert = _b64_encode_str(content["admin_client_cert"])
+    admin_client_key = _b64_encode_str(content["admin_client_key"])
+    # admin_client_cert = base64.b64encode(
+    #     bytes(content["admin_client_cert"], "utf-8"))
+    # admin_client_key = base64.b64encode(
+    #     bytes(content["admin_client_key"], "utf-8"))
+    profile = {
+        "admin_user": admin_user,
+        "cluster_api_endpoint": cluster_api_endpoint,
+        "cluster_ca_cert": cluster_ca_cert,
+        "admin_client_cert": admin_client_cert,
+        "admin_client_key": admin_client_key
+    }
+
+    return json.dumps(profile)
+
+
+def _b64_encode_str(msg: str, encode: str = 'utf-8') -> str:
+    msg_bytes = msg.encode('utf-8')
+    base64_bytes = base64.b64encode(msg_bytes)
+    base64_msg = base64_bytes.decode('utf-8')
+    return base64_msg
index c6896e0..c7489ae 100644 (file)
@@ -94,43 +94,68 @@ class ResourceDTO:
         return api_ims_inventory_v1.model(
             'ResourceGetDto' + str(iteration_number), resource_json_mapping)
 
-    def _recursive_resource_mapping(self, iteration_number=2):
-        resource_json_mapping = {
-            'resourceId': fields.String(required=True,
-                                        description='Resource ID'),
-            'resourceTypeId': fields.String,
-            'resourcePoolId': fields.String,
+    # def _recursive_resource_mapping(self, iteration_number=2):
+    #     resource_json_mapping = {
+    #         'resourceId': fields.String(required=True,
+    #                                     description='Resource ID'),
+    #         'resourceTypeId': fields.String,
+    #         'resourcePoolId': fields.String,
+    #         'name': fields.String,
+    #         'parentId': fields.String,
+    #         'description': fields.String,
+    #     }
+    #     if iteration_number:
+    #         resource_json_mapping['children'] = fields.List(
+    #             fields.Nested(self._recursive_resource_mapping(
+    #                 iteration_number-1)))
+    #         # print(type(resource_json_mapping['children']))
+    #         if resource_json_mapping['children'] is None:
+    #             del resource_json_mapping['children']
+    #     return resource_json_mapping
+
+    # def get_resource_get(self):
+    #     return api_ims_inventory_v1.model(
+    #         'ResourceGetDto',
+    #         {
+    #             'resourceId': fields.String(required=True,
+    #                                         description='Resource ID'),
+    #             'resourceTypeId': fields.String,
+    #             'resourcePoolId': fields.String,
+    #             'name': fields.String,
+    #             'parentId': fields.String,
+    #             'description': fields.String,
+    #             'children': fields.List(fields.Nested(
+    #                 self._recursive_resource_mapping()))
+    #         }
+    #     )
+
+
+class DeploymentManagerDTO:
+
+    deployment_manager_list = api_ims_inventory_v1.model(
+        "DeploymentManagerListDto",
+        {
+            'deploymentManagerId': fields.String(
+                required=True,
+                description='Deployment manager ID'),
             'name': fields.String,
-            'parentId': fields.String,
             'description': fields.String,
+            'deploymentManagementServiceEndpoint': fields.String,
+            'supportedLocations': fields.String,
+            'capabilities': fields.String,
+            'capacity': fields.String,
         }
-        if iteration_number:
-            resource_json_mapping['children'] = fields.List(
-                fields.Nested(self._recursive_resource_mapping(
-                    iteration_number-1)))
-            # print(type(resource_json_mapping['children']))
-            if resource_json_mapping['children'] is None:
-                del resource_json_mapping['children']
-        return resource_json_mapping
-
-    def get_resource_get(self):
-        return api_ims_inventory_v1.model(
-            'ResourceGetDto',
-            {
-                'resourceId': fields.String(required=True,
-                                            description='Resource ID'),
-                'resourceTypeId': fields.String,
-                'resourcePoolId': fields.String,
-                'name': fields.String,
-                'parentId': fields.String,
-                'description': fields.String,
-                'children': fields.List(fields.Nested(
-                    self._recursive_resource_mapping()))
-            }
-        )
-
+    )
 
-class DeploymentManagerDTO:
+    profile = api_ims_inventory_v1.model("DeploymentManagerGetDtoProfile", {
+        'cluster_api_endpoint': fields.String(
+            attributes='cluster_api_endpoint'),
+        'cluster_ca_cert': fields.String(attributes='cluster_ca_cert'),
+        'admin_user': fields.String(attributes='admin_user'),
+        'admin_client_cert': fields.String(attributes='admin_client_cert'),
+        'admin_client_key': fields.String(attributes='admin_client_key'),
+        'kube_config_file': fields.String(attributes='kube_config_file')
+    })
 
     deployment_manager_get = api_ims_inventory_v1.model(
         "DeploymentManagerGetDto",
@@ -144,6 +169,7 @@ class DeploymentManagerDTO:
             'supportedLocations': fields.String,
             'capabilities': fields.String,
             'capacity': fields.String,
+            'profile': fields.Nested(profile, False, True),
         }
     )
 
index d6913a9..6aa6b2e 100644 (file)
@@ -12,8 +12,7 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License.
 
-from flask_restx import Resource
-from flask_restx import reqparse
+from flask_restx import Resource, reqparse
 
 from o2common.service.messagebus import MessageBus
 from o2ims.views import ocloud_view
@@ -159,7 +158,7 @@ class ResourceGetRouter(Resource):
 @api_ims_inventory_v1.route("/deploymentManagers")
 class DeploymentManagersListRouter(Resource):
 
-    model = DeploymentManagerDTO.deployment_manager_get
+    model = DeploymentManagerDTO.deployment_manager_list
 
     @api_ims_inventory_v1.marshal_list_with(model)
     def get(self):
@@ -169,6 +168,8 @@ class DeploymentManagersListRouter(Resource):
 @api_ims_inventory_v1.route("/deploymentManagers/<deploymentManagerID>")
 @api_ims_inventory_v1.param('deploymentManagerID',
                             'ID of the deployment manager')
+@api_ims_inventory_v1.param('profile', 'DMS profile',
+                            location='args')
 @api_ims_inventory_v1.response(404, 'Deployment manager not found')
 class DeploymentManagerGetRouter(Resource):
 
@@ -177,8 +178,11 @@ class DeploymentManagerGetRouter(Resource):
     @api_ims_inventory_v1.doc('Get deployment manager')
     @api_ims_inventory_v1.marshal_with(model)
     def get(self, deploymentManagerID):
+        parser = reqparse.RequestParser()
+        parser.add_argument('profile', location='args')
+        args = parser.parse_args()
         result = ocloud_view.deployment_manager_one(
-            deploymentManagerID, bus.uow)
+            deploymentManagerID, bus.uow, args.profile)
         if result is not None:
             return result
         api_ims_inventory_v1.abort(
index 7355f71..7213fc4 100644 (file)
 #  limitations under the License.
 
 import uuid
+import yaml
+import random
+import string
+from datetime import datetime
 
 from o2common.service import unit_of_work
 from o2ims.views.ocloud_dto import SubscriptionDTO
 from o2ims.domain.subscription_obj import Subscription
 
 from o2common.helper import o2logging
+from o2common.config import config
 logger = o2logging.get_logger(__name__)
 
 
@@ -99,10 +104,82 @@ def deployment_managers(uow: unit_of_work.AbstractUnitOfWork):
 
 
 def deployment_manager_one(deploymentManagerId: str,
-                           uow: unit_of_work.AbstractUnitOfWork):
+                           uow: unit_of_work.AbstractUnitOfWork,
+                           profile: str = 'params'):
     with uow:
         first = uow.deployment_managers.get(deploymentManagerId)
-        return first.serialize() if first is not None else None
+        if first is None:
+            return first
+        result = first.serialize()
+
+    if "params" == profile:
+        pass
+    elif "file" == profile and result.hasattr("profile"):
+        p = result.pop("profile", None)
+        result["profile"] = _gen_kube_config(deploymentManagerId, p)
+    else:
+        result.pop("profile", None)
+
+    return result
+
+
+def _gen_kube_config(dmId: str, kubeconfig: dict) -> dict:
+
+    # KUBECONFIG environment variable
+    # reference:
+    # https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/
+    data = {
+        'apiVersion': 'v1',
+        'clusters': [
+            {
+                'cluster': {
+                    'server':
+                    kubeconfig.pop('cluster_api_endpoint', None),
+                    'certificate-authority-data':
+                    kubeconfig.pop('cluster_ca_cert', None),
+                },
+                'name': 'inf-cluster'
+            }],
+        'contexts': [
+            {
+                'context': {
+                    'cluster': 'inf-cluster',
+                    'user': 'kubernetes-admin'
+                },
+                'name': 'kubernetes-admin@inf-cluster'
+            }
+        ],
+        'current-context': 'kubernetes-admin@inf-cluster',
+        'kind': 'Config',
+        'preferences': {},
+        'users': [
+            {
+                'name': kubeconfig.pop('admin_user', None),
+                'user': {
+                    'client-certificate-data':
+                    kubeconfig.pop('admin_client_cert', None),
+                    'client-key-data':
+                    kubeconfig.pop('admin_client_key', None),
+                }
+            }]
+    }
+
+    # Generate a random key for tmp kube config file
+    letters = string.ascii_uppercase
+    random_key = ''.join(random.choice(letters) for i in range(10))
+
+    # Get datetime of now as tag of the tmp file
+    current_time = datetime.now().strftime("%Y%m%d%H%M%S")
+    tmp_file_name = random_key + "_" + current_time
+
+    # write down the yaml file of kubectl into tmp folder
+    with open('/tmp/kubeconfig_' + tmp_file_name, 'w') as file:
+        yaml.dump(data, file)
+
+    kubeconfig["kube_config_file"] = config.get_api_url() + \
+        config.get_o2dms_api_base() + "/" + dmId + "/download/" + tmp_file_name
+
+    return kubeconfig
 
 
 def subscriptions(uow: unit_of_work.AbstractUnitOfWork):