perf: 优化 asset migrations

pull/8931/head
ibuler 2022-09-22 15:24:32 +08:00
parent 21a60bf55e
commit cc859f302a
21 changed files with 213 additions and 223 deletions

View File

@ -49,3 +49,10 @@ class BaseType(TextChoices):
def _get_automation_constrains(cls) -> dict:
raise NotImplementedError
@classmethod
def internal_platforms(cls):
raise NotImplementedError
@classmethod
def create_or_update_internal_platforms(cls):
data = cls._internal_platforms()

View File

@ -39,3 +39,11 @@ class CloudTypes(BaseType):
'choices': ['k8s']
}
}
@classmethod
def internal_platforms(cls):
return {
cls.PUBLIC: [],
cls.PRIVATE: [{'name': 'Vmware-vSphere'}],
cls.K8S: [{'name': 'Kubernetes'}],
}

View File

@ -42,3 +42,15 @@ class DatabaseTypes(BaseType):
}
}
@classmethod
def internal_platforms(cls):
return {
cls.MYSQL: [{'name': 'MySQL'}],
cls.MARIADB: [{'name': 'MariaDB'}],
cls.POSTGRESQL: [{'name': 'PostgreSQL'}],
cls.ORACLE: [{'name': 'Oracle'}],
cls.SQLSERVER: [{'name': 'SQLServer'}],
cls.MONGODB: [{'name': 'MongoDB'}],
cls.REDIS: [{'name': 'Redis'}],
}

View File

@ -39,3 +39,12 @@ class DeviceTypes(BaseType):
'create_account_enabled': False,
}
}
@classmethod
def internal_platforms(cls):
return {
cls.GENERAL: [{'name': 'General'}, {'name': 'Cisco'}, {'name': 'Huawei'}, {'name': 'H3C'}],
cls.SWITCH: [],
cls.ROUTER: [],
cls.FIREWALL: []
}

View File

@ -12,8 +12,19 @@ class HostTypes(BaseType):
return {
'*': {
'charset_enabled': True,
'charset': 'utf-8', # default
'domain_enabled': True,
'su_enabled': True,
'su_methods': [
{
'name': 'sudo su',
'id': 'sudo su'
},
{
'name': 'su -',
'id': 'su -'
}
],
},
cls.WINDOWS: {
'su_enabled': False,
@ -43,3 +54,30 @@ class HostTypes(BaseType):
'create_account_enabled': True,
}
}
@classmethod
def internal_platforms(cls):
return {
cls.LINUX: [
{'name': 'Linux'},
],
cls.UNIX: [
{'name': 'Unix'},
{'name': 'macOS'},
{'name': 'BSD'},
{'name': 'AIX', 'automation': {
'create_account_method': 'create_account_aix',
'change_password_method': 'change_password_aix'
}},
],
cls.WINDOWS: [
{'name': 'Windows'},
{'name': 'Windows-TLS', 'protocol_settings': {
'rdp': {'security': 'tls'},
}},
{'name': 'Windows-RDP', 'protocol_settings': {
'rdp': {'security': 'rdp'},
}}
],
cls.OTHER_HOST: []
}

View File

@ -76,6 +76,25 @@ class AllTypes(ChoicesMixin, metaclass=IncludesTextChoicesMeta):
data['constraints'] = []
return data
@classmethod
def grouped_choices(cls):
grouped_types = [(str(ca), tp.choices) for ca, tp in cls.category_types()]
return grouped_types
@classmethod
def grouped_choices_to_objs(cls):
choices = cls.serialize_to_objs(Category.choices)
mapper = dict(cls.grouped_choices())
for choice in choices:
children = cls.serialize_to_objs(mapper[choice['value']])
choice['children'] = children
return choices
@staticmethod
def serialize_to_objs(choices):
title = ['value', 'display_name']
return [dict(zip(title, choice)) for choice in choices]
@classmethod
def category_types(cls):
return (
@ -111,3 +130,45 @@ class AllTypes(ChoicesMixin, metaclass=IncludesTextChoicesMeta):
tp_node = cls.choice_to_node(tp, category_node.id, meta={'type': 'type'})
nodes.append(tp_node)
return nodes
@classmethod
def get_type_default_platform(cls, category, tp):
constraints = cls.get_constraints(category, tp)
data = {
'name': tp.label, 'category': category.value,
'type': tp.value, 'internal': True,
'charset': constraints.get('charset', 'utf-8'),
'domain_enabled': constraints.get('domain_enabled', False),
'su_enabled': constraints.get('su_enabled', False),
}
if data['su_enabled'] and data.get('su_methods'):
data['su_method'] = data['su_methods'][0]['id']
protocols = constraints.get('protocols', [])
for p in protocols:
p.pop('secret_types', None)
data['protocols'] = protocols
automation = constraints.get('automation', {})
enable_fields = {k: v for k, v in automation.items() if k.endswith('_enabled')}
for k, v in enable_fields.items():
auto_item = k.replace('_enabled', '')
methods = automation.pop(auto_item + '_methods', [])
if methods:
automation[auto_item + '_method'] = methods[0]['id']
data['automation'] = automation
return data
@classmethod
def create_or_update_internal_platforms(cls):
from assets.models import Platform
for category, type_cls in cls.category_types():
data = type_cls.internal_platforms()
for tp, platform_datas in data.items():
for d in platform_datas:
platform_data = {
**d, 'category': category.value, 'type': tp.value,
'internal': True, 'charset': 'utf-8'
}

View File

@ -36,3 +36,11 @@ class WebTypes(BaseType):
'choices': ['http'],
}
}
@classmethod
def internal_platforms(cls):
return {
cls.WEBSITE: [
{'name': 'Website'},
],
}

View File

@ -17,11 +17,6 @@ class Migration(migrations.Migration):
name='info',
field=models.JSONField(blank=True, default=dict, verbose_name='Info'),
),
migrations.RenameField(
model_name='asset',
old_name='ip',
new_name='address',
),
migrations.CreateModel(
name='Host',
fields=[

View File

@ -66,4 +66,7 @@ class Migration(migrations.Migration):
model_name='asset',
name='vendor',
),
migrations.DeleteModel(
name='Cluster',
),
]

View File

@ -55,7 +55,7 @@ def migrate_database_to_asset(apps, *args):
attrs.update(_attrs)
db = db_model(
id=app.id, hostname=app.name, address=attrs['host'],
id=app.id, hostname=app.name, ip=attrs['host'],
protocols='{}/{}'.format(app.type, attrs['port']),
db_name=attrs['database'] or '',
platform=platforms_map[app.type],
@ -83,7 +83,7 @@ def migrate_cloud_to_asset(apps, *args):
print("Create cloud: {}".format(app.name))
cloud = cloud_model(
id=app.id, hostname=app.name,
address=attrs.get('cluster', ''),
ip=attrs.get('cluster', ''),
protocols='', platform=platform,
org_id=app.org_id,
)

View File

@ -16,8 +16,32 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=32, verbose_name='Name')),
('port', models.IntegerField(verbose_name='Port')),
('setting', models.JSONField(default=dict, verbose_name='Setting')),
('platform', models.ForeignKey(on_delete=models.deletion.CASCADE, related_name='protocols', to='assets.platform'),),
],
),
migrations.CreateModel(
name='PlatformAutomation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ping_enabled', models.BooleanField(default=False, verbose_name='Ping enabled')),
('ping_method', models.CharField(blank=True, max_length=32, null=True, verbose_name='Ping method')),
('gather_facts_enabled', models.BooleanField(default=False, verbose_name='Gather facts enabled')),
('gather_facts_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method')),
('create_account_enabled', models.BooleanField(default=False, verbose_name='Create account enabled')),
('create_account_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Create account method')),
('change_password_enabled', models.BooleanField(default=False, verbose_name='Change password enabled')),
('change_password_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Change password method')),
('verify_account_enabled', models.BooleanField(default=False, verbose_name='Verify account enabled')),
('verify_account_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Verify account method')),
('gather_accounts_enabled', models.BooleanField(default=False, verbose_name='Gather facts enabled')),
('gather_accounts_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method')),
],
),
migrations.AddField(
model_name='platform',
name='automation',
field=models.OneToOneField(blank=True, null=True, on_delete=models.deletion.CASCADE, related_name='platform', to='assets.platformautomation', verbose_name='Automation'),
),
migrations.AddField(
model_name='platform',
name='domain_enabled',
@ -28,41 +52,6 @@ class Migration(migrations.Migration):
name='protocols_enabled',
field=models.BooleanField(default=True, verbose_name='Protocols enabled'),
),
migrations.AddField(
model_name='platform',
name='protocols',
field=models.ManyToManyField(blank=True, to='assets.PlatformProtocol', verbose_name='Protocols'),
),
migrations.AddField(
model_name='platform',
name='change_password_enabled',
field=models.BooleanField(default=False, verbose_name='Change password enabled'),
),
migrations.AddField(
model_name='platform',
name='change_password_method',
field=models.TextField(blank=True, max_length=32, null=True, verbose_name='Change password method'),
),
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='ping_enabled',
field=models.BooleanField(default=False, verbose_name='Ping enabled'),
),
migrations.AddField(
model_name='platform',
name='ping_method',
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='Ping method'),
),
migrations.AddField(
model_name='platform',
name='su_enabled',
@ -73,34 +62,4 @@ class Migration(migrations.Migration):
name='su_method',
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='SU method'),
),
migrations.AddField(
model_name='platform',
name='verify_account_enabled',
field=models.BooleanField(default=False, verbose_name='Verify account enabled'),
),
migrations.AddField(
model_name='platform',
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'),
),
]

View File

@ -79,4 +79,24 @@ class Migration(migrations.Migration):
name='su_from',
field=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'),
),
migrations.CreateModel(
name='AccountTemplate',
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')),
('secret_type', models.CharField(choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), ('token', 'Token')], default='password', max_length=16, verbose_name='Secret type'),),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
('privileged', models.BooleanField(default=False, verbose_name='Privileged')),
],
options={
'verbose_name': 'Account template',
'unique_together': {('name', 'org_id')},
},
),
]

View File

@ -24,7 +24,4 @@ class Migration(migrations.Migration):
('asset', models.ForeignKey(on_delete=models.deletion.CASCADE, related_name='protocols', to='assets.asset', verbose_name='Asset')),
],
),
migrations.DeleteModel(
name='Cluster',
),
]

View File

@ -59,6 +59,11 @@ class Migration(migrations.Migration):
name='name',
field=models.CharField(max_length=128, verbose_name='Name'),
),
migrations.RenameField(
model_name='asset',
old_name='ip',
new_name='address',
),
migrations.AddField(
model_name='asset',
name='date_updated',
@ -74,4 +79,5 @@ class Migration(migrations.Migration):
name='created_by',
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by'),
),
]

View File

@ -1,36 +0,0 @@
# Generated by Django 3.2.13 on 2022-08-19 07:23
import assets.models.base
import common.db.fields
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
dependencies = [
('assets', '0105_auto_20220817_1544'),
]
operations = [
migrations.CreateModel(
name='AccountTemplate',
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')),
('secret_type', models.CharField(choices=[('password', 'Password'), ('ssh_key', 'SSH key'), ('access_key', 'Access key'), ('token', 'Token')], default='password', max_length=16, verbose_name='Secret type'),),
('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
('privileged', models.BooleanField(default=False, verbose_name='Privileged')),
],
options={
'verbose_name': 'Account template',
'unique_together': {('name', 'org_id')},
},
),
]

View File

@ -49,10 +49,15 @@ def migrate_backup_types(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
('assets', '0108_auto_20220915_1032'),
('assets', '0105_auto_20220817_1544'),
]
operations = [
migrations.AlterField(
model_name='accountbackupplan',
name='types',
field=models.BigIntegerField(),
),
migrations.AddField(
model_name='accountbackupplan',
name='categories',

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.14 on 2022-09-14 12:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0106_auto_20220819_1523'),
]
operations = [
migrations.AlterField(
model_name='accountbackupplan',
name='types',
field=models.BigIntegerField(),
),
]

View File

@ -1,85 +0,0 @@
# Generated by Django 3.2.14 on 2022-09-15 02:32
from django.db import migrations, models
import django
class Migration(migrations.Migration):
dependencies = [
('assets', '0107_alter_accountbackupplan_types'),
]
operations = [
migrations.CreateModel(
name='PlatformAutomation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ping_enabled', models.BooleanField(default=False, verbose_name='Ping enabled')),
('ping_method', models.CharField(blank=True, max_length=32, null=True, verbose_name='Ping method')),
('gather_facts_enabled', models.BooleanField(default=False, verbose_name='Gather facts enabled')),
('gather_facts_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method')),
('create_account_enabled', models.BooleanField(default=False, verbose_name='Create account enabled')),
('create_account_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Create account method')),
('change_password_enabled', models.BooleanField(default=False, verbose_name='Change password enabled')),
('change_password_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Change password method')),
('verify_account_enabled', models.BooleanField(default=False, verbose_name='Verify account enabled')),
('verify_account_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Verify account method')),
('gather_accounts_enabled', models.BooleanField(default=False, verbose_name='Gather facts enabled')),
('gather_accounts_method', models.TextField(blank=True, max_length=32, null=True, verbose_name='Gather facts method')),
],
),
migrations.RemoveField(
model_name='platform',
name='change_password_enabled',
),
migrations.RemoveField(
model_name='platform',
name='change_password_method',
),
migrations.RemoveField(
model_name='platform',
name='create_account_enabled',
),
migrations.RemoveField(
model_name='platform',
name='create_account_method',
),
migrations.RemoveField(
model_name='platform',
name='gather_accounts_enabled',
),
migrations.RemoveField(
model_name='platform',
name='gather_accounts_method',
),
migrations.RemoveField(
model_name='platform',
name='gather_facts_enabled',
),
migrations.RemoveField(
model_name='platform',
name='gather_facts_method',
),
migrations.RemoveField(
model_name='platform',
name='ping_enabled',
),
migrations.RemoveField(
model_name='platform',
name='ping_method',
),
migrations.RemoveField(
model_name='platform',
name='verify_account_enabled',
),
migrations.RemoveField(
model_name='platform',
name='verify_account_method',
),
migrations.AddField(
model_name='platform',
name='automation',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='platform', to='assets.platformautomation', verbose_name='Automation'),
),
]

View File

@ -18,6 +18,7 @@ class PlatformProtocol(models.Model):
name = models.CharField(max_length=32, verbose_name=_('Name'))
port = models.IntegerField(verbose_name=_('Port'))
setting = models.JSONField(verbose_name=_('Setting'), default=dict)
platform = models.ForeignKey('Platform', on_delete=models.CASCADE, related_name='protocols')
class PlatformAutomation(models.Model):
@ -54,11 +55,11 @@ class Platform(models.Model):
charset = models.CharField(default='utf8', choices=CHARSET_CHOICES, max_length=8, verbose_name=_("Charset"))
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"))
# 账号有关的
su_enabled = models.BooleanField(default=False, verbose_name=_("Su enabled"))
su_method = models.CharField(max_length=32, blank=True, null=True, verbose_name=_("SU method"))
automation = models.OneToOneField(PlatformAutomation, on_delete=models.CASCADE, related_name='platform', blank=True, null=True, verbose_name=_("Automation"))
automation = models.OneToOneField(PlatformAutomation, on_delete=models.CASCADE, related_name='platform',
blank=True, null=True, verbose_name=_("Automation"))
@property
def type_constraints(self):

View File

@ -59,17 +59,17 @@ def update_internal_platforms(platform_model):
{'name': 'Redis', 'category': 'database', 'type': 'redis'},
# 网络设备
{'name': 'Generic', 'category': 'device', 'type': 'general', 'brand': 'other'},
{'name': 'Huawei', 'category': 'device', 'type': 'general', 'brand': 'huawei'},
{'name': 'Cisco', 'category': 'device', 'type': 'general', 'brand': 'cisco'},
{'name': 'H3C', 'category': 'device', 'type': 'general', 'brand': 'h3c'},
{'name': 'Generic', 'category': 'device', 'type': 'general'},
{'name': 'Huawei', 'category': 'device', 'type': 'general'},
{'name': 'Cisco', 'category': 'device', 'type': 'general'},
{'name': 'H3C', 'category': 'device', 'type': 'general'},
# Web
{'name': 'Website', 'category': 'web', 'type': 'general'},
# Cloud
{'name': 'Kubernetes', 'category': 'cloud', 'type': 'k8s'},
{'name': 'VMware vSphere', 'category': 'cloud', 'type': 'vsphere'},
{'name': 'VMware vSphere', 'category': 'cloud', 'type': 'private'},
]
platforms = platform_model.objects.all()

View File

@ -11,7 +11,7 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assets', '0106_auto_20220819_1523'),
('assets', '0105_auto_20220817_1544'),
('ops', '0022_auto_20220817_1346'),
]