perf: Remove kubernetes tree api (#13995)

* perf: Remove kubernetes tree api

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: feng <1304903146@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com>
pull/14005/head
fit2bot 2024-08-19 16:04:00 +08:00 committed by GitHub
parent 828582333d
commit 181eb621c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 2 additions and 276 deletions

View File

@ -1,2 +1 @@
from .k8s import *
from .node import *

View File

@ -1,177 +0,0 @@
# -*- coding: utf-8 -*-
from urllib.parse import urlencode, urlparse
from kubernetes import client
from kubernetes.client import api_client
from kubernetes.client.api import core_v1_api
from sshtunnel import SSHTunnelForwarder, BaseSSHTunnelForwarderError
from common.utils import get_logger
from ..const import CloudTypes, Category
logger = get_logger(__file__)
class KubernetesClient:
def __init__(self, asset, token):
self.url = asset.address
self.token = token or ''
self.server = self.get_gateway_server(asset)
@property
def api(self):
configuration = client.Configuration()
scheme = urlparse(self.url).scheme
if not self.server:
host = self.url
else:
host = f'{scheme}://127.0.0.1:{self.server.local_bind_port}'
configuration.host = host
configuration.verify_ssl = False
configuration.api_key = {"authorization": "Bearer " + self.token}
c = api_client.ApiClient(configuration=configuration)
api = core_v1_api.CoreV1Api(c)
return api
def get_namespaces(self):
namespaces = []
resp = self.api.list_namespace()
for ns in resp.items:
namespaces.append(ns.metadata.name)
return namespaces
def get_pods(self, namespace):
pods = []
resp = self.api.list_namespaced_pod(namespace)
for pd in resp.items:
pods.append(pd.metadata.name)
return pods
def get_containers(self, namespace, pod_name):
containers = []
resp = self.api.read_namespaced_pod(pod_name, namespace)
for container in resp.spec.containers:
containers.append(container.name)
return containers
@staticmethod
def get_gateway_server(asset):
gateway = None
if not asset.is_gateway and asset.domain:
gateway = asset.domain.select_gateway()
if not gateway:
return
remote_bind_address = (
urlparse(asset.address).hostname,
urlparse(asset.address).port or 443
)
server = SSHTunnelForwarder(
(gateway.address, gateway.port),
ssh_username=gateway.username,
ssh_password=gateway.password,
ssh_pkey=gateway.private_key_path,
remote_bind_address=remote_bind_address
)
try:
server.start()
except BaseSSHTunnelForwarderError:
err_msg = 'Gateway is not active: %s' % asset.get('name', '')
print('\033[31m %s \033[0m\n' % err_msg)
return server
def run(self, tp, *args):
func_name = f'get_{tp}s'
data = []
if hasattr(self, func_name):
try:
data = getattr(self, func_name)(*args)
except Exception as e:
logger.error(f'K8S tree get {tp} error: {e}')
if self.server:
self.server.stop()
return data
class KubernetesTree:
def __init__(self, asset, secret):
self.asset = asset
self.secret = secret
def as_asset_tree_node(self):
i = str(self.asset.id)
name = str(self.asset)
node = self.create_tree_node(
i, i, name, 'asset', icon='k8s', is_open=True,
)
return node
def as_namespace_node(self, name, tp):
i = urlencode({'namespace': name})
pid = str(self.asset.id)
node = self.create_tree_node(i, pid, name, tp, icon='cloud')
return node
def as_pod_tree_node(self, namespace, name, tp):
pid = urlencode({'namespace': namespace})
i = urlencode({'namespace': namespace, 'pod': name})
node = self.create_tree_node(i, pid, name, tp, icon='cloud')
return node
def as_container_tree_node(self, namespace, pod, name, tp):
pid = urlencode({'namespace': namespace, 'pod': pod})
i = urlencode({'namespace': namespace, 'pod': pod, 'container': name})
node = self.create_tree_node(
i, pid, name, tp, icon='cloud', is_container=True
)
return node
@staticmethod
def create_tree_node(id_, pid, name, identity, icon='', is_container=False, is_open=False):
node = {
'id': id_,
'name': name,
'title': name,
'pId': pid,
'isParent': not is_container,
'open': is_open,
'iconSkin': icon,
'meta': {
'type': 'k8s',
'data': {
'category': Category.CLOUD,
'type': CloudTypes.K8S,
'identity': identity
}
}
}
return node
def async_tree_node(self, namespace, pod):
tree = []
k8s_client = KubernetesClient(self.asset, self.secret)
if pod:
tp = 'container'
containers = k8s_client.run(
tp, namespace, pod
)
for container in containers:
container_node = self.as_container_tree_node(
namespace, pod, container, tp
)
tree.append(container_node)
elif namespace:
tp = 'pod'
pods = k8s_client.run(tp, namespace)
for pod in pods:
pod_node = self.as_pod_tree_node(namespace, pod, tp)
tree.append(pod_node)
else:
tp = 'namespace'
namespaces = k8s_client.run(tp)
for namespace in namespaces:
namespace_node = self.as_namespace_node(namespace, tp)
tree.append(namespace_node)
return tree

View File

@ -1,31 +1,22 @@
import abc
from urllib.parse import parse_qsl
from django.conf import settings
from django.db.models import F, Value, CharField
from rest_framework.exceptions import PermissionDenied, NotFound
from rest_framework.generics import ListAPIView
from rest_framework.generics import get_object_or_404
from rest_framework.request import Request
from rest_framework.response import Response
from accounts.const import AliasAccount
from assets.api import SerializeToTreeNodeMixin
from assets.models import Asset
from assets.utils import KubernetesTree
from authentication.models import ConnectionToken
from common.exceptions import JMSException
from common.utils import get_object_or_none, lazyproperty
from common.utils.common import timeit
from perms.hands import Node
from perms.models import PermNode
from perms.utils import PermAssetDetailUtil, UserPermNodeUtil
from perms.utils import UserPermAssetUtil
from perms.utils import UserPermNodeUtil
from .mixin import RebuildTreeMixin
from ..mixin import SelfOrPKUserMixin
__all__ = [
'UserGrantedK8sAsTreeApi',
'UserPermedNodesWithAssetsAsTreeApi',
'UserPermedNodeChildrenWithAssetsAsTreeApi',
'UserPermedNodeChildrenWithAssetsAsCategoryTreeApi',
@ -218,55 +209,3 @@ class UserPermedNodeChildrenWithAssetsAsCategoryTreeApi(BaseUserNodeWithAssetAsT
return self.get_assets()
else:
return []
class UserGrantedK8sAsTreeApi(SelfOrPKUserMixin, ListAPIView):
""" 用户授权的K8s树 """
def get_token(self):
token_id = self.request.query_params.get('token')
token = get_object_or_404(ConnectionToken, pk=token_id)
if token.is_expired:
raise PermissionDenied('Token is expired')
token.renewal()
return token
def get_account_secret(self, token: ConnectionToken):
util = PermAssetDetailUtil(self.user, token.asset)
accounts = util.get_permed_accounts_for_user()
account_name = token.account
if account_name in [AliasAccount.INPUT, AliasAccount.USER]:
return token.input_secret
else:
accounts = filter(lambda x: x.name == account_name, accounts)
accounts = list(accounts)
if not accounts:
raise NotFound('Account is not found')
account = accounts[0]
return account.secret
@staticmethod
def get_namespace_and_pod(key):
namespace_and_pod = dict(parse_qsl(key))
pod = namespace_and_pod.get('pod')
namespace = namespace_and_pod.get('namespace')
return namespace, pod
def list(self, request: Request, *args, **kwargs):
token = self.get_token()
asset = token.asset
secret = self.get_account_secret(token)
key = self.request.query_params.get('key')
namespace, pod = self.get_namespace_and_pod(key)
tree = []
k8s_tree_instance = KubernetesTree(asset, secret)
if not any([namespace, pod]) and not key:
asset_node = k8s_tree_instance.as_asset_tree_node()
tree.append(asset_node)
try:
tree.extend(k8s_tree_instance.async_tree_node(namespace, pod))
return Response(data=tree)
except Exception as e:
raise JMSException(e)

View File

@ -47,9 +47,6 @@ user_permission_urlpatterns = [
path('<str:user>/nodes/all-with-assets/tree/',
api.UserPermedNodesWithAssetsAsTreeApi.as_view(),
name='user-nodes-with-assets-as-tree'),
path('<str:user>/nodes/children-with-k8s/tree/',
api.UserGrantedK8sAsTreeApi.as_view(),
name='user-nodes-children-with-k8s-as-tree'),
]
user_group_permission_urlpatterns = [

33
poetry.lock generated
View File

@ -3500,37 +3500,6 @@ type = "legacy"
url = "https://mirrors.aliyun.com/pypi/simple"
reference = "aliyun"
[[package]]
name = "kubernetes"
version = "27.2.0"
description = "Kubernetes python client"
optional = false
python-versions = ">=3.6"
files = [
{file = "kubernetes-27.2.0-py2.py3-none-any.whl", hash = "sha256:0f9376329c85cf07615ed6886bf9bf21eb1cbfc05e14ec7b0f74ed8153cd2815"},
{file = "kubernetes-27.2.0.tar.gz", hash = "sha256:d479931c6f37561dbfdf28fc5f46384b1cb8b28f9db344ed4a232ce91990825a"},
]
[package.dependencies]
certifi = ">=14.05.14"
google-auth = ">=1.0.1"
oauthlib = ">=3.2.2"
python-dateutil = ">=2.5.3"
pyyaml = ">=5.4.1"
requests = "*"
requests-oauthlib = "*"
six = ">=1.9.0"
urllib3 = ">=1.24.2"
websocket-client = ">=0.32.0,<0.40.0 || >0.40.0,<0.41.dev0 || >=0.43.dev0"
[package.extras]
adal = ["adal (>=1.0.2)"]
[package.source]
type = "legacy"
url = "https://mirrors.aliyun.com/pypi/simple"
reference = "aliyun"
[[package]]
name = "ldap3"
version = "2.9.1"
@ -7701,4 +7670,4 @@ reference = "aliyun"
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
content-hash = "2dc429e66e78ab1e264e26da60df6a67cb8d5e501d80297332d673646bc0cf13"
content-hash = "9acfafd75bf7dbb7e0dffb54b7f11f6b09aa4ceff769d193a3906d03ae796ccc"

View File

@ -126,7 +126,6 @@ django-auth-ldap = "4.4.0"
boto3 = "1.28.9"
botocore = "1.31.9"
s3transfer = "0.6.1"
kubernetes = "27.2.0"
mysqlclient = "2.2.4"
pymssql = "2.2.8"
django-redis = "5.3.0"