perf: 修改k8s 树 (#9228)

Co-authored-by: feng <1304903146@qq.com>
pull/9225/head^2
fit2bot 2022-12-21 17:17:54 +08:00 committed by GitHub
parent 0e534f3251
commit c304a58c05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 87 deletions

View File

@ -1,16 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from urllib3.exceptions import MaxRetryError from urllib3.exceptions import MaxRetryError
from urllib.parse import urlencode, parse_qsl from urllib.parse import urlencode
from kubernetes import client from kubernetes import client
from kubernetes.client import api_client from kubernetes.client import api_client
from kubernetes.client.api import core_v1_api from kubernetes.client.api import core_v1_api
from kubernetes.client.exceptions import ApiException from kubernetes.client.exceptions import ApiException
from rest_framework.generics import get_object_or_404
from common.utils import get_logger from common.utils import get_logger
from assets.models import Account, Asset
from ..const import CloudTypes, Category from ..const import CloudTypes, Category
@ -94,57 +91,45 @@ class KubernetesClient:
return f'{gateway.address}:{gateway.port}' return f'{gateway.address}:{gateway.port}'
@classmethod @classmethod
def get_kubernetes_data(cls, app_id, username): def get_kubernetes_data(cls, asset, secret):
asset = get_object_or_404(Asset, id=app_id)
account = get_object_or_404(Account, asset=asset, username=username)
k8s_url = f'{asset.address}:{asset.port}' k8s_url = f'{asset.address}:{asset.port}'
proxy_url = cls.get_proxy_url(asset) proxy_url = cls.get_proxy_url(asset)
k8s = cls(k8s_url, account.secret, proxy=proxy_url) k8s = cls(k8s_url, secret, proxy=proxy_url)
return k8s.get_pods() return k8s.get_pods()
class KubernetesTree: class KubernetesTree:
def __init__(self, tree_id): def __init__(self, asset, secret):
self.tree_id = str(tree_id) self.asset = asset
self.secret = secret
@staticmethod def as_asset_tree_node(self):
def create_tree_id(pid, tp, v): i = str(self.asset.id)
i = dict(parse_qsl(pid)) name = str(self.asset)
i[tp] = v
tree_id = urlencode(i)
return tree_id
def as_tree_node(self, app):
pid = app.create_app_tree_pid(self.tree_id)
app_id = str(app.id)
node = self.create_tree_node( node = self.create_tree_node(
app_id, pid, app.name, 'k8s' i, i, name, 'asset', is_open=True,
) )
return node return node
def as_asset_tree_node(self, asset): def as_namespace_node(self, name, tp, counts=0):
i = urlencode({'asset_id': self.tree_id}) i = urlencode({'namespace': name})
node = self.create_tree_node( pid = str(self.asset.id)
i, str(asset.id), str(asset), 'asset', is_open=True, name = f'{name}({counts})'
) node = self.create_tree_node(i, pid, name, tp, icon='cloud')
return node return node
def as_account_tree_node(self, account, parent_info): def as_pod_tree_node(self, namespace, name, tp, counts=0):
username = account.username pid = urlencode({'namespace': namespace})
name = str(account) i = urlencode({'namespace': namespace, 'pod': name})
pid = urlencode({'asset_id': self.tree_id}) name = f'{name}({counts})'
i = self.create_tree_id(pid, 'account', username) node = self.create_tree_node(i, pid, name, tp, icon='cloud')
parent_info.update({'account': username})
node = self.create_tree_node(
i, pid, name, 'account', icon='user-tie'
)
return node return node
def as_namespace_pod_tree_node(self, name, tp, counts=0, is_container=False): def as_container_tree_node(self, namespace, pod, name, tp):
i = self.create_tree_id(self.tree_id, tp, name) pid = urlencode({'namespace': namespace, 'pod': pod})
name = name if is_container else f'{name}({counts})' i = urlencode({'namespace': namespace, 'pod': pod, 'container': name})
node = self.create_tree_node( node = self.create_tree_node(
i, self.tree_id, name, tp, icon='cloud', is_container=is_container i, pid, name, tp, icon='cloud', is_container=True
) )
return node return node
@ -169,36 +154,31 @@ class KubernetesTree:
} }
return node return node
def async_tree_node(self, parent_info): def async_tree_node(self, namespace, pod):
pod_name = parent_info.get('pod')
asset_id = parent_info.get('asset_id')
namespace = parent_info.get('namespace')
account_username = parent_info.get('account')
tree = [] tree = []
data = KubernetesClient.get_kubernetes_data(asset_id, account_username) data = KubernetesClient.get_kubernetes_data(self.asset, self.secret)
if not data: if not data:
return tree return tree
if pod_name: if pod:
for container in next( for container in next(
filter( filter(
lambda x: x['pod_name'] == pod_name, data[namespace] lambda x: x['pod_name'] == pod, data[namespace]
) )
)['containers']: )['containers']:
container_node = self.as_namespace_pod_tree_node( container_node = self.as_container_tree_node(
container, 'container', is_container=True namespace, pod, container, 'container'
) )
tree.append(container_node) tree.append(container_node)
elif namespace: elif namespace:
for pod in data[namespace]: for pod in data[namespace]:
pod_nodes = self.as_namespace_pod_tree_node( pod_nodes = self.as_pod_tree_node(
pod['pod_name'], 'pod', len(pod['containers']) namespace, pod['pod_name'], 'pod', len(pod['containers'])
) )
tree.append(pod_nodes) tree.append(pod_nodes)
elif account_username: else:
for namespace, pods in data.items(): for namespace, pods in data.items():
namespace_node = self.as_namespace_pod_tree_node( namespace_node = self.as_namespace_node(
namespace, 'namespace', len(pods) namespace, 'namespace', len(pods)
) )
tree.append(namespace_node) tree.append(namespace_node)

View File

@ -1,6 +1,7 @@
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from common.drf.fields import EncryptedField
from orgs.mixins.serializers import OrgResourceModelSerializerMixin from orgs.mixins.serializers import OrgResourceModelSerializerMixin
from ..models import ConnectionToken from ..models import ConnectionToken
@ -11,6 +12,9 @@ __all__ = [
class ConnectionTokenSerializer(OrgResourceModelSerializerMixin): class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
expire_time = serializers.IntegerField(read_only=True, label=_('Expired time')) expire_time = serializers.IntegerField(read_only=True, label=_('Expired time'))
input_secret = EncryptedField(
label=_("Input secret"), max_length=40960, required=False, allow_blank=True
)
class Meta: class Meta:
model = ConnectionToken model = ConnectionToken

View File

@ -3,14 +3,16 @@ from urllib.parse import parse_qsl
from django.conf import settings from django.conf import settings
from django.db.models import F, Value, CharField from django.db.models import F, Value, CharField
from rest_framework.generics import ListAPIView
from rest_framework.generics import get_object_or_404
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.generics import ListAPIView
from rest_framework.generics import get_object_or_404
from rest_framework.exceptions import PermissionDenied, NotFound
from assets.api import SerializeToTreeNodeMixin
from assets.models import Asset, Account
from assets.utils import KubernetesTree from assets.utils import KubernetesTree
from assets.models import Asset, Account
from assets.api import SerializeToTreeNodeMixin
from authentication.models import ConnectionToken
from common.utils import get_object_or_none, lazyproperty from common.utils import get_object_or_none, lazyproperty
from common.utils.common import timeit from common.utils.common import timeit
from perms.hands import Node from perms.hands import Node
@ -133,41 +135,47 @@ class UserPermedNodeChildrenWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
class UserGrantedK8sAsTreeApi(SelfOrPKUserMixin, ListAPIView): class UserGrantedK8sAsTreeApi(SelfOrPKUserMixin, ListAPIView):
""" 用户授权的K8s树 """ """ 用户授权的K8s树 """
@staticmethod def get_token(self):
def asset(asset_id): token_id = self.request.query_params.get('token')
kwargs = {'id': asset_id, 'is_active': True} token = get_object_or_404(ConnectionToken, pk=token_id)
asset = get_object_or_404(Asset, **kwargs) if token.is_expired:
return asset raise PermissionDenied('Token is expired')
token.renewal()
return token
def get_accounts(self, asset): def get_account_secret(self, token: ConnectionToken):
util = PermAccountUtil() util = PermAccountUtil()
accounts = util.get_permed_accounts_for_user(self.user, asset) accounts = util.get_permed_accounts_for_user(self.user, token.asset)
ignore_username = [Account.AliasAccount.INPUT, Account.AliasAccount.USER] account_username = token.account
accounts = filter(lambda x: x.username not in ignore_username, accounts) accounts = filter(lambda x: x.username == account_username, accounts)
accounts = list(accounts) accounts = list(accounts)
return accounts if not accounts:
raise NotFound('Account is not found')
account = accounts[0]
if account.username in [
Account.AliasAccount.INPUT, Account.AliasAccount.USER
]:
return token.input_secret
else:
return account.secret
def get_namespace_and_pod(self):
key = self.request.query_params.get('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): def list(self, request: Request, *args, **kwargs):
tree_id = request.query_params.get('tree_id') token = self.get_token()
key = request.query_params.get('key', {}) asset = token.asset
secret = self.get_account_secret(token)
namespace, pod = self.get_namespace_and_pod()
tree = [] tree = []
parent_info = dict(parse_qsl(key)) k8s_tree_instance = KubernetesTree(asset, secret)
account_username = parent_info.get('account') if not any([namespace, pod]):
asset_node = k8s_tree_instance.as_asset_tree_node()
asset_id = parent_info.get('asset_id')
asset_id = tree_id if not asset_id else asset_id
if tree_id and not key and not account_username:
asset = self.asset(asset_id)
accounts = self.get_accounts(asset)
asset_node = KubernetesTree(tree_id).as_asset_tree_node(asset)
tree.append(asset_node) tree.append(asset_node)
for account in accounts: tree.extend(k8s_tree_instance.async_tree_node(namespace, pod))
account_node = KubernetesTree(tree_id).as_account_tree_node(
account, parent_info,
)
tree.append(account_node)
elif key and account_username:
tree = KubernetesTree(key).async_tree_node(parent_info)
return Response(data=tree) return Response(data=tree)