From dbdb8a58fed770d7146fd8c9ab702c9709b4caa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B3=E4=B9=A6=E5=83=AE?= <343306138@qq.com> Date: Fri, 6 Jan 2017 20:34:24 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B5=84=E4=BA=A7=E7=9B=B8=E5=85=B3API?= =?UTF-8?q?=E5=8F=8AWeb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api.py | 183 ++- apps/assets/forms.py | 502 +++---- apps/assets/models.py | 28 +- apps/assets/serializers.py | 206 ++- .../assets/_asset_bulk_update_modal.html | 80 +- .../_asset_group_bulk_update_modal.html | 42 + .../templates/assets/admin_user_detail.html | 234 ++- .../templates/assets/admin_user_list.html | 76 + .../assets/templates/assets/asset_detail.html | 9 +- .../templates/assets/asset_group_detail.html | 326 ++++- .../templates/assets/asset_group_list.html | 138 +- apps/assets/templates/assets/asset_list.html | 319 +++-- .../templates/assets/asset_tag_detail.html | 244 ++-- .../templates/assets/asset_tags_list.html | 174 ++- apps/assets/templates/assets/idc_assets.html | 298 +++- apps/assets/templates/assets/idc_detail.html | 69 +- apps/assets/templates/assets/idc_list.html | 88 +- .../templates/assets/system_user_asset.html | 284 +++- .../templates/assets/system_user_list.html | 121 +- apps/assets/urls/api_urls.py | 27 +- apps/assets/views.py | 1272 +++++++++-------- 21 files changed, 3190 insertions(+), 1530 deletions(-) create mode 100644 apps/assets/templates/assets/_asset_group_bulk_update_modal.html diff --git a/apps/assets/api.py b/apps/assets/api.py index e96f1cdab..38451f8cb 100644 --- a/apps/assets/api.py +++ b/apps/assets/api.py @@ -3,66 +3,106 @@ from rest_framework import viewsets, generics, mixins from rest_framework.response import Response from rest_framework.views import APIView +from rest_framework_bulk import BulkModelViewSet, BulkDestroyAPIView +from django_filters.rest_framework import DjangoFilterBackend from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin, ListBulkCreateUpdateDestroyAPIView from django.shortcuts import get_object_or_404 from common.mixins import IDInFilterMixin from common.utils import get_object_or_none, signer from .hands import IsSuperUserOrTerminalUser, IsSuperUser -from .models import AssetGroup, Asset, IDC, SystemUser, AdminUser +from .models import AssetGroup, Asset, IDC, SystemUser, AdminUser, Tag from . import serializers -class AssetViewSet(IDInFilterMixin, viewsets.ModelViewSet): - """API endpoint that allows Asset to be viewed or edited.""" - queryset = Asset.objects.all() - serializer_class = serializers.AssetSerializer - filter_fields = ('id', 'ip', 'hostname') +class AssetViewSet(IDInFilterMixin, BulkModelViewSet): + """API endpoint that allows Asset to be viewed or edited.""" + queryset = Asset.objects.all() + serializer_class = serializers.AssetSerializer + filter_backends = (DjangoFilterBackend,) + filter_fields = ('id', 'ip', 'hostname') + permission_classes = (IsSuperUser,) - def get_queryset(self): - queryset = super(AssetViewSet, self).get_queryset() - idc_id = self.request.query_params.get('idc_id', '') - asset_group_id = self.request.query_params.get('asset_group_id', '') - if idc_id: - queryset = queryset.filter(idc__id=idc_id) - - if asset_group_id: - queryset = queryset.filter(groups__id=asset_group_id) - return queryset + def get_queryset(self): + queryset = super(AssetViewSet, self).get_queryset() + idc_id = self.request.query_params.get('idc_id', '') + tags_id = self.request.query_params.get('tag_id', '') + system_users_id = self.request.query_params.get('system_user_id', '') + asset_group_id = self.request.query_params.get('asset_group_id', '') + admin_user_id = self.request.query_params.get('admin_user_id', '') + if idc_id: + queryset = queryset.filter(idc__id=idc_id) + if tags_id: + queryset = queryset.filter(tags__id=tags_id) + if system_users_id: + queryset = queryset.filter(system_users__id=system_users_id) + if admin_user_id: + queryset = queryset.filter(admin_user__id=admin_user_id) + if asset_group_id: + queryset = queryset.filter(groups__id=asset_group_id) + return queryset -class AssetGroupViewSet(viewsets.ModelViewSet): - """ API endpoint that allows AssetGroup to be viewed or edited. - some other comment - """ - queryset = AssetGroup.objects.all() - serializer_class = serializers.AssetGroupSerializer +class AssetGroupViewSet(IDInFilterMixin, BulkModelViewSet): + queryset = AssetGroup.objects.all() + serializer_class = serializers.AssetGroupSerializer + permission_classes = (IsSuperUser,) class AssetUpdateGroupApi(generics.RetrieveUpdateAPIView): - queryset = Asset.objects.all() - serializer_class = serializers.AssetUpdateGroupSerializer - permission_classes = (IsSuperUser,) + queryset = Asset.objects.all() + serializer_class = serializers.AssetUpdateGroupSerializer + permission_classes = (IsSuperUser,) -class IDCViewSet(viewsets.ModelViewSet): - """API endpoint that allows IDC to be viewed or edited.""" - queryset = IDC.objects.all() - serializer_class = serializers.IDCSerializer - permission_classes = (IsSuperUser,) +## update the asset group, and add or delete the asset to the group +class AssetGroupUpdateApi(generics.RetrieveUpdateAPIView): + queryset = AssetGroup.objects.all() + serializer_class = serializers.AssetGroupUpdateSerializer + permission_classes = (IsSuperUser,) -class AdminUserViewSet(viewsets.ModelViewSet): - queryset = AdminUser.objects.all() - serializer_class = serializers.AdminUserSerializer - permission_classes = (IsSuperUser,) +## update the asset group, and add or delete the system_user to the group +class AssetGroupUpdateSystemUserApi(generics.RetrieveUpdateAPIView): + queryset = AssetGroup.objects.all() + serializer_class = serializers.AssetGroupUpdateSystemUserSerializer + permission_classes = (IsSuperUser,) + +## update the IDC, and add or delete the assets to the IDC +class IDCupdateAssetsApi(generics.RetrieveUpdateAPIView): + queryset = IDC.objects.all() + serializer_class = serializers.IDCUpdateAssetsSerializer + permission_classes = (IsSuperUser,) + +class IDCViewSet(IDInFilterMixin, BulkModelViewSet): + """API endpoint that allows IDC to be viewed or edited.""" + queryset = IDC.objects.all() + serializer_class = serializers.IDCSerializer + permission_classes = (IsSuperUser,) + +class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet): + queryset = AdminUser.objects.all() + serializer_class = serializers.AdminUserSerializer + permission_classes = (IsSuperUser,) + + +class SystemUserViewSet(IDInFilterMixin, BulkModelViewSet): + queryset = SystemUser.objects.all() + serializer_class = serializers.SystemUserSerializer + permission_classes = (IsSuperUser,) -class SystemUserViewSet(viewsets.ModelViewSet): - queryset = SystemUser.objects.all() - serializer_class = serializers.SystemUserSerializer - permission_classes = (IsSuperUser,) class SystemUserUpdateApi(generics.RetrieveUpdateAPIView): - queryset = Asset.objects.all() - serializer_class = serializers.AssetUpdateSystemUserSerializer - permission_classes = (IsSuperUser,) + queryset = Asset.objects.all() + serializer_class = serializers.AssetUpdateSystemUserSerializer + permission_classes = (IsSuperUser,) + +class SystemUserUpdateAssetsApi(generics.RetrieveUpdateAPIView): + queryset = SystemUser.objects.all() + serializer_class = serializers.SystemUserUpdateAssetsSerializer + permission_classes = (IsSuperUser,) + +class SystemUserUpdateAssetGroupApi(generics.RetrieveUpdateAPIView): + queryset = SystemUser.objects.all() + serializer_class = serializers.SystemUserUpdateAssetGroupSerializer + permission_classes = (IsSuperUser,) # class IDCAssetsApi(generics.ListAPIView): @@ -79,39 +119,50 @@ class SystemUserUpdateApi(generics.RetrieveUpdateAPIView): class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView): - queryset = Asset.objects.all() - serializer_class = serializers.AssetSerializer - permission_classes = (IsSuperUser,) + queryset = Asset.objects.all() + serializer_class = serializers.AssetSerializer + permission_classes = (IsSuperUser,) class SystemUserAuthApi(APIView): - permission_classes = (IsSuperUserOrTerminalUser,) + permission_classes = (IsSuperUserOrTerminalUser,) - def get(self, request, *args, **kwargs): - system_user_id = request.query_params.get('system_user_id', -1) - system_user_username = request.query_params.get('system_user_username', '') + def get(self, request, *args, **kwargs): + system_user_id = request.query_params.get('system_user_id', -1) + system_user_username = request.query_params.get('system_user_username', '') - system_user = get_object_or_none(SystemUser, id=system_user_id, username=system_user_username) + system_user = get_object_or_none(SystemUser, id=system_user_id, username=system_user_username) - if system_user: - if system_user.password: - password = signer.sign(system_user.password) - else: - password = signer.sign('') + if system_user: + if system_user.password: + password = signer.sign(system_user.password) + else: + password = signer.sign('') - if system_user.private_key: - private_key = signer.sign(system_user.private_key) - else: - private_key = signer.sign(None) + if system_user.private_key: + private_key = signer.sign(system_user.private_key) + else: + private_key = signer.sign(None) - response = { - 'id': system_user.id, - 'password': password, - 'private_key': private_key, - } + response = { + 'id': system_user.id, + 'password': password, + 'private_key': private_key, + } - return Response(response) - else: - return Response({'msg': 'error system user id or username'}, status=401) + return Response(response) + else: + return Response({'msg': 'error system user id or username'}, status=401) +class TagViewSet(IDInFilterMixin, BulkModelViewSet): + queryset = Tag.objects.all() + serializer_class = serializers.TagSerializer + permission_classes = (IsSuperUser,) + +## update the IDC, and add or delete the assets to the IDC +class TagUpdateAssetsApi(generics.RetrieveUpdateAPIView): + queryset = Tag.objects.all() + serializer_class = serializers.TagUpdateAssetsSerializer + permission_classes = (IsSuperUser,) + diff --git a/apps/assets/forms.py b/apps/assets/forms.py index aeb7062cb..677b9c4e5 100644 --- a/apps/assets/forms.py +++ b/apps/assets/forms.py @@ -20,297 +20,305 @@ from common.utils import validate_ssh_private_key, ssh_pubkey_gen # 'groups': forms.SelectMultiple(attrs={'class': 'select2-groups', 'data-placeholder': _('Select asset groups')}), # 'system_user': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}), # 'admin_user': forms.SelectMultiple(attrs={'class': 'select2-admin-user', 'data-placeholder': _('Select asset admin user')}), - # } + # } # class AssetCreateForm(forms.ModelForm): - def __init__(self, *args, **kwargs): - instance = kwargs.get('instance', None) - if instance: - initial = kwargs.get('initial', {}) - initial['tags'] = [t.pk for t in kwargs['instance'].tags.all()] - super(AssetCreateForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + instance = kwargs.get('instance', None) + if instance: + initial = kwargs.get('initial', {}) + initial['tags'] = [t.pk for t in kwargs['instance'].tags.all()] + super(AssetCreateForm, self).__init__(*args, **kwargs) - def _save_m2m(self): - super(AssetCreateForm, self)._save_m2m() - tags = self.cleaned_data['tags'] - self.instance.tags.clear() - self.instance.tags.add(*tuple(tags)) + def _save_m2m(self): + super(AssetCreateForm, self)._save_m2m() + tags = self.cleaned_data['tags'] + self.instance.tags.clear() + self.instance.tags.add(*tuple(tags)) - class Meta: - model = Asset - tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all()) - fields = [ - 'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'system_users', 'idc', 'groups', - 'other_ip', 'remote_card_ip', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no', - 'cabinet_pos', 'number', 'status', 'env', 'sn', 'tags', - ] - widgets = { - 'groups': forms.SelectMultiple(attrs={'class': 'select2', - 'data-placeholder': _('Select asset groups')}), - 'tags': forms.SelectMultiple(attrs={'class': 'select2', - 'data-placeholder': _('Select asset tags')}), - 'system_users': forms.SelectMultiple(attrs={'class': 'select2', - 'data-placeholder': _('Select asset system users')}), - 'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}), - } - help_texts = { - 'hostname': '* required', - 'ip': '* required', - 'system_users': _('System user will be granted for user to login assets (using ansible create automatic)'), - 'admin_user': _('Admin user should be exist on asset already, And have sudo ALL permission'), - 'tags': '最多5个标签,单个标签最长8个汉字,按回车确认' - } + def clean(self): + clean_data = super(AssetCreateForm, self).clean() + ip = clean_data.get('ip') + port = clean_data.get('port') + query = Asset.objects.filter(ip=ip, port=port) + if query: + raise forms.ValidationError('this asset has exists.') + + class Meta: + model = Asset + tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all()) + fields = [ + 'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'system_users', 'idc', 'groups', + 'other_ip', 'remote_card_ip', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no', + 'cabinet_pos', 'number', 'status', 'env', 'sn', 'tags', + ] + widgets = { + 'groups': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select asset groups')}), + 'tags': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select asset tags')}), + 'system_users': forms.SelectMultiple(attrs={'class': 'select2', + 'data-placeholder': _('Select asset system users')}), + 'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}), + } + help_texts = { + 'hostname': '* required', + 'ip': '* required', + 'system_users': _('System user will be granted for user to login assets (using ansible create automatic)'), + 'admin_user': _('Admin user should be exist on asset already, And have sudo ALL permission'), + 'tags': '最多5个标签,单个标签最长8个汉字,按回车确认' + } class AssetGroupForm(forms.ModelForm): - # See AdminUserForm comment same it - assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), - label=_('Asset'), - required=False, - widget=forms.SelectMultiple( - attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) - ) + # See AdminUserForm comment same it + assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) - def __init__(self, *args, **kwargs): - if kwargs.get('instance', None): - initial = kwargs.get('initial', {}) - initial['assets'] = kwargs['instance'].assets.all() - super(AssetGroupForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + if kwargs.get('instance', None): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].assets.all() + super(AssetGroupForm, self).__init__(*args, **kwargs) - def _save_m2m(self): - super(AssetGroupForm, self)._save_m2m() - assets = self.cleaned_data['assets'] - self.instance.assets.clear() - self.instance.assets.add(*tuple(assets)) + def _save_m2m(self): + super(AssetGroupForm, self)._save_m2m() + assets = self.cleaned_data['assets'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) - class Meta: - model = AssetGroup - fields = [ - "name", "comment","system_users", - ] - widgets = { - 'name' : forms.TextInput(attrs={}), - 'system_users': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}), + class Meta: + model = AssetGroup + fields = [ + "name", "comment","system_users", + ] + widgets = { + 'name' : forms.TextInput(attrs={}), + 'system_users': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}), - } - help_texts = { - 'name': '* required', - } + } + help_texts = { + 'name': '* required', + } class IDCForm(forms.ModelForm): - # See AdminUserForm comment same it - assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), - label=_('Asset'), - required=False, - widget=forms.SelectMultiple( - attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) - ) + # See AdminUserForm comment same it + assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) - def __init__(self, *args, **kwargs): - if kwargs.get('instance'): - initial = kwargs.get('initial', {}) - initial['assets'] = kwargs['instance'].assets.all() - super(IDCForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + if kwargs.get('instance'): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].assets.all() + super(IDCForm, self).__init__(*args, **kwargs) - def _save_m2m(self): - super(IDCForm, self)._save_m2m() - assets = self.cleaned_data['assets'] - self.instance.assets.clear() - self.instance.assets.add(*tuple(assets)) + def _save_m2m(self): + super(IDCForm, self)._save_m2m() + assets = self.cleaned_data['assets'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) - class Meta: - model = IDC - fields = ['name', "bandwidth", "operator", 'contact', 'phone', 'address', 'intranet', 'extranet','comment'] - widgets = { - 'name': forms.TextInput(attrs={'placeholder': _('Name')}), - 'intranet': forms.Textarea( - attrs={'placeholder': 'IP段之间用逗号隔开,如:192.168.1.0/24,192.168.1.0/24'}), - 'extranet': forms.Textarea( - attrs={'placeholder': 'IP段之间用逗号隔开,如:201.1.32.1/24,202.2.32.1/24'}) - } + class Meta: + model = IDC + fields = ['name', "bandwidth", "operator", 'contact', 'phone', 'address', 'intranet', 'extranet','comment'] + widgets = { + 'name': forms.TextInput(attrs={'placeholder': _('Name')}), + 'intranet': forms.Textarea( + attrs={'placeholder': 'IP段之间用逗号隔开,如:192.168.1.0/24,192.168.1.0/24'}), + 'extranet': forms.Textarea( + attrs={'placeholder': 'IP段之间用逗号隔开,如:201.1.32.1/24,202.2.32.1/24'}) + } class AdminUserForm(forms.ModelForm): - # Admin user assets define, let user select, save it in form not in view - assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), - label=_('Asset'), - required=False, - widget=forms.SelectMultiple( - attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) - ) - # Form field name can not start with `_`, so redefine it, - password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True, - help_text=_('If also set private key, use that first'), required=False) - # Need use upload private key file except paste private key content - private_key_file = forms.FileField(required=False) + # Admin user assets define, let user select, save it in form not in view + assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) + # Form field name can not start with `_`, so redefine it, + password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True, + help_text=_('If also set private key, use that first'), required=False) + # Need use upload private key file except paste private key content + private_key_file = forms.FileField(required=False) - def __init__(self, *args, **kwargs): - # When update a admin user instance, initial it - if kwargs.get('instance'): - initial = kwargs.get('initial', {}) - initial['assets'] = kwargs['instance'].assets.all() - super(AdminUserForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + # When update a admin user instance, initial it + if kwargs.get('instance'): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].assets.all() + super(AdminUserForm, self).__init__(*args, **kwargs) - def _save_m2m(self): - # Save assets relation with admin user - super(AdminUserForm, self)._save_m2m() - assets = self.cleaned_data['assets'] - self.instance.assets.clear() - self.instance.assets.add(*tuple(assets)) + def _save_m2m(self): + # Save assets relation with admin user + super(AdminUserForm, self)._save_m2m() + assets = self.cleaned_data['assets'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) - def save(self, commit=True): - # Because we define custom field, so we need rewrite :method: `save` - admin_user = super(AdminUserForm, self).save(commit=commit) - password = self.cleaned_data['password'] - private_key = self.cleaned_data['private_key_file'] - public_key = ssh_pubkey_gen(private_key) + def save(self, commit=True): + # Because we define custom field, so we need rewrite :method: `save` + admin_user = super(AdminUserForm, self).save(commit=commit) + password = self.cleaned_data['password'] + private_key = self.cleaned_data['private_key_file'] + public_key = ssh_pubkey_gen(private_key) - if password: - admin_user.password = password - if private_key: - admin_user.private_key = private_key - admin_user.public_key = public_key - admin_user.save() - return admin_user + if password: + admin_user.password = password + if private_key: + admin_user.private_key = private_key + admin_user.public_key = public_key + admin_user.save() + return admin_user - def clean_private_key_file(self): - private_key_file = self.cleaned_data['private_key_file'] - if private_key_file: - private_key = private_key_file.read() - if not validate_ssh_private_key(private_key): - raise forms.ValidationError(_('Invalid private key')) - return private_key - return private_key_file + def clean_private_key_file(self): + private_key_file = self.cleaned_data['private_key_file'] + if private_key_file: + private_key = private_key_file.read() + if not validate_ssh_private_key(private_key): + raise forms.ValidationError(_('Invalid private key')) + return private_key + return private_key_file - def clean(self): - password = self.cleaned_data['password'] - private_key_file = self.cleaned_data.get('private_key_file', '') + def clean(self): + password = self.cleaned_data['password'] + private_key_file = self.cleaned_data.get('private_key_file', '') - if not (password or private_key_file): - raise forms.ValidationError(_('Password and private key file must be input one')) + if not (password or private_key_file): + raise forms.ValidationError(_('Password and private key file must be input one')) - class Meta: - model = AdminUser - fields = ['name', 'username', 'password', 'private_key_file', 'comment'] - widgets = { - 'name': forms.TextInput(attrs={'placeholder': _('Name')}), - 'username': forms.TextInput(attrs={'placeholder': _('Username')}), - } - help_texts = { - 'name': '* required', - 'username': '* required', - } + class Meta: + model = AdminUser + fields = ['name', 'username', 'password', 'private_key_file', 'comment'] + widgets = { + 'name': forms.TextInput(attrs={'placeholder': _('Name')}), + 'username': forms.TextInput(attrs={'placeholder': _('Username')}), + } + help_texts = { + 'name': '* required', + 'username': '* required', + } class SystemUserForm(forms.ModelForm): - # Admin user assets define, let user select, save it in form not in view - assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), - label=_('Asset'), - required=False, - widget=forms.SelectMultiple( - attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) - ) - asset_groups = forms.ModelMultipleChoiceField(queryset=AssetGroup.objects.all(), - label=_('Asset group'), - required=False, - widget=forms.SelectMultiple( - attrs={'class': 'select2', - 'data-placeholder': _('Select asset groups')}) - ) - auto_generate_key = forms.BooleanField(initial=True) - # Form field name can not start with `_`, so redefine it, - password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True, - help_text=_('If also set private key, use that first'), required=False) - # Need use upload private key file except paste private key content - private_key_file = forms.FileField(required=False) + # Admin user assets define, let user select, save it in form not in view + assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) + asset_groups = forms.ModelMultipleChoiceField(queryset=AssetGroup.objects.all(), + label=_('Asset group'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', + 'data-placeholder': _('Select asset groups')}) + ) + auto_generate_key = forms.BooleanField(initial=True) + # Form field name can not start with `_`, so redefine it, + password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True, + help_text=_('If also set private key, use that first'), required=False) + # Need use upload private key file except paste private key content + private_key_file = forms.FileField(required=False) - def __init__(self, *args, **kwargs): - # When update a admin user instance, initial it - if kwargs.get('instance'): - initial = kwargs.get('initial', {}) - initial['assets'] = kwargs['instance'].assets.all() - initial['asset_groups'] = kwargs['instance'].asset_groups.all() - super(SystemUserForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + # When update a admin user instance, initial it + if kwargs.get('instance'): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].assets.all() + initial['asset_groups'] = kwargs['instance'].asset_groups.all() + super(SystemUserForm, self).__init__(*args, **kwargs) - def _save_m2m(self): - # Save assets relation with admin user - super(SystemUserForm, self)._save_m2m() - assets = self.cleaned_data['assets'] - asset_groups = self.cleaned_data['asset_groups'] - self.instance.assets.clear() - self.instance.assets.add(*tuple(assets)) - self.instance.asset_groups.clear() - self.instance.asset_groups.add(*tuple(asset_groups)) + def _save_m2m(self): + # Save assets relation with admin user + super(SystemUserForm, self)._save_m2m() + assets = self.cleaned_data['assets'] + asset_groups = self.cleaned_data['asset_groups'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) + self.instance.asset_groups.clear() + self.instance.asset_groups.add(*tuple(asset_groups)) - def save(self, commit=True): - # Because we define custom field, so we need rewrite :method: `save` - system_user = super(SystemUserForm, self).save(commit=commit) - password = self.cleaned_data['password'] - private_key_file = self.cleaned_data['private_key_file'] + def save(self, commit=True): + # Because we define custom field, so we need rewrite :method: `save` + system_user = super(SystemUserForm, self).save(commit=commit) + password = self.cleaned_data['password'] + private_key_file = self.cleaned_data['private_key_file'] - if password: - system_user.password = password - print(password) - # Todo: Validate private key file, and generate public key - # Todo: Auto generate private key and public key - if private_key_file: - system_user.private_key = private_key_file.read().strip() - system_user.save() - return self.instance + if password: + system_user.password = password + print(password) + # Todo: Validate private key file, and generate public key + # Todo: Auto generate private key and public key + if private_key_file: + system_user.private_key = private_key_file.read().strip() + system_user.save() + return self.instance - class Meta: - model = SystemUser - fields = [ - 'name', 'username', 'protocol', 'auto_generate_key', 'password', 'private_key_file', 'as_default', - 'auto_push', 'auto_update', 'sudo', 'comment', 'shell', 'home', 'uid', - ] - widgets = { - 'name': forms.TextInput(attrs={'placeholder': _('Name')}), - 'username': forms.TextInput(attrs={'placeholder': _('Username')}), - } - help_texts = { - 'name': '* required', - 'username': '* required', - 'auth_push': 'Auto push system user to asset', - 'auth_update': 'Auto update system user ssh key', - } + class Meta: + model = SystemUser + fields = [ + 'name', 'username', 'protocol', 'auto_generate_key', 'password', 'private_key_file', 'as_default', + 'auto_push', 'auto_update', 'sudo', 'comment', 'shell', 'home', 'uid', + ] + widgets = { + 'name': forms.TextInput(attrs={'placeholder': _('Name')}), + 'username': forms.TextInput(attrs={'placeholder': _('Username')}), + } + help_texts = { + 'name': '* required', + 'username': '* required', + 'auth_push': 'Auto push system user to asset', + 'auth_update': 'Auto update system user ssh key', + } class AssetTagForm(forms.ModelForm): - assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), - label=_('Asset'), - required=False, - widget=forms.SelectMultiple( - attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) - ) + assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(), + label=_('Asset'), + required=False, + widget=forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + ) - def __init__(self, *args, **kwargs): - if kwargs.get('instance', None): - initial = kwargs.get('initial', {}) - initial['assets'] = kwargs['instance'].asset_set.all() - super(AssetTagForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + if kwargs.get('instance', None): + initial = kwargs.get('initial', {}) + initial['assets'] = kwargs['instance'].asset_set.all() + super(AssetTagForm, self).__init__(*args, **kwargs) - def _save_m2m(self): - super(AssetTagForm, self)._save_m2m() - assets = self.cleaned_data['assets'] - self.instance.asset_set.clear() - self.instance.asset_set.add(*tuple(assets)) + def _save_m2m(self): + assets = self.cleaned_data['assets'] + self.instance.assets.clear() + self.instance.assets.add(*tuple(assets)) + super(AssetTagForm, self)._save_m2m() - class Meta: - model = Tag - fields = [ - "name", - ] - widgets = { - 'name' : forms.TextInput(attrs={}), + class Meta: + model = Tag + fields = [ + "name", + ] + widgets = { + 'name' : forms.TextInput(attrs={}), - } - help_texts = { - 'name': '* required', - } + } + help_texts = { + 'name': '* required', + } class FileForm(forms.Form): - file = forms.FileField() \ No newline at end of file + file = forms.FileField() \ No newline at end of file diff --git a/apps/assets/models.py b/apps/assets/models.py index aa22a2f02..7cd025946 100644 --- a/apps/assets/models.py +++ b/apps/assets/models.py @@ -269,6 +269,19 @@ class AssetGroup(models.Model): def get_default_idc(): return IDC.initial() +class Tag(models.Model): + name = models.CharField(max_length=64, unique=True, verbose_name=_('Name')) + created_time = models.DateTimeField(auto_now_add=True, verbose_name=_('Create time')) + created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by')) + + def __unicode__(self): + return self.name + + __str__ = __unicode__ + + class Meta: + db_table = 'tag' + class Asset(models.Model): STATUS_CHOICES = ( @@ -320,7 +333,7 @@ class Asset(models.Model): is_active = models.BooleanField(default=True, verbose_name=_('Is active')) date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date added')) comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) - tags = models.ManyToManyField('Tag', blank=True, verbose_name=_('Tags')) + tags = models.ManyToManyField(Tag, related_name='assets', blank=True, verbose_name=_('Tags')) def __unicode__(self): return '%(ip)s:%(port)s' % {'ip': self.ip, 'port': self.port} @@ -339,7 +352,7 @@ class Asset(models.Model): class Meta: db_table = 'asset' - unique_together = ('ip', 'port') + # unique_together = ('ip', 'port') @classmethod def generate_fake(cls, count=100): @@ -365,18 +378,7 @@ class Asset(models.Model): continue -class Tag(models.Model): - name = models.CharField(max_length=64, unique=True, verbose_name=_('Name')) - created_time = models.DateTimeField(auto_now_add=True, verbose_name=_('Create time')) - created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by')) - def __unicode__(self): - return self.name - - __str__ = __unicode__ - - class Meta: - db_table = 'tag' def init_all_models(): diff --git a/apps/assets/serializers.py b/apps/assets/serializers.py index 6e6353a86..d99f3eb56 100644 --- a/apps/assets/serializers.py +++ b/apps/assets/serializers.py @@ -1,112 +1,172 @@ # -*- coding: utf-8 -*- from django.utils.translation import ugettext_lazy as _ from rest_framework import viewsets, serializers,generics -from .models import AssetGroup, Asset, IDC, AdminUser, SystemUser +from .models import AssetGroup, Asset, IDC, AdminUser, SystemUser, Tag from common.mixins import IDInFilterMixin from rest_framework_bulk import BulkListSerializer, BulkSerializerMixin -class AssetGroupSerializer(serializers.ModelSerializer): - assets_amount = serializers.SerializerMethodField() - # assets = serializers.PrimaryKeyRelatedField(many=True, read_only=True) +class AssetGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer): + assets_amount = serializers.SerializerMethodField() + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) - class Meta: - model = AssetGroup + class Meta: + model = AssetGroup + list_serializer_class = BulkListSerializer - @staticmethod - def get_assets_amount(obj): - return obj.assets.count() + @staticmethod + def get_assets_amount(obj): + return obj.assets.count() class AssetUpdateGroupSerializer(serializers.ModelSerializer): - groups = serializers.PrimaryKeyRelatedField(many=True, queryset=AssetGroup.objects.all()) + groups = serializers.PrimaryKeyRelatedField(many=True, queryset=AssetGroup.objects.all()) - class Meta: - model = Asset - fields = ['id', 'groups'] + class Meta: + model = Asset + fields = ['id', 'groups'] class AssetUpdateSystemUserSerializer(serializers.ModelSerializer): - system_users = serializers.PrimaryKeyRelatedField(many=True, queryset=SystemUser.objects.all()) + system_users = serializers.PrimaryKeyRelatedField(many=True, queryset=SystemUser.objects.all()) + + class Meta: + model = Asset + fields = ['id', 'system_users'] + +## update the asset group, and add or delete the asset to the group +class AssetGroupUpdateSerializer(serializers.ModelSerializer): + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + class Meta: + model = AssetGroup + fields = ['id', 'assets'] + +## update the asset group, and add or delete the system_user to the group +class AssetGroupUpdateSystemUserSerializer(serializers.ModelSerializer): + system_users = serializers.PrimaryKeyRelatedField(many=True, queryset=SystemUser.objects.all()) + class Meta: + model = AssetGroup + fields = ['id', 'system_users'] + +## update the IDC, and add or delete the assets to the IDC +class IDCUpdateAssetsSerializer(serializers.ModelSerializer): + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + class Meta: + model = IDC + fields = ['id', 'assets'] + +## tags API +class TagSerializer(BulkSerializerMixin, serializers.ModelSerializer): + assets_amount = serializers.SerializerMethodField() + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = Tag + list_serializer_class = BulkListSerializer + + @staticmethod + def get_assets_amount(obj): + return obj.assets.count() - class Meta: - model = Asset - fields = ['id', 'system_users'] class AdminUserSerializer(serializers.ModelSerializer): - class Meta: - model = AdminUser + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + class Meta: + model = AdminUser - def get_field_names(self, declared_fields, info): - fields = super(AdminUserSerializer, self).get_field_names(declared_fields, info) - fields.append('assets_amount') - return fields + def get_field_names(self, declared_fields, info): + fields = super(AdminUserSerializer, self).get_field_names(declared_fields, info) + fields.append('assets_amount') + return fields class SystemUserSerializer(serializers.ModelSerializer): - class Meta: - model = SystemUser - exclude = ('_password', '_private_key', '_public_key') + class Meta: + model = SystemUser + exclude = ('_password', '_private_key', '_public_key') - def get_field_names(self, declared_fields, info): - fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info) - fields.extend(['assets_amount']) - return fields + def get_field_names(self, declared_fields, info): + fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info) + fields.extend(['assets_amount']) + return fields + + +class SystemUserUpdateAssetsSerializer(serializers.ModelSerializer): + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + class Meta: + model = SystemUser + fields = ['id', 'assets'] + + +class SystemUserUpdateAssetGroupSerializer(serializers.ModelSerializer): + asset_groups = serializers.PrimaryKeyRelatedField(many=True, queryset=AssetGroup.objects.all()) + class Meta: + model = SystemUser + fields = ['id', 'asset_groups'] class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer): - # system_users = SystemUserSerializer(many=True, read_only=True) - # admin_user = AdminUserSerializer(many=False, read_only=True) - hardware = serializers.SerializerMethodField() + # system_users = SystemUserSerializer(many=True, read_only=True) + # admin_user = AdminUserSerializer(many=False, read_only=True) + hardware = serializers.SerializerMethodField() - class Meta(object): - model = Asset - list_serializer_class = BulkListSerializer + class Meta(object): + model = Asset + list_serializer_class = BulkListSerializer - @staticmethod - def get_hardware(obj): - if obj.cpu: - return '%s %s %s' % (obj.cpu, obj.memory, obj.disk) - else: - return '' + @staticmethod + def get_hardware(obj): + if obj.cpu: + return '%s %s %s' % (obj.cpu, obj.memory, obj.disk) + else: + return '' - def get_field_names(self, declared_fields, info): - fields = super(AssetSerializer, self).get_field_names(declared_fields, info) - fields.extend(['get_type_display', 'get_env_display']) - return fields + def get_field_names(self, declared_fields, info): + fields = super(AssetSerializer, self).get_field_names(declared_fields, info) + fields.extend(['get_type_display', 'get_env_display']) + return fields class AssetGrantedSerializer(serializers.ModelSerializer): - system_users = SystemUserSerializer(many=True, read_only=True) - is_inherited = serializers.SerializerMethodField() - system_users_join = serializers.SerializerMethodField() + system_users = SystemUserSerializer(many=True, read_only=True) + is_inherited = serializers.SerializerMethodField() + system_users_join = serializers.SerializerMethodField() - class Meta(object): - model = Asset - fields = ("id", "hostname", "ip", "port", "system_users", "is_inherited", - "is_active", "system_users_join", "comment") + class Meta(object): + model = Asset + fields = ("id", "hostname", "ip", "port", "system_users", "is_inherited", + "is_active", "system_users_join", "comment") - @staticmethod - def get_is_inherited(obj): - if getattr(obj, 'inherited', ''): - return True - else: - return False + @staticmethod + def get_is_inherited(obj): + if getattr(obj, 'inherited', ''): + return True + else: + return False - @staticmethod - def get_system_users_join(obj): - return ', '.join([system_user.username for system_user in obj.system_users.all()]) + @staticmethod + def get_system_users_join(obj): + return ', '.join([system_user.username for system_user in obj.system_users.all()]) -class IDCSerializer(serializers.ModelSerializer): - assets_amount = serializers.SerializerMethodField() +class IDCSerializer(BulkSerializerMixin, serializers.ModelSerializer): + assets_amount = serializers.SerializerMethodField() + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) - class Meta: - model = IDC + class Meta: + model = IDC - @staticmethod - def get_assets_amount(obj): - return obj.assets.count() + @staticmethod + def get_assets_amount(obj): + return obj.assets.count() - def get_field_names(self, declared_fields, info): - fields = super(IDCSerializer, self).get_field_names(declared_fields, info) - fields.append('assets_amount') - return fields + def get_field_names(self, declared_fields, info): + fields = super(IDCSerializer, self).get_field_names(declared_fields, info) + fields.append('assets_amount') + return fields + + +class TagUpdateAssetsSerializer(serializers.ModelSerializer): + assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + + class Meta: + model = Tag + fields = ['id', 'assets'] \ No newline at end of file diff --git a/apps/assets/templates/assets/_asset_bulk_update_modal.html b/apps/assets/templates/assets/_asset_bulk_update_modal.html index 35b74492f..391fc5361 100644 --- a/apps/assets/templates/assets/_asset_bulk_update_modal.html +++ b/apps/assets/templates/assets/_asset_bulk_update_modal.html @@ -6,30 +6,33 @@ {% block modal_body %} {% load bootstrap %}
{% trans "Hint: only change the field you want to update." %}
- -