From 91649a39083a45c3bab26656671b4c6fe6e9b8ee Mon Sep 17 00:00:00 2001 From: xinwen Date: Fri, 7 Aug 2020 11:52:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(applications):=20=E6=B7=BB=E5=8A=A0=20k8s?= =?UTF-8?q?=20=E5=BA=94=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/applications/api/__init__.py | 1 + apps/applications/api/k8s_app.py | 20 +++ apps/applications/migrations/0005_k8sapp.py | 34 +++++ apps/applications/models/__init__.py | 1 + apps/applications/models/k8s_app.py | 27 ++++ apps/applications/serializers/__init__.py | 1 + apps/applications/serializers/k8s_app.py | 22 ++++ apps/applications/urls/api_urls.py | 1 + .../migrations/0054_auto_20200807_1032.py | 23 ++++ apps/assets/models/user.py | 3 + apps/assets/serializers/system_user.py | 5 +- apps/locale/zh/LC_MESSAGES/django.mo | Bin 56543 -> 56654 bytes apps/locale/zh/LC_MESSAGES/django.po | 107 +++++++++------- apps/perms/api/__init__.py | 3 + apps/perms/api/k8s_app_permission.py | 21 ++++ apps/perms/api/k8s_app_permission_relation.py | 111 ++++++++++++++++ apps/perms/api/user_k8s_app_permission.py | 119 ++++++++++++++++++ .../perms/migrations/0012_k8sapppermission.py | 44 +++++++ apps/perms/models/__init__.py | 1 + apps/perms/models/k8s_app_permission.py | 39 ++++++ apps/perms/serializers/__init__.py | 2 + apps/perms/serializers/k8s_app_permission.py | 50 ++++++++ .../k8s_app_permission_relation.py | 73 +++++++++++ apps/perms/serializers/user_permission.py | 11 ++ apps/perms/urls/api_urls.py | 2 + apps/perms/urls/k8s_app_permission.py | 45 +++++++ apps/perms/utils/__init__.py | 1 + apps/perms/utils/k8s_app_permission.py | 93 ++++++++++++++ .../migrations/0025_auto_20200810_1735.py | 18 +++ apps/terminal/models.py | 1 + 30 files changed, 831 insertions(+), 48 deletions(-) create mode 100644 apps/applications/api/k8s_app.py create mode 100644 apps/applications/migrations/0005_k8sapp.py create mode 100644 apps/applications/models/k8s_app.py create mode 100644 apps/applications/serializers/k8s_app.py create mode 100644 apps/assets/migrations/0054_auto_20200807_1032.py create mode 100644 apps/perms/api/k8s_app_permission.py create mode 100644 apps/perms/api/k8s_app_permission_relation.py create mode 100644 apps/perms/api/user_k8s_app_permission.py create mode 100644 apps/perms/migrations/0012_k8sapppermission.py create mode 100644 apps/perms/models/k8s_app_permission.py create mode 100644 apps/perms/serializers/k8s_app_permission.py create mode 100644 apps/perms/serializers/k8s_app_permission_relation.py create mode 100644 apps/perms/urls/k8s_app_permission.py create mode 100644 apps/perms/utils/k8s_app_permission.py create mode 100644 apps/terminal/migrations/0025_auto_20200810_1735.py diff --git a/apps/applications/api/__init__.py b/apps/applications/api/__init__.py index a707cfde6..0e6e940ee 100644 --- a/apps/applications/api/__init__.py +++ b/apps/applications/api/__init__.py @@ -1,2 +1,3 @@ from .remote_app import * from .database_app import * +from .k8s_app import * diff --git a/apps/applications/api/k8s_app.py b/apps/applications/api/k8s_app.py new file mode 100644 index 000000000..5cc63b546 --- /dev/null +++ b/apps/applications/api/k8s_app.py @@ -0,0 +1,20 @@ +# coding: utf-8 +# + +from orgs.mixins.api import OrgBulkModelViewSet + +from .. import models +from .. import serializers +from ..hands import IsOrgAdminOrAppUser + +__all__ = [ + 'K8sAppViewSet', +] + + +class K8sAppViewSet(OrgBulkModelViewSet): + model = models.K8sApp + filter_fields = ('name',) + search_fields = filter_fields + permission_classes = (IsOrgAdminOrAppUser,) + serializer_class = serializers.K8sAppSerializer diff --git a/apps/applications/migrations/0005_k8sapp.py b/apps/applications/migrations/0005_k8sapp.py new file mode 100644 index 000000000..3f6964a88 --- /dev/null +++ b/apps/applications/migrations/0005_k8sapp.py @@ -0,0 +1,34 @@ +# Generated by Django 2.2.13 on 2020-08-07 07:13 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('applications', '0004_auto_20191218_1705'), + ] + + operations = [ + migrations.CreateModel( + name='K8sApp', + fields=[ + ('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')), + ('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')), + ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), + ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), + ('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), + ('name', models.CharField(max_length=128, verbose_name='Name')), + ('type', models.CharField(choices=[('k8s', 'Kubernetes')], default='k8s', max_length=128, verbose_name='Type')), + ('cluster', models.CharField(max_length=1024, verbose_name='Cluster')), + ('comment', models.TextField(blank=True, default='', max_length=128, verbose_name='Comment')), + ], + options={ + 'verbose_name': 'KubernetesApp', + 'ordering': ('name',), + 'unique_together': {('org_id', 'name')}, + }, + ), + ] diff --git a/apps/applications/models/__init__.py b/apps/applications/models/__init__.py index a707cfde6..0e6e940ee 100644 --- a/apps/applications/models/__init__.py +++ b/apps/applications/models/__init__.py @@ -1,2 +1,3 @@ from .remote_app import * from .database_app import * +from .k8s_app import * diff --git a/apps/applications/models/k8s_app.py b/apps/applications/models/k8s_app.py new file mode 100644 index 000000000..c4f0591ca --- /dev/null +++ b/apps/applications/models/k8s_app.py @@ -0,0 +1,27 @@ +from django.utils.translation import gettext_lazy as _ + +from common.db import models +from orgs.mixins.models import OrgModelMixin + + +class K8sApp(OrgModelMixin, models.JMSModel): + class TYPE(models.ChoiceSet): + K8S = 'k8s', _('Kubernetes') + + name = models.CharField(max_length=128, verbose_name=_('Name')) + type = models.CharField( + default=TYPE.K8S, choices=TYPE.choices, + max_length=128, verbose_name=_('Type') + ) + cluster = models.CharField(max_length=1024, verbose_name=_('Cluster')) + comment = models.TextField( + max_length=128, default='', blank=True, verbose_name=_('Comment') + ) + + def __str__(self): + return self.name + + class Meta: + unique_together = [('org_id', 'name'), ] + verbose_name = _('KubernetesApp') + ordering = ('name', ) diff --git a/apps/applications/serializers/__init__.py b/apps/applications/serializers/__init__.py index a707cfde6..0e6e940ee 100644 --- a/apps/applications/serializers/__init__.py +++ b/apps/applications/serializers/__init__.py @@ -1,2 +1,3 @@ from .remote_app import * from .database_app import * +from .k8s_app import * diff --git a/apps/applications/serializers/k8s_app.py b/apps/applications/serializers/k8s_app.py new file mode 100644 index 000000000..68fafbc86 --- /dev/null +++ b/apps/applications/serializers/k8s_app.py @@ -0,0 +1,22 @@ +from rest_framework import serializers + +from orgs.mixins.serializers import BulkOrgResourceModelSerializer +from .. import models + +__all__ = [ + 'K8sAppSerializer', +] + + +class K8sAppSerializer(BulkOrgResourceModelSerializer): + type_display = serializers.CharField(source='get_type_display', read_only=True) + + class Meta: + model = models.K8sApp + fields = [ + 'id', 'name', 'type', 'type_display', 'comment', 'created_by', + 'date_created', 'date_updated', 'cluster' + ] + read_only_fields = [ + 'id', 'created_by', 'date_created', 'date_updated', + ] diff --git a/apps/applications/urls/api_urls.py b/apps/applications/urls/api_urls.py index 1186bf1a2..42d0fe524 100644 --- a/apps/applications/urls/api_urls.py +++ b/apps/applications/urls/api_urls.py @@ -12,6 +12,7 @@ app_name = 'applications' router = BulkRouter() router.register(r'remote-apps', api.RemoteAppViewSet, 'remote-app') router.register(r'database-apps', api.DatabaseAppViewSet, 'database-app') +router.register(r'k8s-apps', api.K8sAppViewSet, 'k8s-app') urlpatterns = [ path('remote-apps//connection-info/', api.RemoteAppConnectionInfoApi.as_view(), name='remote-app-connection-info'), diff --git a/apps/assets/migrations/0054_auto_20200807_1032.py b/apps/assets/migrations/0054_auto_20200807_1032.py new file mode 100644 index 000000000..288b78e25 --- /dev/null +++ b/apps/assets/migrations/0054_auto_20200807_1032.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.13 on 2020-08-07 02:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0053_auto_20200723_1232'), + ] + + operations = [ + migrations.AddField( + model_name='systemuser', + name='token', + field=models.TextField(default='', verbose_name='Token'), + ), + migrations.AlterField( + model_name='systemuser', + name='protocol', + field=models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('telnet', 'telnet'), ('vnc', 'vnc'), ('mysql', 'mysql'), ('k8s', 'k8s')], default='ssh', max_length=16, verbose_name='Protocol'), + ), + ] diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py index 7085a3b2b..d787cf7e7 100644 --- a/apps/assets/models/user.py +++ b/apps/assets/models/user.py @@ -91,12 +91,14 @@ class SystemUser(BaseUser): PROTOCOL_TELNET = 'telnet' PROTOCOL_VNC = 'vnc' PROTOCOL_MYSQL = 'mysql' + PROTOCOL_K8S = 'k8s' PROTOCOL_CHOICES = ( (PROTOCOL_SSH, 'ssh'), (PROTOCOL_RDP, 'rdp'), (PROTOCOL_TELNET, 'telnet'), (PROTOCOL_VNC, 'vnc'), (PROTOCOL_MYSQL, 'mysql'), + (PROTOCOL_K8S, 'k8s'), ) LOGIN_AUTO = 'auto' @@ -118,6 +120,7 @@ class SystemUser(BaseUser): login_mode = models.CharField(choices=LOGIN_MODE_CHOICES, default=LOGIN_AUTO, max_length=10, verbose_name=_('Login mode')) cmd_filters = models.ManyToManyField('CommandFilter', related_name='system_users', verbose_name=_("Command filter"), blank=True) sftp_root = models.CharField(default='tmp', max_length=128, verbose_name=_("SFTP Root")) + token = models.TextField(default='', verbose_name=_('Token')) _prefer = 'system_user' def __str__(self): diff --git a/apps/assets/serializers/system_user.py b/apps/assets/serializers/system_user.py index 7f3ad5372..1f2a05867 100644 --- a/apps/assets/serializers/system_user.py +++ b/apps/assets/serializers/system_user.py @@ -33,13 +33,14 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): 'login_mode', 'login_mode_display', 'priority', 'username_same_with_user', 'auto_push', 'cmd_filters', 'sudo', 'shell', 'comment', - 'auto_generate_key', 'sftp_root', + 'auto_generate_key', 'sftp_root', 'token', 'assets_amount', 'date_created', 'created_by' ] extra_kwargs = { 'password': {"write_only": True}, 'public_key': {"write_only": True}, 'private_key': {"write_only": True}, + 'token': {"write_only": True}, 'nodes_amount': {'label': _('Node')}, 'assets_amount': {'label': _('Asset')}, 'login_mode_display': {'label': _('Login mode display')}, @@ -169,7 +170,7 @@ class SystemUserWithAuthInfoSerializer(SystemUserSerializer): 'login_mode', 'login_mode_display', 'priority', 'username_same_with_user', 'auto_push', 'sudo', 'shell', 'comment', - 'auto_generate_key', 'sftp_root', + 'auto_generate_key', 'sftp_root', 'token' ] extra_kwargs = { 'nodes_amount': {'label': _('Node')}, diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 70a1cb7e6a2a57ee6f9fef158505be694af3221c..27d124dbad066e7c581997b82e21ae13c5acb293 100644 GIT binary patch delta 16271 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 delta 16179 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/k8s-apps/', api.UserGrantedK8sAppsApi.as_view(), name='user-k8s-apps'), + path('k8s-apps/', api.UserGrantedK8sAppsApi.as_view(), name='my-k8s-apps'), + + # k8sApps as tree + path('/k8s-apps/tree/', api.UserGrantedK8sAppsAsTreeApi.as_view(), name='user-k8ss-apps-tree'), + path('k8s-apps/tree/', api.UserGrantedK8sAppsAsTreeApi.as_view(), name='my-k8ss-apps-tree'), + + path('/k8s-apps//system-users/', api.UserGrantedK8sAppSystemUsersApi.as_view(), name='user-k8s-app-system-users'), + path('k8s-apps//system-users/', api.UserGrantedK8sAppSystemUsersApi.as_view(), name='user-k8s-app-system-users'), +] + +user_group_permission_urlpatterns = [ + path('/k8s-apps/', api.UserGroupGrantedK8sAppsApi.as_view(), name='user-group-k8s-apps'), +] + +permission_urlpatterns = [ + path('/users/all/', api.K8sAppPermissionAllUserListApi.as_view(), name='k8s-app-permission-all-users'), + path('/k8s-apps/all/', api.K8sAppPermissionAllK8sAppListApi.as_view(), name='k8s-app-permission-all-k8s-apps'), + + path('user/validate/', api.ValidateUserK8sAppPermissionApi.as_view(), name='validate-user-k8s-app-permission'), +] + +k8s_app_permission_urlpatterns = [ + path('users/', include(user_permission_urlpatterns)), + path('user-groups/', include(user_group_permission_urlpatterns)), + path('k8s-app-permissions/', include(permission_urlpatterns)) +] + +k8s_app_permission_urlpatterns += router.urls diff --git a/apps/perms/utils/__init__.py b/apps/perms/utils/__init__.py index c6581b858..35e29adb6 100644 --- a/apps/perms/utils/__init__.py +++ b/apps/perms/utils/__init__.py @@ -4,3 +4,4 @@ from .asset_permission import * from .remote_app_permission import * from .database_app_permission import * +from .k8s_app_permission import * \ No newline at end of file diff --git a/apps/perms/utils/k8s_app_permission.py b/apps/perms/utils/k8s_app_permission.py new file mode 100644 index 000000000..578fa6380 --- /dev/null +++ b/apps/perms/utils/k8s_app_permission.py @@ -0,0 +1,93 @@ +# coding: utf-8 +# + +from django.utils.translation import ugettext as _ +from django.db.models import Q + +from orgs.utils import set_to_root_org +from ..models import K8sAppPermission +from common.tree import TreeNode +from applications.models import K8sApp +from assets.models import SystemUser + + +def get_user_k8s_app_permissions(user, include_group=True): + if include_group: + groups = user.groups.all() + arg = Q(users=user) | Q(user_groups__in=groups) + else: + arg = Q(users=user) + return K8sAppPermission.objects.all().valid().filter(arg) + + +def get_user_group_k8s_app_permission(user_group): + return K8sAppPermission.objects.all().valid().filter( + user_groups=user_group + ) + + +class K8sAppPermissionUtil: + get_permissions_map = { + 'User': get_user_k8s_app_permissions, + 'UserGroup': get_user_group_k8s_app_permission + } + + def __init__(self, obj): + self.object = obj + self.change_org_if_need() + + @staticmethod + def change_org_if_need(): + set_to_root_org() + + @property + def permissions(self): + obj_class = self.object.__class__.__name__ + func = self.get_permissions_map[obj_class] + _permissions = func(self.object) + return _permissions + + def get_k8s_apps(self): + k8s_apps = K8sApp.objects.filter( + granted_by_permissions__in=self.permissions + ).distinct() + return k8s_apps + + def get_k8s_app_system_users(self, k8s_app): + queryset = self.permissions + kwargs = {'k8s_apps': k8s_app} + queryset = queryset.filter(**kwargs) + system_users_ids = queryset.values_list('system_users', flat=True) + system_users_ids = system_users_ids.distinct() + system_users = SystemUser.objects.filter(id__in=system_users_ids) + system_users = system_users.order_by('-priority') + return system_users + + +def construct_k8s_apps_tree_root(): + tree_root = { + 'id': 'ID_K8S_APP_ROOT', + 'name': _('KubernetesApp'), + 'title': 'K8sApp', + 'pId': '', + 'open': False, + 'isParent': True, + 'iconSkin': '', + 'meta': {'type': 'k8s_app'} + } + return TreeNode(**tree_root) + + +def parse_k8s_app_to_tree_node(parent, k8s_app): + pid = parent.id if parent else '' + tree_node = { + 'id': k8s_app.id, + 'name': k8s_app.name, + 'title': k8s_app.name, + 'pId': pid, + 'open': False, + 'isParent': False, + 'iconSkin': 'file', + 'meta': {'type': 'k8s_app'} + } + return TreeNode(**tree_node) diff --git a/apps/terminal/migrations/0025_auto_20200810_1735.py b/apps/terminal/migrations/0025_auto_20200810_1735.py new file mode 100644 index 000000000..96a06915c --- /dev/null +++ b/apps/terminal/migrations/0025_auto_20200810_1735.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.13 on 2020-08-10 09:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('terminal', '0024_auto_20200715_1713'), + ] + + operations = [ + migrations.AlterField( + model_name='session', + name='protocol', + field=models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('vnc', 'vnc'), ('telnet', 'telnet'), ('mysql', 'mysql'), ('k8s', 'kubernetes')], db_index=True, default='ssh', max_length=8), + ), + ] diff --git a/apps/terminal/models.py b/apps/terminal/models.py index f3914cc1c..ba43d131a 100644 --- a/apps/terminal/models.py +++ b/apps/terminal/models.py @@ -179,6 +179,7 @@ class Session(OrgModelMixin): ('vnc', 'vnc'), ('telnet', 'telnet'), ('mysql', 'mysql'), + ('k8s', 'kubernetes') ) id = models.UUIDField(default=uuid.uuid4, primary_key=True)