mirror of https://github.com/jumpserver/jumpserver
Merge branch 'v3' of github.com:jumpserver/jumpserver into v3
commit
572f03d844
|
@ -2,11 +2,8 @@ from .mixin import *
|
|||
from .platform import *
|
||||
from .asset import *
|
||||
from .label import *
|
||||
from .accounts import *
|
||||
from .account import *
|
||||
from .node import *
|
||||
from .domain import *
|
||||
from .gathered_user import *
|
||||
from .favorite_asset import *
|
||||
from .account_template import *
|
||||
from .account_backup import *
|
||||
from .account_history import *
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from .account import *
|
||||
from .backup import *
|
||||
from .history import *
|
||||
from .template import *
|
|
@ -9,9 +9,9 @@ from common.drf.filters import BaseFilterSet, UUIDInFilter
|
|||
from common.mixins import RecordViewLogMixin
|
||||
from common.permissions import UserConfirmation
|
||||
from authentication.const import ConfirmType
|
||||
from ..tasks.account_connectivity import test_accounts_connectivity_manual
|
||||
from ..models import Account, Node
|
||||
from .. import serializers
|
||||
from assets.tasks.account_connectivity import test_accounts_connectivity_manual
|
||||
from assets.models import Account, Node
|
||||
from assets import serializers
|
||||
|
||||
__all__ = ['AccountFilterSet', 'AccountViewSet', 'AccountSecretsViewSet', 'AccountTaskCreateAPI']
|
||||
|
|
@ -4,9 +4,9 @@ from rest_framework import status, viewsets
|
|||
from rest_framework.response import Response
|
||||
|
||||
from orgs.mixins.api import OrgBulkModelViewSet
|
||||
from .. import serializers
|
||||
from ..tasks import execute_account_backup_plan
|
||||
from ..models import (
|
||||
from assets import serializers
|
||||
from assets.tasks import execute_account_backup_plan
|
||||
from assets.models import (
|
||||
AccountBackupPlan, AccountBackupPlanExecution
|
||||
)
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
from assets.api.accounts import (
|
||||
from .account import (
|
||||
AccountFilterSet, AccountViewSet, AccountSecretsViewSet
|
||||
)
|
||||
from common.mixins import RecordViewLogMixin
|
||||
from .. import serializers
|
||||
from ..models import Account
|
||||
from assets import serializers
|
||||
from assets.models import Account
|
||||
|
||||
__all__ = ['AccountHistoryViewSet', 'AccountHistorySecretsViewSet']
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
from orgs.mixins.api import OrgBulkModelViewSet
|
||||
from ..models import AccountTemplate
|
||||
from .. import serializers
|
||||
from assets.models import AccountTemplate
|
||||
from assets import serializers
|
||||
|
||||
|
||||
class AccountTemplateViewSet(OrgBulkModelViewSet):
|
|
@ -38,18 +38,19 @@ class Category(PlatformMixin, ChoicesMixin, models.TextChoices):
|
|||
return {
|
||||
cls.HOST: {
|
||||
'domain_enabled': True,
|
||||
'su_enabled': True,
|
||||
'ping_enabled': True,
|
||||
'gather_facts_enabled': True,
|
||||
'verify_account_enabled': True,
|
||||
'change_password_enabled': True,
|
||||
'create_account_enabled': True,
|
||||
'gather_accounts_enabled': True,
|
||||
'_protocols': ['ssh', 'sftp']
|
||||
'su_enabled': True, 'su_method': 'sudo',
|
||||
'ping_enabled': True, 'ping_method': 'ping',
|
||||
'gather_facts_enabled': True, 'gather_facts_method': 'gather_facts_posix',
|
||||
'verify_account_enabled': True, 'verify_account_method': 'verify_account_posix',
|
||||
'change_password_enabled': True, 'change_password_method': 'change_password_posix',
|
||||
'create_account_enabled': True, 'create_account_method': 'create_account_posix',
|
||||
'gather_accounts_enabled': True, 'gather_accounts_method': 'gather_accounts_posix',
|
||||
'_protocols': ['ssh', 'telnet'],
|
||||
},
|
||||
cls.NETWORKING: {
|
||||
'domain_enabled': True,
|
||||
'su_enabled': False,
|
||||
'ping_enabled': True, 'ping_method': 'ping',
|
||||
'gather_facts_enabled': False,
|
||||
'verify_account_enabled': False,
|
||||
'change_password_enabled': False,
|
||||
|
@ -65,15 +66,28 @@ class Category(PlatformMixin, ChoicesMixin, models.TextChoices):
|
|||
'change_password_enabled': True,
|
||||
'create_account_enabled': True,
|
||||
'gather_accounts_enabled': True,
|
||||
'_protocols': []
|
||||
},
|
||||
cls.WEB: {
|
||||
'domain_enabled': False,
|
||||
'su_enabled': False,
|
||||
'ping_enabled': False,
|
||||
'gather_facts_enabled': False,
|
||||
'verify_account_enabled': False,
|
||||
'change_password_enabled': False,
|
||||
'create_account_enabled': False,
|
||||
'gather_accounts_enabled': False,
|
||||
'_protocols': ['http', 'https']
|
||||
},
|
||||
cls.CLOUD: {
|
||||
'domain_enabled': False,
|
||||
'su_enabled': False,
|
||||
'ping_enabled': False,
|
||||
'gather_facts_enabled': False,
|
||||
'verify_account_enabled': False,
|
||||
'change_password_enabled': False,
|
||||
'create_account_enabled': False,
|
||||
'gather_accounts_enabled': False,
|
||||
'_protocols': []
|
||||
}
|
||||
}
|
||||
|
@ -83,9 +97,6 @@ class HostTypes(PlatformMixin, ChoicesMixin, models.TextChoices):
|
|||
LINUX = 'linux', 'Linux'
|
||||
WINDOWS = 'windows', 'Windows'
|
||||
UNIX = 'unix', 'Unix'
|
||||
BSD = 'bsd', 'BSD'
|
||||
MACOS = 'macos', 'MacOS'
|
||||
MAINFRAME = 'mainframe', _("Mainframe")
|
||||
OTHER_HOST = 'other_host', _("Other host")
|
||||
|
||||
@classmethod
|
||||
|
@ -95,20 +106,26 @@ class HostTypes(PlatformMixin, ChoicesMixin, models.TextChoices):
|
|||
'_protocols': ['ssh', 'rdp', 'vnc', 'telnet']
|
||||
},
|
||||
cls.WINDOWS: {
|
||||
'_protocols': ['ssh', 'rdp', 'vnc'],
|
||||
'gather_facts_method': 'gather_facts_windows',
|
||||
'verify_account_method': 'verify_account_windows',
|
||||
'change_password_method': 'change_password_windows',
|
||||
'create_account_method': 'create_account_windows',
|
||||
'gather_accounts_method': 'gather_accounts_windows',
|
||||
'_protocols': ['rdp', 'ssh', 'vnc'],
|
||||
'su_enabled': False
|
||||
},
|
||||
cls.MACOS: {
|
||||
cls.UNIX: {
|
||||
'_protocols': ['ssh', 'vnc']
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NetworkingTypes(PlatformMixin, ChoicesMixin, models.TextChoices):
|
||||
GENERAL = 'general', _("General device")
|
||||
SWITCH = 'switch', _("Switch")
|
||||
ROUTER = 'router', _("Router")
|
||||
FIREWALL = 'firewall', _("Firewall")
|
||||
OTHER_NETWORK = 'other_network', _("Other device")
|
||||
OTHER_NETWORK = 'other', _("Other device")
|
||||
|
||||
|
||||
class DatabaseTypes(PlatformMixin, ChoicesMixin, models.TextChoices):
|
||||
|
@ -125,7 +142,12 @@ class DatabaseTypes(PlatformMixin, ChoicesMixin, models.TextChoices):
|
|||
meta = {}
|
||||
for name, label in cls.choices:
|
||||
meta[name] = {
|
||||
'_protocols': [name]
|
||||
'_protocols': [name],
|
||||
'gather_facts_method': f'gather_facts_{name}',
|
||||
'verify_account_method': f'verify_account_{name}',
|
||||
'change_password_method': f'change_password_{name}',
|
||||
'create_account_method': f'create_account_{name}',
|
||||
'gather_accounts_method': f'gather_accounts_{name}',
|
||||
}
|
||||
return meta
|
||||
|
||||
|
|
|
@ -12,38 +12,15 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='DeviceInfo',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
||||
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('vendor', models.CharField(blank=True, max_length=64, null=True, verbose_name='Vendor')),
|
||||
('model', models.CharField(blank=True, max_length=54, null=True, verbose_name='Model')),
|
||||
('sn', models.CharField(blank=True, max_length=128, null=True, verbose_name='Serial number')),
|
||||
('cpu_model', models.CharField(blank=True, max_length=64, null=True, verbose_name='CPU model')),
|
||||
('cpu_count', models.IntegerField(null=True, verbose_name='CPU count')),
|
||||
('cpu_cores', models.IntegerField(null=True, verbose_name='CPU cores')),
|
||||
('cpu_vcpus', models.IntegerField(null=True, verbose_name='CPU vcpus')),
|
||||
('memory', models.CharField(blank=True, max_length=64, null=True, verbose_name='Memory')),
|
||||
('disk_total', models.CharField(blank=True, max_length=1024, null=True, verbose_name='Disk total')),
|
||||
('disk_info', models.CharField(blank=True, max_length=1024, null=True, verbose_name='Disk info')),
|
||||
('os', models.CharField(blank=True, max_length=128, null=True, verbose_name='OS')),
|
||||
('os_version', models.CharField(blank=True, max_length=16, null=True, verbose_name='OS version')),
|
||||
('os_arch', models.CharField(blank=True, max_length=16, null=True, verbose_name='OS arch')),
|
||||
('hostname_raw', models.CharField(blank=True, max_length=128, null=True, verbose_name='Hostname raw')),
|
||||
('number', models.CharField(blank=True, max_length=128, null=True, verbose_name='Asset number')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'DeviceInfo',
|
||||
},
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='info',
|
||||
field=models.JSONField(blank=True, default=dict, verbose_name='Info'),
|
||||
),
|
||||
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')),
|
||||
('device_info', models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.deviceinfo', verbose_name='Host')),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
@ -4,46 +4,6 @@ from django.utils import timezone
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
def migrate_hardware(apps, *args):
|
||||
host_model = apps.get_model('assets', 'Host')
|
||||
asset_model = apps.get_model('assets', 'Asset')
|
||||
hardware_model = apps.get_model('assets', 'DeviceInfo')
|
||||
|
||||
created = 0
|
||||
batch_size = 1000
|
||||
|
||||
excludes = ['id', 'host', 'date_updated']
|
||||
fields = [f.name for f in hardware_model._meta.fields]
|
||||
fields = [name for name in fields if name not in excludes]
|
||||
|
||||
while True:
|
||||
start = created
|
||||
end = created + batch_size
|
||||
hosts = host_model.objects.all()[start:end]
|
||||
asset_ids = [h.asset_ptr_id for h in hosts]
|
||||
assets = asset_model.objects.filter(id__in=asset_ids)
|
||||
asset_mapper = {a.id: a for a in assets}
|
||||
|
||||
if not hosts:
|
||||
break
|
||||
|
||||
hardware_infos = []
|
||||
hosts_updated = []
|
||||
for host in hosts:
|
||||
hardware = hardware_model()
|
||||
asset = asset_mapper[host.asset_ptr_id]
|
||||
hardware.date_updated = timezone.now()
|
||||
for name in fields:
|
||||
setattr(hardware, name, getattr(asset, name))
|
||||
hardware_infos.append(hardware)
|
||||
host.device_info_id = hardware.id
|
||||
hosts_updated.append(host)
|
||||
|
||||
hardware_model.objects.bulk_create(hardware_infos, ignore_conflicts=True)
|
||||
host_model.objects.bulk_update(hosts_updated, ['device_info_id'])
|
||||
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')
|
||||
|
@ -64,6 +24,34 @@ def migrate_to_host(apps, schema_editor):
|
|||
created += len(hosts)
|
||||
|
||||
|
||||
def migrate_hardware_info(apps, *args):
|
||||
asset_model = apps.get_model("assets", "Asset")
|
||||
|
||||
count = 0
|
||||
batch_size = 1000
|
||||
hardware_fields = [
|
||||
'vendor', 'model', 'sn', 'cpu_model', 'cpu_count', 'cpu_cores',
|
||||
'cpu_vcpus', 'memory', 'disk_total', 'disk_info', 'os', 'os_arch',
|
||||
'os_version', 'hostname_raw', 'number'
|
||||
]
|
||||
|
||||
while True:
|
||||
start = count
|
||||
end = count + batch_size
|
||||
assets = asset_model.objects.all()[start:end]
|
||||
if not assets:
|
||||
break
|
||||
|
||||
updated = []
|
||||
for asset in assets:
|
||||
info = {getattr(asset, field) for field in hardware_fields if getattr(asset, field)}
|
||||
if not info:
|
||||
continue
|
||||
asset.info = info
|
||||
updated.append(asset)
|
||||
asset_model.objects.bulk_update(updated, ['info'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
|
@ -71,6 +59,6 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_hardware_info),
|
||||
migrations.RunPython(migrate_to_host),
|
||||
migrations.RunPython(migrate_hardware),
|
||||
]
|
||||
|
|
|
@ -48,6 +48,10 @@ class Migration(migrations.Migration):
|
|||
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')),
|
||||
('url', models.CharField(max_length=1024, verbose_name='url')),
|
||||
('autofill', models.CharField(default='basic', max_length=16)),
|
||||
('password_selector', models.CharField(blank=True, default='', max_length=128)),
|
||||
('submit_selector', models.CharField(blank=True, default='', max_length=128)),
|
||||
('username_selector', models.CharField(blank=True, default='', max_length=128))
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# Generated by Django 3.1.14 on 2022-04-30 14:41
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -19,11 +18,6 @@ class Migration(migrations.Migration):
|
|||
('setting', models.JSONField(default=dict, verbose_name='Setting')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='domain_default',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.domain', verbose_name='Domain default'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='domain_enabled',
|
||||
|
@ -62,12 +56,12 @@ class Migration(migrations.Migration):
|
|||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='ping_enabled',
|
||||
field=models.BooleanField(default=False),
|
||||
field=models.BooleanField(default=False, verbose_name='Ping enabled'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='ping_method',
|
||||
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Ping method'),
|
||||
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='Ping method'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
|
@ -89,4 +83,24 @@ class Migration(migrations.Migration):
|
|||
name='verify_account_method',
|
||||
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Verify account method'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='gather_accounts_enabled',
|
||||
field=models.BooleanField(default=False, verbose_name='Gather facts enabled'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='gather_accounts_method',
|
||||
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='gather_facts_enabled',
|
||||
field=models.BooleanField(default=False, verbose_name='Gather facts enabled'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='gather_facts_method',
|
||||
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -21,6 +21,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
|
||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
|
||||
('password', common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
|
||||
('private_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
|
||||
|
@ -38,6 +39,7 @@ class Migration(migrations.Migration):
|
|||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('asset', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='assets.asset', verbose_name='Asset')),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('su_from', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='assets.account', verbose_name='Su from')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Account',
|
||||
|
@ -52,6 +54,7 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||
('username', models.CharField(blank=True, db_index=True, max_length=128, verbose_name='Username')),
|
||||
('password', common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
|
||||
('private_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
|
||||
|
@ -63,12 +66,13 @@ class Migration(migrations.Migration):
|
|||
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
|
||||
('privileged', models.BooleanField(default=False, verbose_name='Privileged account')),
|
||||
('version', models.IntegerField(default=0, verbose_name='Version')),
|
||||
('asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.asset', verbose_name='Asset')),
|
||||
('asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='accounts', to='assets.asset', verbose_name='Asset')),
|
||||
('su_from', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='su_to', to='assets.account', verbose_name='Su from')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Account',
|
||||
'permissions': [('view_accountsecret', 'Can view asset account secret'), ('change_accountsecret', 'Can change asset account secret'), ('view_historyaccount', 'Can view asset history account'), ('view_historyaccountsecret', 'Can view asset history account secret')],
|
||||
'unique_together': {('username', 'asset')},
|
||||
'unique_together': {('username', 'asset'), ('name', 'asset')},
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -40,7 +40,7 @@ def migrate_accounts(apps, schema_editor):
|
|||
values['version'] = 1
|
||||
|
||||
system_user = auth_book.systemuser
|
||||
if auth_book.systemuser:
|
||||
if system_user:
|
||||
values.update({attr: getattr(system_user, attr) for attr in auth_attrs})
|
||||
values['created_by'] = str(system_user.id)
|
||||
values['privileged'] = system_user.type == 'admin'
|
||||
|
@ -48,6 +48,7 @@ def migrate_accounts(apps, schema_editor):
|
|||
auth_book_auth = {attr: getattr(auth_book, attr) for attr in auth_attrs}
|
||||
auth_book_auth = {attr: value for attr, value in auth_book_auth.items() if value}
|
||||
values.update(auth_book_auth)
|
||||
values['name'] = values['username']
|
||||
|
||||
account = account_model(**values)
|
||||
accounts.append(account)
|
||||
|
|
|
@ -41,6 +41,11 @@ class Migration(migrations.Migration):
|
|||
old_name='hostname',
|
||||
new_name='name',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='name',
|
||||
field=models.CharField(max_length=128, verbose_name='Name'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='date_updated',
|
||||
|
|
|
@ -1,44 +1,10 @@
|
|||
# Generated by Django 3.2.13 on 2022-08-29 11:46
|
||||
# Generated by Django 3.2.14 on 2022-09-14 12:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
from assets.const import Category
|
||||
from assets.models import Type
|
||||
|
||||
|
||||
def update_account_backup_type(apps, schema_editor):
|
||||
backup_model = apps.get_model('assets', 'AccountBackupPlan')
|
||||
all_number = 4294967295
|
||||
asset_number = Type.choices_to_value([Category.HOST])
|
||||
app_number = Type.choices_to_value([
|
||||
Category.NETWORKING, Category.DATABASE, Category.CLOUD, Category.WEB]
|
||||
)
|
||||
|
||||
backup_model.objects.filter(types=255).update(types=all_number)
|
||||
backup_model.objects.filter(types=1).update(types=asset_number)
|
||||
backup_model.objects.filter(types=2).update(types=app_number)
|
||||
|
||||
backup_execution_model = apps.get_model('assets', 'AccountBackupPlanExecution')
|
||||
choices_dict = {
|
||||
'all': Type.get_types(value=all_number),
|
||||
'asset': Type.get_types(value=asset_number),
|
||||
'app': Type.get_types(value=app_number)
|
||||
}
|
||||
qs_dict = {
|
||||
'all': backup_execution_model.objects.filter(plan__types=255),
|
||||
'asset': backup_execution_model.objects.filter(plan__types=1),
|
||||
'app': backup_execution_model.objects.filter(plan__types=2)
|
||||
}
|
||||
|
||||
backup_executions = []
|
||||
for k, qs in qs_dict.items():
|
||||
type_choices = choices_dict[k]
|
||||
for i in qs:
|
||||
i.plan_snapshot['types'] = type_choices
|
||||
backup_executions.append(i)
|
||||
backup_execution_model.objects.bulk_update(backup_executions, fields=['plan_snapshot'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0106_auto_20220819_1523'),
|
||||
]
|
||||
|
@ -47,13 +13,6 @@ class Migration(migrations.Migration):
|
|||
migrations.AlterField(
|
||||
model_name='accountbackupplan',
|
||||
name='types',
|
||||
field=models.BigIntegerField(
|
||||
choices=[(4294967295, 'All'), (1, 'Linux'), (2, 'Windows'), (4, 'Unix'), (8, 'BSD'), (16, 'MacOS'),
|
||||
(32, 'Mainframe'), (64, 'Other host'), (127, 'Host'), (128, 'Switch'), (256, 'Router'),
|
||||
(512, 'Firewall'), (1024, 'Other device'), (1920, 'NetworkDevice'), (2048, 'MySQL'),
|
||||
(4096, 'MariaDB'), (8192, 'PostgreSQL'), (16384, 'Oracle'), (32768, 'SQLServer'),
|
||||
(65536, 'MongoDB'), (131072, 'Redis'), (260096, 'Database'), (262144, 'Clouding'),
|
||||
(524288, 'Web')], default=4294967295, verbose_name='Type'),
|
||||
field=models.BigIntegerField(),
|
||||
),
|
||||
migrations.RunPython(update_account_backup_type),
|
||||
]
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
# Generated by Django 3.2.14 on 2022-09-01 02:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0107_alter_accountbackupplan_types'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='create_account_enabled',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='create_account_method',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='domain_default',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='domain_enabled',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='ping_enabled',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='ping_method',
|
||||
),
|
||||
]
|
|
@ -1,30 +0,0 @@
|
|||
# Generated by Django 3.2.14 on 2022-09-01 06:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0108_auto_20220901_1034'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='host',
|
||||
name='device_info',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='info',
|
||||
field=models.JSONField(blank=True, default=dict, verbose_name='Info'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='database',
|
||||
name='version',
|
||||
field=models.CharField(blank=True, max_length=16, verbose_name='Version'),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='DeviceInfo',
|
||||
),
|
||||
]
|
|
@ -1,43 +0,0 @@
|
|||
# Generated by Django 3.2.14 on 2022-09-01 07:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0109_auto_20220901_1431'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='create_account_enabled',
|
||||
field=models.BooleanField(default=False, verbose_name='Create account enabled'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='create_account_method',
|
||||
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Create account method'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='gather_accounts_enabled',
|
||||
field=models.BooleanField(default=False, verbose_name='Gather facts enabled'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='gather_accounts_method',
|
||||
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='gather_facts_enabled',
|
||||
field=models.BooleanField(default=False, verbose_name='Gather facts enabled'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='gather_facts_method',
|
||||
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method'),
|
||||
),
|
||||
]
|
|
@ -1,29 +0,0 @@
|
|||
# Generated by Django 3.2.14 on 2022-09-08 11:58
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0110_auto_20220901_1542'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='domain_enabled',
|
||||
field=models.BooleanField(default=True, verbose_name='Domain enalbed'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='account',
|
||||
name='asset',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='accounts', to='assets.asset', verbose_name='Asset'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='name',
|
||||
field=models.CharField(max_length=128, verbose_name='Name'),
|
||||
),
|
||||
]
|
|
@ -1,38 +0,0 @@
|
|||
# Generated by Django 3.2.14 on 2022-09-09 11:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0111_auto_20220908_1958'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='web',
|
||||
name='autofill',
|
||||
field=models.CharField(default='basic', max_length=16),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='web',
|
||||
name='password_selector',
|
||||
field=models.CharField(blank=True, default='', max_length=128),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='web',
|
||||
name='submit_selector',
|
||||
field=models.CharField(blank=True, default='', max_length=128),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='web',
|
||||
name='username_selector',
|
||||
field=models.CharField(blank=True, default='', max_length=128),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='platform',
|
||||
name='domain_enabled',
|
||||
field=models.BooleanField(default=True, verbose_name='Domain enabled'),
|
||||
),
|
||||
]
|
|
@ -3,20 +3,29 @@ from django.utils.translation import gettext_lazy as _
|
|||
from simple_history.models import HistoricalRecords
|
||||
|
||||
from common.utils import lazyproperty
|
||||
|
||||
from .base import BaseAccount
|
||||
|
||||
__all__ = ['Account', 'AccountTemplate']
|
||||
|
||||
|
||||
class Account(BaseAccount):
|
||||
asset = models.ForeignKey('assets.Asset', related_name='accounts', on_delete=models.CASCADE, verbose_name=_('Asset'))
|
||||
asset = models.ForeignKey(
|
||||
'assets.Asset', related_name='accounts',
|
||||
on_delete=models.CASCADE, verbose_name=_('Asset')
|
||||
)
|
||||
su_from = models.ForeignKey(
|
||||
'assets.Account', related_name='su_to', null=True,
|
||||
on_delete=models.SET_NULL, verbose_name=_("Su from")
|
||||
)
|
||||
version = models.IntegerField(default=0, verbose_name=_('Version'))
|
||||
history = HistoricalRecords()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Account')
|
||||
unique_together = [('username', 'asset')]
|
||||
unique_together = [
|
||||
('username', 'asset'),
|
||||
('name', 'asset'),
|
||||
]
|
||||
permissions = [
|
||||
('view_accountsecret', _('Can view asset account secret')),
|
||||
('change_accountsecret', _('Can change asset account secret')),
|
||||
|
@ -24,10 +33,6 @@ class Account(BaseAccount):
|
|||
('view_historyaccountsecret', _('Can view asset history account secret')),
|
||||
]
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return "{}({})_{}".format(self.asset_name, self.ip, self.username)
|
||||
|
||||
@lazyproperty
|
||||
def ip(self):
|
||||
return self.asset.ip
|
||||
|
|
|
@ -6,7 +6,6 @@ from .common import Asset
|
|||
|
||||
class Database(Asset):
|
||||
db_name = models.CharField(max_length=1024, verbose_name=_("Database"), blank=True)
|
||||
version = models.CharField(max_length=16, verbose_name=_("Version"), blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return '{}({}://{}/{})'.format(self.name, self.type, self.ip, self.db_name)
|
||||
|
|
|
@ -3,4 +3,5 @@ from .common import Asset
|
|||
|
||||
|
||||
class Networking(Asset):
|
||||
|
||||
pass
|
||||
|
|
|
@ -71,7 +71,7 @@ class Type(BitOperationChoice):
|
|||
|
||||
class AccountBackupPlan(CommonModelMixin, PeriodTaskModelMixin, OrgModelMixin):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
types = models.BigIntegerField(choices=Type.DB_CHOICES, default=Type.ALL, verbose_name=_('Type'))
|
||||
types = models.BigIntegerField()
|
||||
recipients = models.ManyToManyField(
|
||||
'users.User', related_name='recipient_escape_route_plans', blank=True,
|
||||
verbose_name=_("Recipient")
|
||||
|
|
|
@ -9,6 +9,12 @@ __all__ = ['Platform', 'PlatformProtocol']
|
|||
|
||||
|
||||
class PlatformProtocol(models.Model):
|
||||
SETTING_ATTRS = {
|
||||
'console': True,
|
||||
'security': 'any,tls,rdp',
|
||||
'sftp_enabled': True,
|
||||
'sftp_home': '/tmp'
|
||||
}
|
||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||
port = models.IntegerField(verbose_name=_('Port'))
|
||||
setting = models.JSONField(verbose_name=_('Setting'), default=dict)
|
||||
|
@ -34,6 +40,8 @@ class Platform(models.Model):
|
|||
domain_enabled = models.BooleanField(default=True, verbose_name=_("Domain enabled"))
|
||||
protocols_enabled = models.BooleanField(default=True, verbose_name=_("Protocols enabled"))
|
||||
protocols = models.ManyToManyField(PlatformProtocol, blank=True, verbose_name=_("Protocols"))
|
||||
ping_enabled = models.BooleanField(default=False, verbose_name=_("Ping enabled"))
|
||||
ping_method = models.CharField(max_length=32, blank=True, null=True, verbose_name=_("Ping method"))
|
||||
gather_facts_enabled = models.BooleanField(default=False, verbose_name=_("Gather facts enabled"))
|
||||
gather_facts_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Gather facts method"))
|
||||
# 账号有关的
|
||||
|
@ -61,71 +69,7 @@ class Platform(models.Model):
|
|||
|
||||
@staticmethod
|
||||
def set_default_platforms_ops(platform_model):
|
||||
default_ok = {
|
||||
'su_enabled': True,
|
||||
'su_method': 'sudo',
|
||||
'domain_enabled': True,
|
||||
'change_password_enabled': True,
|
||||
'change_password_method': 'change_password_linux',
|
||||
'verify_account_enabled': True,
|
||||
'verify_account_method': 'ansible_posix_ping',
|
||||
}
|
||||
db_default = {
|
||||
'su_enabled': False,
|
||||
'domain_enabled': True,
|
||||
'change_password_enabled': True,
|
||||
'verify_account_enabled': True,
|
||||
}
|
||||
|
||||
platform_ops_map = {
|
||||
('host', 'linux'): {
|
||||
**default_ok,
|
||||
'change_password_method': 'change_password_linux',
|
||||
'verify_account_method': 'ansible_posix_ping'
|
||||
},
|
||||
('host', 'windows'): {
|
||||
**default_ok,
|
||||
'su_enabled': False,
|
||||
'change_password_method': 'change_password_windows',
|
||||
'verify_account_method': 'ansible_win_ping'
|
||||
},
|
||||
('host', 'unix'): {
|
||||
**default_ok,
|
||||
'verify_account_method': 'ansible_posix_ping',
|
||||
'change_password_method': 'change_password_aix'
|
||||
},
|
||||
('database', 'mysql'): {
|
||||
**db_default,
|
||||
'verify_account_method': 'mysql_ping',
|
||||
'change_password_method': 'change_password_mysql'
|
||||
},
|
||||
('database', 'postgresql'): {
|
||||
**db_default,
|
||||
'verify_account_method': 'postgresql_ping',
|
||||
'change_password_method': 'change_password_postgresql'
|
||||
},
|
||||
('database', 'oracle'): {
|
||||
**db_default,
|
||||
'verify_account_method': 'oracle_ping',
|
||||
'change_password_method': 'change_password_oracle'
|
||||
},
|
||||
('database', 'sqlserver'): {
|
||||
**db_default,
|
||||
'verify_account_method': 'mysql_ping',
|
||||
'change_password_method': 'change_password_sqlserver'
|
||||
},
|
||||
}
|
||||
platforms = platform_model.objects.all()
|
||||
|
||||
updated = []
|
||||
for p in platforms:
|
||||
attrs = platform_ops_map.get((p.category, p.type), {})
|
||||
if not attrs:
|
||||
continue
|
||||
for k, v in attrs.items():
|
||||
setattr(p, k, v)
|
||||
updated.append(p)
|
||||
platform_model.objects.bulk_update(updated, list(default_ok.keys()))
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django.utils import timezone
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -21,3 +19,53 @@ def private_key_validator(value):
|
|||
_('%(value)s is not an even number'),
|
||||
params={'value': value},
|
||||
)
|
||||
|
||||
|
||||
def update_internal_platforms(platform_model):
|
||||
from assets.const import AllTypes
|
||||
|
||||
platforms = [
|
||||
{'name': 'Linux', 'category': 'host', 'type': 'linux'},
|
||||
{'name': 'BSD', 'category': 'host', 'type': 'unix'},
|
||||
{'name': 'Unix', 'category': 'host', 'type': 'unix'},
|
||||
{'name': 'MacOS', 'category': 'host', 'type': 'unix'},
|
||||
{'name': 'Windows', 'category': 'host', 'type': 'unix'},
|
||||
{
|
||||
'name': 'AIX', 'category': 'host', 'type': 'unix',
|
||||
'create_account_method': 'create_account_aix',
|
||||
'change_password_method': 'change_password_aix',
|
||||
},
|
||||
{'name': 'Windows', 'category': 'host', 'type': 'windows'},
|
||||
{'name': 'Windows-TLS', 'category': 'host', 'type': 'windows'},
|
||||
{'name': 'Windows-RDP', 'category': 'host', 'type': 'windows'},
|
||||
|
||||
# 数据库
|
||||
{'name': 'MySQL', 'category': 'database', 'type': 'mysql'},
|
||||
{'name': 'PostgreSQL', 'category': 'database', 'type': 'postgresql'},
|
||||
{'name': 'Oracle', 'category': 'database', 'type': 'oracle'},
|
||||
{'name': 'SQLServer', 'category': 'database', 'type': 'sqlserver'},
|
||||
{'name': 'MongoDB', 'category': 'database', 'type': 'mongodb'},
|
||||
{'name': 'Redis', 'category': 'database', 'type': 'redis'},
|
||||
|
||||
# 网络设备
|
||||
{'name': 'Generic', 'category': 'networking', 'type': 'general'},
|
||||
{'name': 'Huawei', 'category': 'networking', 'type': 'general'},
|
||||
{'name': 'Cisco', 'category': 'networking', 'type': 'general'},
|
||||
{'name': 'H3C', 'category': 'networking', 'type': 'general'},
|
||||
|
||||
# Web
|
||||
|
||||
# Cloud
|
||||
]
|
||||
|
||||
platforms = platform_model.objects.all()
|
||||
|
||||
updated = []
|
||||
for p in platforms:
|
||||
attrs = platform_ops_map.get((p.category, p.type), {})
|
||||
if not attrs:
|
||||
continue
|
||||
for k, v in attrs.items():
|
||||
setattr(p, k, v)
|
||||
updated.append(p)
|
||||
platform_model.objects.bulk_update(updated, list(default_ok.keys()))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- hosts: {{ account.asset.name }}
|
||||
- hosts: all
|
||||
vars:
|
||||
account:
|
||||
username: {{ account.username }}
|
||||
|
|
|
@ -4,7 +4,8 @@ from rest_framework import serializers
|
|||
|
||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||
from common.drf.serializers import SecretReadableMixin
|
||||
from assets.models import Account, AccountTemplate
|
||||
from common.drf.fields import ObjectRelatedField
|
||||
from assets.models import Account, AccountTemplate, Asset
|
||||
from assets.serializers.base import AuthValidateMixin
|
||||
from .common import AccountFieldsSerializerMixin
|
||||
|
||||
|
@ -14,7 +15,9 @@ class AccountSerializerCreateMixin(serializers.ModelSerializer):
|
|||
required=False, allow_null=True, write_only=True,
|
||||
label=_('Account template')
|
||||
)
|
||||
push_to_asset = serializers.BooleanField(default=False, label=_("Push to asset"), write_only=True)
|
||||
push_now = serializers.BooleanField(
|
||||
default=False, label=_("Push now"), write_only=True
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def validate_template(value):
|
||||
|
@ -39,30 +42,34 @@ class AccountSerializerCreateMixin(serializers.ModelSerializer):
|
|||
account_template = attrs.pop('template', None)
|
||||
if account_template:
|
||||
self.replace_attrs(account_template, attrs)
|
||||
push_to_asset = attrs.pop('push_to_asset', False)
|
||||
self.push_now = attrs.pop('push_now', False)
|
||||
return super().validate(attrs)
|
||||
|
||||
def create(self, validated_data):
|
||||
instance = super().create(validated_data)
|
||||
if self.push_now:
|
||||
print("Start push account to asset")
|
||||
# Todo: push it
|
||||
pass
|
||||
return instance
|
||||
|
||||
|
||||
class AccountSerializer(AuthValidateMixin,
|
||||
AccountSerializerCreateMixin,
|
||||
AccountFieldsSerializerMixin,
|
||||
BulkOrgResourceModelSerializer):
|
||||
name = serializers.CharField(max_length=128, read_only=True, label=_("Name"))
|
||||
ip = serializers.ReadOnlyField(label=_("IP"))
|
||||
asset_name = serializers.ReadOnlyField(label=_("Asset"))
|
||||
asset = ObjectRelatedField(required=False, queryset=Asset.objects, label=_('Asset'), attrs=('id', 'name', 'ip'))
|
||||
platform = serializers.ReadOnlyField(label=_("Platform"))
|
||||
|
||||
class Meta(AccountFieldsSerializerMixin.Meta):
|
||||
model = Account
|
||||
fields = AccountFieldsSerializerMixin.Meta.fields \
|
||||
+ ['template', 'push_to_asset']
|
||||
+ ['template', 'push_now']
|
||||
|
||||
@classmethod
|
||||
def setup_eager_loading(cls, queryset):
|
||||
""" Perform necessary eager loading of data. """
|
||||
queryset = queryset.prefetch_related('asset') \
|
||||
.annotate(ip=F('asset__ip')) \
|
||||
.annotate(asset_name=F('asset__name'))
|
||||
queryset = queryset.prefetch_related('asset')
|
||||
return queryset
|
||||
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ __all__ = ['AccountFieldsSerializerMixin']
|
|||
class AccountFieldsSerializerMixin(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
fields_mini = [
|
||||
'id', 'name', 'username', 'privileged', 'ip',
|
||||
'asset_name', 'platform', 'version'
|
||||
'id', 'name', 'username', 'privileged',
|
||||
'platform', 'version'
|
||||
]
|
||||
fields_write_only = ['password', 'private_key', 'public_key', 'passphrase']
|
||||
fields_other = ['date_created', 'date_updated', 'comment']
|
||||
|
|
|
@ -54,9 +54,12 @@ class AssetAccountSerializer(AccountSerializer):
|
|||
|
||||
class Meta(AccountSerializer.Meta):
|
||||
fields_mini = [
|
||||
'id', 'name', 'username', 'privileged', 'version'
|
||||
'id', 'name', 'username', 'privileged', 'version',
|
||||
]
|
||||
fields_write_only = [
|
||||
'password', 'private_key', 'public_key',
|
||||
'passphrase', 'token', 'push_now'
|
||||
]
|
||||
fields_write_only = ['password', 'private_key', 'public_key', 'passphrase', 'token']
|
||||
fields = fields_mini + fields_write_only
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ class Migration(migrations.Migration):
|
|||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('assets', '0111_auto_20220908_1958'),
|
||||
('assets', '0106_auto_20220819_1523'),
|
||||
('ops', '0022_auto_20220817_1346'),
|
||||
]
|
||||
|
Loading…
Reference in New Issue