mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-06-28 07:47:10 +00:00
commit
59927ffcd9
@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from orgs.mixins import OrgModelForm
|
from orgs.mixins import OrgModelForm
|
||||||
from assets.models import SystemUser, Protocol
|
from assets.models import SystemUser
|
||||||
|
|
||||||
from ..models import RemoteApp
|
from ..models import RemoteApp
|
||||||
from .. import const
|
from .. import const
|
||||||
@ -88,9 +88,7 @@ class RemoteAppCreateUpdateForm(RemoteAppTypeForms, OrgModelForm):
|
|||||||
# 过滤RDP资产和系统用户
|
# 过滤RDP资产和系统用户
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
field_asset = self.fields['asset']
|
field_asset = self.fields['asset']
|
||||||
field_asset.queryset = field_asset.queryset.filter(
|
field_asset.queryset = field_asset.queryset.has_protocol('rdp')
|
||||||
protocols__name=Protocol.PROTOCOL_RDP
|
|
||||||
)
|
|
||||||
field_system_user = self.fields['system_user']
|
field_system_user = self.fields['system_user']
|
||||||
field_system_user.queryset = field_system_user.queryset.filter(
|
field_system_user.queryset = field_system_user.queryset.filter(
|
||||||
protocol=SystemUser.PROTOCOL_RDP
|
protocol=SystemUser.PROTOCOL_RDP
|
||||||
|
@ -37,7 +37,7 @@ __all__ = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class AssetViewSet(LabelFilter, ApiMessageMixin, OrgBulkModelViewSet):
|
class AssetViewSet(LabelFilter, OrgBulkModelViewSet):
|
||||||
"""
|
"""
|
||||||
API endpoint that allows Asset to be viewed or edited.
|
API endpoint that allows Asset to be viewed or edited.
|
||||||
"""
|
"""
|
||||||
|
@ -130,7 +130,7 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
|
|||||||
include_assets = self.request.query_params.get('assets', '0') == '1'
|
include_assets = self.request.query_params.get('assets', '0') == '1'
|
||||||
if not include_assets:
|
if not include_assets:
|
||||||
return queryset
|
return queryset
|
||||||
assets = self.node.get_assets().prefetch_related("protocols").only(
|
assets = self.node.get_assets().only(
|
||||||
"id", "hostname", "ip", 'platform', "os", "org_id",
|
"id", "hostname", "ip", 'platform', "os", "org_id",
|
||||||
)
|
)
|
||||||
for asset in assets:
|
for asset in assets:
|
||||||
|
@ -6,33 +6,27 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from orgs.mixins import OrgModelForm
|
from orgs.mixins import OrgModelForm
|
||||||
|
|
||||||
from ..models import Asset, Protocol, Node
|
from ..models import Asset, Node
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AssetCreateForm', 'AssetUpdateForm', 'AssetBulkUpdateForm',
|
'AssetCreateForm', 'AssetUpdateForm', 'AssetBulkUpdateForm', 'ProtocolForm',
|
||||||
'ProtocolForm'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ProtocolForm(forms.ModelForm):
|
class ProtocolForm(forms.Form):
|
||||||
class Meta:
|
name = forms.ChoiceField(
|
||||||
model = Protocol
|
choices=Asset.PROTOCOL_CHOICES, label=_("Name"), initial='ssh',
|
||||||
fields = ['name', 'port']
|
widget=forms.Select(attrs={'class': 'form-control protocol-name'})
|
||||||
widgets = {
|
)
|
||||||
'name': forms.Select(attrs={
|
port = forms.IntegerField(
|
||||||
'class': 'form-control protocol-name'
|
max_value=65534, min_value=1, label=_("Port"), initial=22,
|
||||||
}),
|
widget=forms.TextInput(attrs={'class': 'form-control protocol-port'})
|
||||||
'port': forms.TextInput(attrs={
|
)
|
||||||
'class': 'form-control protocol-port'
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AssetCreateForm(OrgModelForm):
|
class AssetCreateForm(OrgModelForm):
|
||||||
PROTOCOL_CHOICES = Protocol.PROTOCOL_CHOICES
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if not self.data:
|
if not self.data:
|
||||||
|
@ -3,14 +3,6 @@
|
|||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
def migrate_assets_protocol(apps, schema_editor):
|
|
||||||
asset_model = apps.get_model("assets", "Asset")
|
|
||||||
db_alias = schema_editor.connection.alias
|
|
||||||
assets = asset_model.objects.using(db_alias).all()
|
|
||||||
for asset in assets:
|
|
||||||
asset.protocols.create(name=asset.protocol, port=asset.port)
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@ -18,5 +10,4 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunPython(migrate_assets_protocol),
|
|
||||||
]
|
]
|
||||||
|
39
apps/assets/migrations/0034_auto_20190705_1348.py
Normal file
39
apps/assets/migrations/0034_auto_20190705_1348.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Generated by Django 2.1.7 on 2019-07-05 05:48
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from django.db.models import F
|
||||||
|
from django.db.models import CharField, Value as V
|
||||||
|
from django.db.models.functions import Concat
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_assets_protocol(apps, schema_editor):
|
||||||
|
asset_model = apps.get_model("assets", "Asset")
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
assets = asset_model.objects.using(db_alias).all().annotate(
|
||||||
|
protocols_new=Concat(
|
||||||
|
'protocol', V('/'), 'port',
|
||||||
|
output_field=CharField(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assets.update(protocols=F('protocols_new'))
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0033_auto_20190624_2108'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='asset',
|
||||||
|
name='protocols',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='asset',
|
||||||
|
name='protocols',
|
||||||
|
field=CharField(blank=True, default='ssh/22', max_length=128, verbose_name='Protocols'),
|
||||||
|
),
|
||||||
|
migrations.RunPython(migrate_assets_protocol),
|
||||||
|
migrations.DeleteModel(name='Protocol'),
|
||||||
|
]
|
@ -6,16 +6,16 @@ import uuid
|
|||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
|
||||||
|
|
||||||
from .user import AdminUser, SystemUser
|
from .user import AdminUser, SystemUser
|
||||||
from .utils import Connectivity
|
from .utils import Connectivity
|
||||||
from orgs.mixins import OrgModelMixin, OrgManager
|
from orgs.mixins import OrgModelMixin, OrgManager
|
||||||
|
|
||||||
__all__ = ['Asset', 'Protocol']
|
__all__ = ['Asset']
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -45,8 +45,12 @@ class AssetQuerySet(models.QuerySet):
|
|||||||
def valid(self):
|
def valid(self):
|
||||||
return self.active()
|
return self.active()
|
||||||
|
|
||||||
|
def has_protocol(self, name):
|
||||||
|
return self.filter(protocols__contains=name)
|
||||||
|
|
||||||
class Protocol(models.Model):
|
|
||||||
|
class ProtocolsMixin:
|
||||||
|
protocols = ''
|
||||||
PROTOCOL_SSH = 'ssh'
|
PROTOCOL_SSH = 'ssh'
|
||||||
PROTOCOL_RDP = 'rdp'
|
PROTOCOL_RDP = 'rdp'
|
||||||
PROTOCOL_TELNET = 'telnet'
|
PROTOCOL_TELNET = 'telnet'
|
||||||
@ -57,19 +61,42 @@ class Protocol(models.Model):
|
|||||||
(PROTOCOL_TELNET, 'telnet (beta)'),
|
(PROTOCOL_TELNET, 'telnet (beta)'),
|
||||||
(PROTOCOL_VNC, 'vnc'),
|
(PROTOCOL_VNC, 'vnc'),
|
||||||
)
|
)
|
||||||
PORT_VALIDATORS = [MaxValueValidator(65535), MinValueValidator(1)]
|
|
||||||
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
@property
|
||||||
name = models.CharField(max_length=16, choices=PROTOCOL_CHOICES,
|
def protocols_as_list(self):
|
||||||
default=PROTOCOL_SSH, verbose_name=_("Name"))
|
if not self.protocols:
|
||||||
port = models.IntegerField(default=22, verbose_name=_("Port"),
|
return []
|
||||||
validators=PORT_VALIDATORS)
|
return self.protocols.split(' ')
|
||||||
|
|
||||||
def __str__(self):
|
@property
|
||||||
return "{}/{}".format(self.name, self.port)
|
def protocols_as_dict(self):
|
||||||
|
d = OrderedDict()
|
||||||
|
protocols = self.protocols_as_list
|
||||||
|
for i in protocols:
|
||||||
|
if '/' not in i:
|
||||||
|
continue
|
||||||
|
name, port = i.split('/')[:2]
|
||||||
|
if not all([name, port]):
|
||||||
|
continue
|
||||||
|
d[name] = int(port)
|
||||||
|
return d
|
||||||
|
|
||||||
|
@property
|
||||||
|
def protocols_as_json(self):
|
||||||
|
return [
|
||||||
|
{"name": name, "port": port}
|
||||||
|
for name, port in self.protocols_as_dict.items()
|
||||||
|
]
|
||||||
|
|
||||||
|
def has_protocol(self, name):
|
||||||
|
return name in self.protocols_as_dict
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ssh_port(self):
|
||||||
|
return self.protocols_as_dict.get("ssh", 22)
|
||||||
|
|
||||||
|
|
||||||
class Asset(OrgModelMixin):
|
class Asset(ProtocolsMixin, OrgModelMixin):
|
||||||
# Important
|
# Important
|
||||||
PLATFORM_CHOICES = (
|
PLATFORM_CHOICES = (
|
||||||
('Linux', 'Linux'),
|
('Linux', 'Linux'),
|
||||||
@ -84,12 +111,12 @@ class Asset(OrgModelMixin):
|
|||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
ip = models.CharField(max_length=128, verbose_name=_('IP'), db_index=True)
|
ip = models.CharField(max_length=128, verbose_name=_('IP'), db_index=True)
|
||||||
hostname = models.CharField(max_length=128, verbose_name=_('Hostname'))
|
hostname = models.CharField(max_length=128, verbose_name=_('Hostname'))
|
||||||
protocol = models.CharField(max_length=128, default=Protocol.PROTOCOL_SSH,
|
protocol = models.CharField(max_length=128, default=ProtocolsMixin.PROTOCOL_SSH,
|
||||||
choices=Protocol.PROTOCOL_CHOICES,
|
choices=ProtocolsMixin.PROTOCOL_CHOICES,
|
||||||
verbose_name=_('Protocol'))
|
verbose_name=_('Protocol'))
|
||||||
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
||||||
|
|
||||||
protocols = models.ManyToManyField('Protocol', verbose_name=_("Protocol"))
|
protocols = models.CharField(max_length=128, default='ssh/22', blank=True, verbose_name=_("Protocols"))
|
||||||
platform = models.CharField(max_length=128, choices=PLATFORM_CHOICES, default='Linux', verbose_name=_('Platform'))
|
platform = models.CharField(max_length=128, choices=PLATFORM_CHOICES, default='Linux', verbose_name=_('Platform'))
|
||||||
domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets', verbose_name=_("Domain"), on_delete=models.SET_NULL)
|
domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets', verbose_name=_("Domain"), on_delete=models.SET_NULL)
|
||||||
nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes"))
|
nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes"))
|
||||||
@ -136,41 +163,9 @@ class Asset(OrgModelMixin):
|
|||||||
warning = ''
|
warning = ''
|
||||||
if not self.is_active:
|
if not self.is_active:
|
||||||
warning += ' inactive'
|
warning += ' inactive'
|
||||||
else:
|
if warning:
|
||||||
return True, ''
|
|
||||||
return False, warning
|
return False, warning
|
||||||
|
return True, warning
|
||||||
@property
|
|
||||||
def protocols_name(self):
|
|
||||||
names = []
|
|
||||||
for protocol in self.protocols.all():
|
|
||||||
names.append(protocol.name)
|
|
||||||
return names
|
|
||||||
|
|
||||||
def has_protocol(self, name):
|
|
||||||
return name in self.protocols_name
|
|
||||||
|
|
||||||
def get_protocol_by_name(self, name):
|
|
||||||
for i in self.protocols.all():
|
|
||||||
if i.name.lower() == name.lower():
|
|
||||||
return i
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def protocol_ssh(self):
|
|
||||||
return self.get_protocol_by_name("ssh")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def protocol_rdp(self):
|
|
||||||
return self.get_protocol_by_name("rdp")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def ssh_port(self):
|
|
||||||
if self.protocol_ssh:
|
|
||||||
port = self.protocol_ssh.port
|
|
||||||
else:
|
|
||||||
port = 22
|
|
||||||
return port
|
|
||||||
|
|
||||||
def is_windows(self):
|
def is_windows(self):
|
||||||
if self.platform in ("Windows", "Windows2016"):
|
if self.platform in ("Windows", "Windows2016"):
|
||||||
@ -278,10 +273,7 @@ class Asset(OrgModelMixin):
|
|||||||
'id': self.id,
|
'id': self.id,
|
||||||
'hostname': self.hostname,
|
'hostname': self.hostname,
|
||||||
'ip': self.ip,
|
'ip': self.ip,
|
||||||
'protocols': [
|
'protocols': self.protocols_as_list,
|
||||||
{"name": p.name, "port": p.port}
|
|
||||||
for p in self.protocols.all()
|
|
||||||
],
|
|
||||||
'platform': self.platform,
|
'platform': self.platform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +306,7 @@ class Asset(OrgModelMixin):
|
|||||||
created_by='Fake')
|
created_by='Fake')
|
||||||
try:
|
try:
|
||||||
asset.save()
|
asset.save()
|
||||||
asset.protocols.create(name="ssh", port=22)
|
asset.protocols = 'ssh/22'
|
||||||
if nodes and len(nodes) > 3:
|
if nodes and len(nodes) > 3:
|
||||||
_nodes = random.sample(nodes, 3)
|
_nodes = random.sample(nodes, 3)
|
||||||
else:
|
else:
|
||||||
|
@ -1,48 +1,66 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.validators import ValidationError
|
|
||||||
from django.db.models import Prefetch
|
from django.db.models import Prefetch
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orgs.mixins import BulkOrgResourceModelSerializer
|
from orgs.mixins import BulkOrgResourceModelSerializer
|
||||||
from common.serializers import AdaptedBulkListSerializer
|
from common.serializers import AdaptedBulkListSerializer
|
||||||
from ..models import Asset, Protocol, Node, Label
|
from ..models import Asset, Node, Label
|
||||||
from .base import ConnectivitySerializer
|
from .base import ConnectivitySerializer
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AssetSerializer', 'AssetSimpleSerializer',
|
'AssetSerializer', 'AssetSimpleSerializer',
|
||||||
'ProtocolSerializer', 'ProtocolsRelatedField',
|
'ProtocolsField',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ProtocolSerializer(serializers.ModelSerializer):
|
class ProtocolField(serializers.RegexField):
|
||||||
class Meta:
|
protocols = '|'.join(dict(Asset.PROTOCOL_CHOICES).keys())
|
||||||
model = Protocol
|
default_error_messages = {
|
||||||
fields = ["name", "port"]
|
'invalid': _('Protocol format should {}/{}'.format(protocols, '1-65535'))
|
||||||
|
}
|
||||||
|
regex = r'^(%s)/(\d{1,5})$' % protocols
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(self.regex, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ProtocolsRelatedField(serializers.RelatedField):
|
def validate_duplicate_protocols(values):
|
||||||
|
errors = []
|
||||||
|
names = []
|
||||||
|
|
||||||
|
for value in values:
|
||||||
|
if not value or '/' not in value:
|
||||||
|
continue
|
||||||
|
name = value.split('/')[0]
|
||||||
|
if name in names:
|
||||||
|
errors.append(_("Protocol duplicate: {}").format(name))
|
||||||
|
names.append(name)
|
||||||
|
errors.append('')
|
||||||
|
if any(errors):
|
||||||
|
raise serializers.ValidationError(errors)
|
||||||
|
|
||||||
|
|
||||||
|
class ProtocolsField(serializers.ListField):
|
||||||
|
default_validators = [validate_duplicate_protocols]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['child'] = ProtocolField()
|
||||||
|
kwargs['allow_null'] = True
|
||||||
|
kwargs['allow_empty'] = True
|
||||||
|
kwargs['min_length'] = 1
|
||||||
|
kwargs['max_length'] = 4
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
return str(value)
|
if not value:
|
||||||
|
return []
|
||||||
def to_internal_value(self, data):
|
return value.split(' ')
|
||||||
if isinstance(data, dict):
|
|
||||||
return data
|
|
||||||
if '/' not in data:
|
|
||||||
raise ValidationError("protocol not contain /: {}".format(data))
|
|
||||||
v = data.split("/")
|
|
||||||
if len(v) != 2:
|
|
||||||
raise ValidationError("protocol format should be name/port: {}".format(data))
|
|
||||||
name, port = v
|
|
||||||
cleaned_data = {"name": name, "port": port}
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
|
|
||||||
class AssetSerializer(BulkOrgResourceModelSerializer):
|
class AssetSerializer(BulkOrgResourceModelSerializer):
|
||||||
protocols = ProtocolsRelatedField(
|
protocols = ProtocolsField(label=_('Protocols'), required=False)
|
||||||
many=True, queryset=Protocol.objects.all(), label=_("Protocols")
|
|
||||||
)
|
|
||||||
connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity"))
|
connectivity = ConnectivitySerializer(read_only=True, label=_("Connectivity"))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -79,66 +97,32 @@ class AssetSerializer(BulkOrgResourceModelSerializer):
|
|||||||
queryset = queryset.prefetch_related(
|
queryset = queryset.prefetch_related(
|
||||||
Prefetch('nodes', queryset=Node.objects.all().only('id')),
|
Prefetch('nodes', queryset=Node.objects.all().only('id')),
|
||||||
Prefetch('labels', queryset=Label.objects.all().only('id')),
|
Prefetch('labels', queryset=Label.objects.all().only('id')),
|
||||||
'protocols'
|
|
||||||
).select_related('admin_user', 'domain')
|
).select_related('admin_user', 'domain')
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
@staticmethod
|
def compatible_with_old_protocol(self, validated_data):
|
||||||
def validate_protocols(attr):
|
|
||||||
protocols_serializer = ProtocolSerializer(data=attr, many=True)
|
|
||||||
protocols_serializer.is_valid(raise_exception=True)
|
|
||||||
protocols_name = [i.get("name", "ssh") for i in attr]
|
|
||||||
errors = [{} for i in protocols_name]
|
|
||||||
for i, name in enumerate(protocols_name):
|
|
||||||
if name in protocols_name[:i]:
|
|
||||||
errors[i] = {"name": _("Protocol duplicate: {}").format(name)}
|
|
||||||
if any(errors):
|
|
||||||
raise ValidationError(errors)
|
|
||||||
return attr
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
protocols_data = validated_data.pop("protocols", [])
|
protocols_data = validated_data.pop("protocols", [])
|
||||||
|
|
||||||
# 兼容老的api
|
# 兼容老的api
|
||||||
protocol = validated_data.get("protocol")
|
name = validated_data.get("protocol")
|
||||||
port = validated_data.get("port")
|
port = validated_data.get("port")
|
||||||
if not protocols_data and protocol and port:
|
if not protocols_data and name and port:
|
||||||
protocols_data = [{"name": protocol, "port": port}]
|
protocols_data.insert(0, '/'.join([name, str(port)]))
|
||||||
|
elif not name and not port and protocols_data:
|
||||||
|
protocol = protocols_data[0].split('/')
|
||||||
|
validated_data["protocol"] = protocol[0]
|
||||||
|
validated_data["port"] = int(protocol[1])
|
||||||
|
if validated_data:
|
||||||
|
validated_data["protocols"] = ' '.join(protocols_data)
|
||||||
|
|
||||||
if not protocol and not port and protocols_data:
|
def create(self, validated_data):
|
||||||
validated_data["protocol"] = protocols_data[0]["name"]
|
self.compatible_with_old_protocol(validated_data)
|
||||||
validated_data["port"] = protocols_data[0]["port"]
|
|
||||||
|
|
||||||
protocols_serializer = ProtocolSerializer(data=protocols_data, many=True)
|
|
||||||
protocols_serializer.is_valid(raise_exception=True)
|
|
||||||
protocols = protocols_serializer.save()
|
|
||||||
instance = super().create(validated_data)
|
instance = super().create(validated_data)
|
||||||
instance.protocols.set(protocols)
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
protocols_data = validated_data.pop("protocols", [])
|
self.compatible_with_old_protocol(validated_data)
|
||||||
|
return super().update(instance, validated_data)
|
||||||
# 兼容老的api
|
|
||||||
protocol = validated_data.get("protocol")
|
|
||||||
port = validated_data.get("port")
|
|
||||||
if not protocols_data and protocol and port:
|
|
||||||
protocols_data = [{"name": protocol, "port": port}]
|
|
||||||
|
|
||||||
if not protocol and not port and protocols_data:
|
|
||||||
validated_data["protocol"] = protocols_data[0]["name"]
|
|
||||||
validated_data["port"] = protocols_data[0]["port"]
|
|
||||||
protocols = None
|
|
||||||
if protocols_data:
|
|
||||||
protocols_serializer = ProtocolSerializer(data=protocols_data, many=True)
|
|
||||||
protocols_serializer.is_valid(raise_exception=True)
|
|
||||||
protocols = protocols_serializer.save()
|
|
||||||
|
|
||||||
instance = super().update(instance, validated_data)
|
|
||||||
if protocols:
|
|
||||||
instance.protocols.all().delete()
|
|
||||||
instance.protocols.set(protocols)
|
|
||||||
return instance
|
|
||||||
|
|
||||||
|
|
||||||
class AssetSimpleSerializer(serializers.ModelSerializer):
|
class AssetSimpleSerializer(serializers.ModelSerializer):
|
||||||
|
@ -70,11 +70,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Protocol' %}</td>
|
<td>{% trans 'Protocol' %}</td>
|
||||||
<td>
|
<td>{{ asset.protocols }}</td>
|
||||||
{% for protocol in asset.protocols.all %}
|
|
||||||
<b>{{ protocol }}</b>
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Admin user' %}:</td>
|
<td>{% trans 'Admin user' %}:</td>
|
||||||
|
@ -1,37 +1,25 @@
|
|||||||
# coding:utf-8
|
# coding:utf-8
|
||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
import csv
|
|
||||||
import json
|
|
||||||
import uuid
|
|
||||||
import codecs
|
|
||||||
import chardet
|
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
from django.db import transaction
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views.generic import TemplateView, ListView, View
|
from django.views.generic import TemplateView, ListView
|
||||||
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
|
from django.views.generic.edit import FormMixin
|
||||||
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic.detail import DetailView
|
from django.views.generic.detail import DetailView
|
||||||
from django.http import HttpResponse, JsonResponse
|
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils import timezone
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.forms.formsets import formset_factory
|
from django.forms.formsets import formset_factory
|
||||||
|
|
||||||
from common.mixins import JSONResponseMixin
|
|
||||||
from common.utils import get_object_or_none, get_logger
|
from common.utils import get_object_or_none, get_logger
|
||||||
from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser
|
from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser
|
||||||
from common.const import (
|
from common.const import (
|
||||||
create_success_msg, update_success_msg, KEY_CACHE_RESOURCES_ID
|
create_success_msg, update_success_msg, KEY_CACHE_RESOURCES_ID
|
||||||
)
|
)
|
||||||
from .. import forms
|
from .. import forms
|
||||||
from ..models import Asset, AdminUser, SystemUser, Label, Node, Domain
|
from ..models import Asset, SystemUser, Label, Node
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@ -87,7 +75,7 @@ class UserAssetListView(PermissionsMixin, TemplateView):
|
|||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AssetCreateView(PermissionsMixin, SuccessMessageMixin, CreateView):
|
class AssetCreateView(PermissionsMixin, FormMixin, TemplateView):
|
||||||
model = Asset
|
model = Asset
|
||||||
form_class = forms.AssetCreateForm
|
form_class = forms.AssetCreateForm
|
||||||
template_name = 'assets/asset_create.html'
|
template_name = 'assets/asset_create.html'
|
||||||
@ -112,16 +100,6 @@ class AssetCreateView(PermissionsMixin, SuccessMessageMixin, CreateView):
|
|||||||
formset = ProtocolFormset()
|
formset = ProtocolFormset()
|
||||||
return formset
|
return formset
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
formset = self.get_protocol_formset()
|
|
||||||
valid = formset.is_valid()
|
|
||||||
if not valid:
|
|
||||||
return self.form_invalid(form)
|
|
||||||
protocols = formset.save()
|
|
||||||
instance = super().form_valid(form)
|
|
||||||
instance.protocols.set(protocols)
|
|
||||||
return instance
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
formset = self.get_protocol_formset()
|
formset = self.get_protocol_formset()
|
||||||
context = {
|
context = {
|
||||||
@ -132,8 +110,32 @@ class AssetCreateView(PermissionsMixin, SuccessMessageMixin, CreateView):
|
|||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
return create_success_msg % ({"name": cleaned_data["hostname"]})
|
class AssetUpdateView(PermissionsMixin, UpdateView):
|
||||||
|
model = Asset
|
||||||
|
form_class = forms.AssetUpdateForm
|
||||||
|
template_name = 'assets/asset_update.html'
|
||||||
|
success_url = reverse_lazy('assets:asset-list')
|
||||||
|
permission_classes = [IsOrgAdmin]
|
||||||
|
|
||||||
|
def get_protocol_formset(self):
|
||||||
|
ProtocolFormset = formset_factory(forms.ProtocolForm, extra=0, min_num=1, max_num=5)
|
||||||
|
if self.request.method == "POST":
|
||||||
|
formset = ProtocolFormset(self.request.POST)
|
||||||
|
else:
|
||||||
|
initial_data = self.object.protocols_as_json
|
||||||
|
formset = ProtocolFormset(initial=initial_data)
|
||||||
|
return formset
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
formset = self.get_protocol_formset()
|
||||||
|
context = {
|
||||||
|
'app': _('Assets'),
|
||||||
|
'action': _('Update asset'),
|
||||||
|
'formset': formset,
|
||||||
|
}
|
||||||
|
kwargs.update(context)
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AssetBulkUpdateView(PermissionsMixin, ListView):
|
class AssetBulkUpdateView(PermissionsMixin, ListView):
|
||||||
@ -177,36 +179,6 @@ class AssetBulkUpdateView(PermissionsMixin, ListView):
|
|||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AssetUpdateView(PermissionsMixin, SuccessMessageMixin, UpdateView):
|
|
||||||
model = Asset
|
|
||||||
form_class = forms.AssetUpdateForm
|
|
||||||
template_name = 'assets/asset_update.html'
|
|
||||||
success_url = reverse_lazy('assets:asset-list')
|
|
||||||
permission_classes = [IsOrgAdmin]
|
|
||||||
|
|
||||||
def get_protocol_formset(self):
|
|
||||||
ProtocolFormset = formset_factory(forms.ProtocolForm, extra=0, min_num=1, max_num=5)
|
|
||||||
if self.request.method == "POST":
|
|
||||||
formset = ProtocolFormset(self.request.POST)
|
|
||||||
else:
|
|
||||||
initial_data = [{"name": p.name, "port": p.port} for p in self.object.protocols.all()]
|
|
||||||
formset = ProtocolFormset(initial=initial_data)
|
|
||||||
return formset
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
formset = self.get_protocol_formset()
|
|
||||||
context = {
|
|
||||||
'app': _('Assets'),
|
|
||||||
'action': _('Update asset'),
|
|
||||||
'formset': formset,
|
|
||||||
}
|
|
||||||
kwargs.update(context)
|
|
||||||
return super().get_context_data(**kwargs)
|
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
return update_success_msg % ({"name": cleaned_data["hostname"]})
|
|
||||||
|
|
||||||
|
|
||||||
class AssetDeleteView(PermissionsMixin, DeleteView):
|
class AssetDeleteView(PermissionsMixin, DeleteView):
|
||||||
model = Asset
|
model = Asset
|
||||||
template_name = 'delete_confirm.html'
|
template_name = 'delete_confirm.html'
|
||||||
@ -222,7 +194,7 @@ class AssetDetailView(PermissionsMixin, DetailView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super().get_queryset().prefetch_related(
|
return super().get_queryset().prefetch_related(
|
||||||
"nodes", "labels", "protocols"
|
"nodes", "labels",
|
||||||
).select_related('admin_user', 'domain')
|
).select_related('admin_user', 'domain')
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -135,9 +135,7 @@ function getSelectedAssetsNode() {
|
|||||||
var assetsNode = [];
|
var assetsNode = [];
|
||||||
nodes.forEach(function (node) {
|
nodes.forEach(function (node) {
|
||||||
if (node.meta.type === 'asset' && !node.isHidden) {
|
if (node.meta.type === 'asset' && !node.isHidden) {
|
||||||
var protocols = $.map(node.meta.asset.protocols, function (v) {
|
var protocols = node.meta.asset.protocols;
|
||||||
return v.name
|
|
||||||
});
|
|
||||||
if (assetsNodeId.indexOf(node.id) === -1 && protocols.indexOf("ssh") > -1) {
|
if (assetsNodeId.indexOf(node.id) === -1 && protocols.indexOf("ssh") > -1) {
|
||||||
assetsNodeId.push(node.id);
|
assetsNodeId.push(node.id);
|
||||||
assetsNode.push(node)
|
assetsNode.push(node)
|
||||||
|
@ -126,7 +126,7 @@ class GenerateTree:
|
|||||||
for asset, system_users in assets.items():
|
for asset, system_users in assets.items():
|
||||||
self.add_asset(asset, system_users)
|
self.add_asset(asset, system_users)
|
||||||
|
|
||||||
#@timeit
|
# #@timeit
|
||||||
def add_asset(self, asset, system_users=None):
|
def add_asset(self, asset, system_users=None):
|
||||||
nodes = asset.nodes.all()
|
nodes = asset.nodes.all()
|
||||||
nodes = self.node_util.get_nodes_by_queryset(nodes)
|
nodes = self.node_util.get_nodes_by_queryset(nodes)
|
||||||
@ -494,11 +494,12 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
|
|||||||
pattern = '|'.join(list(pattern))
|
pattern = '|'.join(list(pattern))
|
||||||
if pattern:
|
if pattern:
|
||||||
assets = Asset.objects.filter(nodes__key__regex=pattern) \
|
assets = Asset.objects.filter(nodes__key__regex=pattern) \
|
||||||
.prefetch_related('nodes', "protocols")\
|
.prefetch_related('nodes')\
|
||||||
.only(*self.assets_only)\
|
.only(*self.assets_only)\
|
||||||
.distinct()
|
.distinct()
|
||||||
else:
|
else:
|
||||||
assets = []
|
assets = []
|
||||||
|
assets = list(assets)
|
||||||
self.tree.add_assets_without_system_users(assets)
|
self.tree.add_assets_without_system_users(assets)
|
||||||
assets = self.tree.get_assets()
|
assets = self.tree.get_assets()
|
||||||
self._assets = assets
|
self._assets = assets
|
||||||
@ -598,7 +599,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
|
|||||||
'id': asset.id,
|
'id': asset.id,
|
||||||
'hostname': asset.hostname,
|
'hostname': asset.hostname,
|
||||||
'ip': asset.ip,
|
'ip': asset.ip,
|
||||||
'protocols': [str(p) for p in asset.protocols.all()],
|
'protocols': asset.protocols_as_list,
|
||||||
'platform': asset.platform,
|
'platform': asset.platform,
|
||||||
'domain': None if not asset.domain else asset.domain.id,
|
'domain': None if not asset.domain else asset.domain.id,
|
||||||
'is_active': asset.is_active,
|
'is_active': asset.is_active,
|
||||||
|
Loading…
Reference in New Issue
Block a user