mirror of https://github.com/jumpserver/jumpserver
stash it
parent
d43acd8612
commit
6c57db0897
|
@ -12,7 +12,6 @@ from assets.models import Asset, Node, Gateway
|
||||||
from assets import serializers
|
from assets import serializers
|
||||||
from assets.tasks import (
|
from assets.tasks import (
|
||||||
update_assets_hardware_info_manual, test_assets_connectivity_manual,
|
update_assets_hardware_info_manual, test_assets_connectivity_manual,
|
||||||
test_system_users_connectivity_a_asset, push_system_users_a_asset
|
|
||||||
)
|
)
|
||||||
from assets.filters import FilterAssetByNodeFilterBackend, LabelFilterBackend, IpInFilterBackend
|
from assets.filters import FilterAssetByNodeFilterBackend, LabelFilterBackend, IpInFilterBackend
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
# Generated by Django 3.1.14 on 2022-03-30 10:35
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('assets', '0089_auto_20220310_0616'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Host',
|
|
||||||
fields=[
|
|
||||||
('asset_ptr', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='assets.asset')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,40 +0,0 @@
|
||||||
# Generated by Django 3.1.14 on 2022-04-01 07:58
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
def migrate_to_host(apps, schema_editor):
|
|
||||||
asset_model = apps.get_model("assets", "Asset")
|
|
||||||
host_model = apps.get_model("assets", 'Host')
|
|
||||||
db_alias = schema_editor.connection.alias
|
|
||||||
|
|
||||||
created = 0
|
|
||||||
batch_size = 1000
|
|
||||||
|
|
||||||
while True:
|
|
||||||
start = created
|
|
||||||
end = created + batch_size
|
|
||||||
assets = asset_model.objects.using(db_alias).all()[start:end]
|
|
||||||
if not assets:
|
|
||||||
break
|
|
||||||
|
|
||||||
hosts = [host_model(asset_ptr=asset) for asset in assets]
|
|
||||||
host_model.objects.using(db_alias).bulk_create(hosts, ignore_conflicts=True)
|
|
||||||
created += len(hosts)
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('assets', '0090_add_host'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='host',
|
|
||||||
name='asset_ptr',
|
|
||||||
field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='assets.asset'),
|
|
||||||
),
|
|
||||||
migrations.RunPython(migrate_to_host)
|
|
||||||
]
|
|
|
@ -1,17 +1,23 @@
|
||||||
# Generated by Django 3.1.14 on 2022-04-02 09:09
|
# Generated by Django 3.1.14 on 2022-03-30 10:35
|
||||||
|
|
||||||
|
import uuid
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import uuid
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('assets', '0091_auto_20220401_1558'),
|
('assets', '0091_auto_20220629_1826'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Host',
|
||||||
|
fields=[
|
||||||
|
('asset_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='assets.asset')),
|
||||||
|
],
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='DeviceInfo',
|
name='DeviceInfo',
|
||||||
fields=[
|
fields=[
|
|
@ -41,12 +41,33 @@ def migrate_hardware(apps, *args):
|
||||||
created += len(hardware_infos)
|
created += len(hardware_infos)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_to_host(apps, schema_editor):
|
||||||
|
asset_model = apps.get_model("assets", "Asset")
|
||||||
|
host_model = apps.get_model("assets", 'Host')
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
|
||||||
|
created = 0
|
||||||
|
batch_size = 1000
|
||||||
|
|
||||||
|
while True:
|
||||||
|
start = created
|
||||||
|
end = created + batch_size
|
||||||
|
assets = asset_model.objects.using(db_alias).all()[start:end]
|
||||||
|
if not assets:
|
||||||
|
break
|
||||||
|
|
||||||
|
hosts = [host_model(asset_ptr=asset) for asset in assets]
|
||||||
|
host_model.objects.using(db_alias).bulk_create(hosts, ignore_conflicts=True)
|
||||||
|
created += len(hosts)
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('assets', '0092_hardware'),
|
('assets', '0092_add_host'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RunPython(migrate_hardware)
|
migrations.RunPython(migrate_to_host),
|
||||||
|
migrations.RunPython(migrate_hardware),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Generated by Django 3.2.12 on 2022-07-13 09:38
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('assets', '0093_auto_20220711_1413'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='systemuser',
|
|
||||||
name='assets',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='systemuser',
|
|
||||||
name='assets',
|
|
||||||
field=models.ManyToManyField(blank=True, related_name='system_users', to='assets.Asset', verbose_name='Assets'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,16 +0,0 @@
|
||||||
# Generated by Django 3.2.14 on 2022-08-03 06:48
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('assets', '0093_auto_20220711_1413'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='Cluster',
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,45 +0,0 @@
|
||||||
# Generated by Django 3.2.12 on 2022-07-13 09:46
|
|
||||||
|
|
||||||
import time
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
def migrate_asset_system_user_relations(apps, schema_editor):
|
|
||||||
system_user_model = apps.get_model('assets', 'SystemUser')
|
|
||||||
old_model = apps.get_model('assets', 'AuthBook')
|
|
||||||
new_model = system_user_model.assets.through
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
bulk_size = 1000
|
|
||||||
print("\nStart migrate asset system user relations")
|
|
||||||
while True:
|
|
||||||
start = time.time()
|
|
||||||
auth_books = old_model.objects.only('asset_id', 'systemuser_id')[count:count+bulk_size]
|
|
||||||
auth_books = list(auth_books)
|
|
||||||
count += len(auth_books)
|
|
||||||
if not auth_books:
|
|
||||||
break
|
|
||||||
asset_system_users = []
|
|
||||||
for auth_book in auth_books:
|
|
||||||
if not auth_book.asset_id or not auth_book.systemuser_id:
|
|
||||||
continue
|
|
||||||
asset_system_user = new_model(
|
|
||||||
asset_id=auth_book.asset_id,
|
|
||||||
systemuser_id=auth_book.systemuser_id
|
|
||||||
)
|
|
||||||
asset_system_users.append(asset_system_user)
|
|
||||||
new_model.objects.bulk_create(asset_system_users, ignore_conflicts=True)
|
|
||||||
print("Create asset system user relations: {}-{} using: {:.2f}s".format(
|
|
||||||
count - bulk_size, count, time.time()-start
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('assets', '0094_alter_systemuser_assets'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(migrate_asset_system_user_relations)
|
|
||||||
]
|
|
|
@ -1,23 +0,0 @@
|
||||||
# Generated by Django 3.2.12 on 2022-07-14 08:27
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('assets', '0095_auto_20220713_1746'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RenameField(
|
|
||||||
model_name='systemuser',
|
|
||||||
old_name='auto_push',
|
|
||||||
new_name='auto_push_account',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='systemuser',
|
|
||||||
name='account_template_enabled',
|
|
||||||
field=models.BooleanField(default=False, verbose_name='Auto account if not exist'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -13,7 +13,7 @@ class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
('assets', '0091_auto_20220629_1826'),
|
('assets', '0100_auto_20220430_2126'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
|
@ -57,7 +57,7 @@ def migrate_accounts(apps, schema_editor):
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('assets', '0092_auto_20220711_1409'),
|
('assets', '0101_auto_20220711_1409'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
|
@ -0,0 +1,51 @@
|
||||||
|
# Generated by Django 3.2.14 on 2022-08-03 10:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0102_auto_20220711_1413'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Protocol',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=32, verbose_name='Name')),
|
||||||
|
('port', models.IntegerField(verbose_name='Port')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='asset',
|
||||||
|
name='port',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='asset',
|
||||||
|
name='protocol',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='asset',
|
||||||
|
name='_protocols',
|
||||||
|
field=models.CharField(blank=True, default='ssh/22', max_length=128, verbose_name='Protocols'),
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='asset',
|
||||||
|
name='protocols',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='systemuser',
|
||||||
|
name='protocol',
|
||||||
|
field=models.CharField(default='ssh', max_length=16, verbose_name='Protocol'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='asset',
|
||||||
|
name='protocols',
|
||||||
|
field=models.ManyToManyField(blank=True, to='assets.Protocol', verbose_name='Protocols'),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Cluster',
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Generated by Django 3.2.14 on 2022-08-03 10:59
|
||||||
|
import time
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_asset_protocols(apps, schema_editor):
|
||||||
|
asset_model = apps.get_model('assets', 'Asset')
|
||||||
|
protocol_model = apps.get_model('assets', 'Protocol')
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
bulk_size = 1000
|
||||||
|
print("\nStart migrate asset protocols")
|
||||||
|
while True:
|
||||||
|
start = time.time()
|
||||||
|
assets = asset_model.objects.all()[count:count+bulk_size]
|
||||||
|
count += len(assets)
|
||||||
|
if not assets:
|
||||||
|
break
|
||||||
|
|
||||||
|
protocols = []
|
||||||
|
for asset in assets:
|
||||||
|
for protocol in asset.protocols.all():
|
||||||
|
protocols.append(protocol_model(
|
||||||
|
asset_id=asset.id,
|
||||||
|
protocol=protocol.protocol,
|
||||||
|
port=protocol.port,
|
||||||
|
))
|
||||||
|
protocol_model.objects.bulk_create(protocols, ignore_conflicts=True)
|
||||||
|
print("Create asset protocols: {}-{} using: {:.2f}s".format(
|
||||||
|
count - bulk_size, count, time.time()-start
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0103_auto_20220803_1448'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(migrate_asset_protocols)
|
||||||
|
]
|
|
@ -41,7 +41,7 @@ class SystemUser(ProtocolMixin, BaseUser):
|
||||||
groups = models.ManyToManyField('users.UserGroup', blank=True, verbose_name=_("User groups"))
|
groups = models.ManyToManyField('users.UserGroup', blank=True, verbose_name=_("User groups"))
|
||||||
type = models.CharField(max_length=16, choices=Type.choices, default=Type.common, verbose_name=_('Type'))
|
type = models.CharField(max_length=16, choices=Type.choices, default=Type.common, verbose_name=_('Type'))
|
||||||
priority = models.IntegerField(default=81, verbose_name=_("Priority"), help_text=_("1-100, the lower the value will be match first"), validators=[MinValueValidator(1), MaxValueValidator(100)])
|
priority = models.IntegerField(default=81, verbose_name=_("Priority"), help_text=_("1-100, the lower the value will be match first"), validators=[MinValueValidator(1), MaxValueValidator(100)])
|
||||||
protocol = models.CharField(max_length=16, choices=ProtocolMixin.Protocol.choices, default='ssh', verbose_name=_('Protocol'))
|
protocol = models.CharField(max_length=16, default='ssh', verbose_name=_('Protocol'))
|
||||||
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
|
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
|
||||||
sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo'))
|
sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo'))
|
||||||
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
|
shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell'))
|
||||||
|
|
|
@ -5,19 +5,17 @@
|
||||||
import uuid
|
import uuid
|
||||||
import logging
|
import logging
|
||||||
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 common.db.fields import JsonDictTextField
|
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
from orgs.mixins.models import OrgModelMixin, OrgManager
|
from orgs.mixins.models import OrgModelMixin, OrgManager
|
||||||
from assets.const import Category, AllTypes
|
from assets.const import Category, AllTypes
|
||||||
from ..platform import Platform
|
from ..platform import Platform
|
||||||
from ..base import AbsConnectivity
|
from ..base import AbsConnectivity
|
||||||
|
|
||||||
__all__ = ['Asset', 'ProtocolsMixin', 'AssetQuerySet', 'default_node', 'default_cluster']
|
__all__ = ['Asset', 'AssetQuerySet', 'default_node']
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,49 +43,6 @@ class AssetQuerySet(models.QuerySet):
|
||||||
return self.filter(protocols__contains=name)
|
return self.filter(protocols__contains=name)
|
||||||
|
|
||||||
|
|
||||||
class ProtocolsMixin:
|
|
||||||
protocols = ''
|
|
||||||
|
|
||||||
class Protocol(models.TextChoices):
|
|
||||||
ssh = 'ssh', 'SSH'
|
|
||||||
rdp = 'rdp', 'RDP'
|
|
||||||
telnet = 'telnet', 'Telnet'
|
|
||||||
vnc = 'vnc', 'VNC'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def protocols_as_list(self):
|
|
||||||
if not self.protocols:
|
|
||||||
return []
|
|
||||||
return self.protocols.split(' ')
|
|
||||||
|
|
||||||
@property
|
|
||||||
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 NodesRelationMixin:
|
class NodesRelationMixin:
|
||||||
NODES_CACHE_KEY = 'ASSET_NODES_{}'
|
NODES_CACHE_KEY = 'ASSET_NODES_{}'
|
||||||
ALL_ASSET_NODES_CACHE_KEY = 'ALL_ASSETS_NODES'
|
ALL_ASSET_NODES_CACHE_KEY = 'ALL_ASSETS_NODES'
|
||||||
|
@ -112,17 +67,15 @@ class NodesRelationMixin:
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
class Asset(AbsConnectivity, ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
|
class Asset(AbsConnectivity, NodesRelationMixin, OrgModelMixin):
|
||||||
Category = Category
|
Category = Category
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
hostname = models.CharField(max_length=128, verbose_name=_('Hostname'))
|
hostname = models.CharField(max_length=128, verbose_name=_('Hostname'))
|
||||||
ip = models.CharField(max_length=128, verbose_name=_('IP'), db_index=True)
|
ip = models.CharField(max_length=128, verbose_name=_('IP'), db_index=True)
|
||||||
category = models.CharField(max_length=16, choices=Category.choices, verbose_name=_("Category"))
|
category = models.CharField(max_length=16, choices=Category.choices, verbose_name=_("Category"))
|
||||||
type = models.CharField(max_length=128, choices=AllTypes.choices, verbose_name=_("Type"))
|
type = models.CharField(max_length=128, choices=AllTypes.choices, verbose_name=_("Type"))
|
||||||
protocol = models.CharField(max_length=128, default=ProtocolsMixin.Protocol.ssh,
|
_protocols = models.CharField(max_length=128, default='ssh/22', blank=True, verbose_name=_("Protocols"))
|
||||||
choices=ProtocolsMixin.Protocol.choices, verbose_name=_('Protocol'))
|
protocols = models.ManyToManyField('Protocol', verbose_name=_("Protocols"), blank=True)
|
||||||
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
|
||||||
protocols = models.CharField(max_length=128, default='ssh/22', blank=True, verbose_name=_("Protocols"))
|
|
||||||
platform = models.ForeignKey(Platform, default=Platform.default, on_delete=models.PROTECT,
|
platform = models.ForeignKey(Platform, default=Platform.default, on_delete=models.PROTECT,
|
||||||
verbose_name=_("Platform"), related_name='assets')
|
verbose_name=_("Platform"), related_name='assets')
|
||||||
domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets',
|
domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets',
|
||||||
|
@ -134,7 +87,6 @@ class Asset(AbsConnectivity, ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
|
||||||
# Auth
|
# Auth
|
||||||
admin_user = models.ForeignKey('assets.SystemUser', on_delete=models.SET_NULL, null=True,
|
admin_user = models.ForeignKey('assets.SystemUser', on_delete=models.SET_NULL, null=True,
|
||||||
verbose_name=_("Admin user"), related_name='admin_assets')
|
verbose_name=_("Admin user"), related_name='admin_assets')
|
||||||
|
|
||||||
# Some information
|
# Some information
|
||||||
public_ip = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Public IP'))
|
public_ip = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Public IP'))
|
||||||
number = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Asset number'))
|
number = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('Asset number'))
|
||||||
|
@ -178,55 +130,6 @@ class Asset(AbsConnectivity, ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
|
||||||
"""
|
"""
|
||||||
return self.admin_user.username
|
return self.admin_user.username
|
||||||
|
|
||||||
def is_windows(self):
|
|
||||||
return self.platform.is_windows()
|
|
||||||
|
|
||||||
def is_unixlike(self):
|
|
||||||
return self.platform.is_unixlike()
|
|
||||||
|
|
||||||
def is_support_ansible(self):
|
|
||||||
return self.has_protocol('ssh') and self.platform_base not in ("Other",)
|
|
||||||
|
|
||||||
def get_auth_info(self, with_become=False):
|
|
||||||
if not self.admin_user:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
if self.is_unixlike() and self.admin_user.su_enabled and self.admin_user.su_from:
|
|
||||||
auth_user = self.admin_user.su_from
|
|
||||||
become_user = self.admin_user
|
|
||||||
else:
|
|
||||||
auth_user = self.admin_user
|
|
||||||
become_user = None
|
|
||||||
|
|
||||||
auth_user.load_asset_special_auth(self)
|
|
||||||
info = {
|
|
||||||
'username': auth_user.username,
|
|
||||||
'password': auth_user.password,
|
|
||||||
'private_key': auth_user.private_key_file
|
|
||||||
}
|
|
||||||
|
|
||||||
if not with_become or self.is_windows():
|
|
||||||
return info
|
|
||||||
|
|
||||||
if become_user:
|
|
||||||
become_user.load_asset_special_auth(self)
|
|
||||||
become_method = 'su'
|
|
||||||
become_username = become_user.username
|
|
||||||
become_pass = become_user.password
|
|
||||||
else:
|
|
||||||
become_method = 'sudo'
|
|
||||||
become_username = 'root'
|
|
||||||
become_pass = auth_user.password
|
|
||||||
become_info = {
|
|
||||||
'become': {
|
|
||||||
'method': become_method,
|
|
||||||
'username': become_username,
|
|
||||||
'pass': become_pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info.update(become_info)
|
|
||||||
return info
|
|
||||||
|
|
||||||
def nodes_display(self):
|
def nodes_display(self):
|
||||||
names = []
|
names = []
|
||||||
for n in self.nodes.all():
|
for n in self.nodes.all():
|
||||||
|
@ -270,7 +173,7 @@ class Asset(AbsConnectivity, ProtocolsMixin, NodesRelationMixin, OrgModelMixin):
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'hostname': self.hostname,
|
'hostname': self.hostname,
|
||||||
'ip': self.ip,
|
'ip': self.ip,
|
||||||
'protocols': self.protocols_as_list,
|
'protocols': self.protocols,
|
||||||
'platform': self.platform_base,
|
'platform': self.platform_base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from common.db.models import JMSBaseModel
|
|
||||||
|
|
||||||
|
class Protocol(models.Model):
|
||||||
class Protocol(JMSBaseModel):
|
|
||||||
name = models.CharField(max_length=32, verbose_name=_("Name"))
|
name = models.CharField(max_length=32, verbose_name=_("Name"))
|
||||||
port = models.IntegerField(verbose_name=_("Port"))
|
port = models.IntegerField(verbose_name=_("Port"))
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
from .asset import *
|
from .asset import *
|
||||||
from .label import *
|
from .label import *
|
||||||
from .system_user import *
|
|
||||||
from .node import *
|
from .node import *
|
||||||
from .domain import *
|
from .domain import *
|
||||||
from .gathered_user import *
|
from .gathered_user import *
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
from rest_framework import serializers
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from common.validators import alphanumeric_re, alphanumeric_cn_re, alphanumeric_win_re
|
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'SystemUserSerializer', 'MiniSystemUserSerializer',
|
|
||||||
'SystemUserSimpleSerializer',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class SystemUserSerializer(BulkOrgResourceModelSerializer):
|
|
||||||
"""
|
|
||||||
系统用户
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = SystemUser
|
|
||||||
fields_mini = ['id', 'name', 'username', 'protocol']
|
|
||||||
fields_small = fields_mini + [
|
|
||||||
'login_mode', 'su_enabled', 'su_from',
|
|
||||||
'date_created', 'date_updated', 'comment',
|
|
||||||
'created_by',
|
|
||||||
]
|
|
||||||
fields = fields_small
|
|
||||||
extra_kwargs = {
|
|
||||||
'cmd_filters': {"required": False, 'label': _('Command filter')},
|
|
||||||
'login_mode_display': {'label': _('Login mode display')},
|
|
||||||
'created_by': {'read_only': True},
|
|
||||||
'ad_domain': {'required': False, 'allow_blank': True, 'label': _('Ad domain')},
|
|
||||||
'su_from': {'help_text': _('Only ssh and automatic login system users are supported')}
|
|
||||||
}
|
|
||||||
|
|
||||||
def validate_username_same_with_user(self, username_same_with_user):
|
|
||||||
if not username_same_with_user:
|
|
||||||
return username_same_with_user
|
|
||||||
protocol = self.get_initial_value("protocol", "ssh")
|
|
||||||
queryset = SystemUser.objects.filter(
|
|
||||||
protocol=protocol,
|
|
||||||
username_same_with_user=True
|
|
||||||
)
|
|
||||||
if self.instance:
|
|
||||||
queryset = queryset.exclude(id=self.instance.id)
|
|
||||||
exists = queryset.exists()
|
|
||||||
if not exists:
|
|
||||||
return username_same_with_user
|
|
||||||
error = _("Username same with user with protocol {} only allow 1").format(protocol)
|
|
||||||
raise serializers.ValidationError(error)
|
|
||||||
|
|
||||||
def validate_username(self, username):
|
|
||||||
protocol = self.get_initial_value("protocol")
|
|
||||||
if username:
|
|
||||||
if protocol == Protocol.telnet:
|
|
||||||
regx = alphanumeric_cn_re
|
|
||||||
elif protocol == Protocol.rdp:
|
|
||||||
regx = alphanumeric_win_re
|
|
||||||
else:
|
|
||||||
regx = alphanumeric_re
|
|
||||||
if not regx.match(username):
|
|
||||||
raise serializers.ValidationError(_('Special char not allowed'))
|
|
||||||
return username
|
|
||||||
|
|
||||||
username_same_with_user = self.get_initial_value("username_same_with_user")
|
|
||||||
if username_same_with_user:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
login_mode = self.get_initial_value("login_mode")
|
|
||||||
if login_mode == SystemUser.LOGIN_AUTO and protocol != Protocol.vnc \
|
|
||||||
and protocol != Protocol.redis:
|
|
||||||
msg = _('* Automatic login mode must fill in the username.')
|
|
||||||
raise serializers.ValidationError(msg)
|
|
||||||
return username
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def validate_sftp_root(value):
|
|
||||||
if value in ['home', 'tmp']:
|
|
||||||
return value
|
|
||||||
if not value.startswith('/'):
|
|
||||||
error = _("Path should starts with /")
|
|
||||||
raise serializers.ValidationError(error)
|
|
||||||
return value
|
|
||||||
|
|
||||||
def validate_su_from(self, su_from: SystemUser):
|
|
||||||
# self: su enabled
|
|
||||||
su_enabled = self.get_initial_value('su_enabled', default=False)
|
|
||||||
if not su_enabled:
|
|
||||||
return
|
|
||||||
if not su_from:
|
|
||||||
error = _('This field is required.')
|
|
||||||
raise serializers.ValidationError(error)
|
|
||||||
# self: protocol ssh
|
|
||||||
protocol = self.get_initial_value('protocol', default=Protocol.ssh.value)
|
|
||||||
if protocol not in [Protocol.ssh.value]:
|
|
||||||
error = _('Only ssh protocol system users are allowed')
|
|
||||||
raise serializers.ValidationError(error)
|
|
||||||
# su_from: protocol same
|
|
||||||
if su_from.protocol != protocol:
|
|
||||||
error = _('The protocol must be consistent with the current user: {}').format(protocol)
|
|
||||||
raise serializers.ValidationError(error)
|
|
||||||
# su_from: login model auto
|
|
||||||
if su_from.login_mode != su_from.LOGIN_AUTO:
|
|
||||||
error = _('Only system users with automatic login are allowed')
|
|
||||||
raise serializers.ValidationError(error)
|
|
||||||
return su_from
|
|
||||||
|
|
||||||
|
|
||||||
class MiniSystemUserSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = SystemUser
|
|
||||||
fields = SystemUserSerializer.Meta.fields_mini
|
|
||||||
|
|
||||||
|
|
||||||
class SystemUserSimpleSerializer(serializers.ModelSerializer):
|
|
||||||
"""
|
|
||||||
系统用户最基本信息的数据结构
|
|
||||||
"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = SystemUser
|
|
||||||
fields = ('id', 'name', 'username')
|
|
||||||
|
|
||||||
|
|
||||||
class SystemUserTempAuthSerializer(SystemUserSerializer):
|
|
||||||
instance_id = serializers.CharField()
|
|
||||||
|
|
||||||
class Meta(SystemUserSerializer.Meta):
|
|
||||||
fields = ['instance_id', 'username', 'password']
|
|
|
@ -4,11 +4,11 @@ from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
|
||||||
from common.drf.api import JMSModelViewSet
|
from common.drf.api import JMSModelViewSet
|
||||||
|
from common.mixins.api import PaginatedResponseMixin
|
||||||
from ..filters import RoleFilter
|
from ..filters import RoleFilter
|
||||||
from ..serializers import RoleSerializer, RoleUserSerializer
|
from ..serializers import RoleSerializer, RoleUserSerializer
|
||||||
from ..models import Role, SystemRole, OrgRole
|
from ..models import Role, SystemRole, OrgRole
|
||||||
from .permission import PermissionViewSet
|
from .permission import PermissionViewSet
|
||||||
from common.mixins.api import PaginatedResponseMixin
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'RoleViewSet', 'SystemRoleViewSet', 'OrgRoleViewSet',
|
'RoleViewSet', 'SystemRoleViewSet', 'OrgRoleViewSet',
|
||||||
|
@ -16,7 +16,7 @@ __all__ = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class RoleViewSet(PaginatedResponseMixin, JMSModelViewSet):
|
class RoleViewSet(JMSModelViewSet):
|
||||||
queryset = Role.objects.all()
|
queryset = Role.objects.all()
|
||||||
serializer_classes = {
|
serializer_classes = {
|
||||||
'default': RoleSerializer,
|
'default': RoleSerializer,
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.db import migrations, models
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('terminal', '0047_auto_20220302_1951'),
|
('terminal', '0051_sessionsharing_users'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
Loading…
Reference in New Issue