diff --git a/apps/assets/const.py b/apps/assets/const.py index ca33a93bb..5a46d8d31 100644 --- a/apps/assets/const.py +++ b/apps/assets/const.py @@ -16,8 +16,10 @@ class PlatformMixin: def platform_constraints(cls): return { 'domain_enabled': False, - 'gather_facts_enabled': False, 'su_enabled': False, + 'vendor_enabled': False, + 'ping_enabled': False, + 'gather_facts_enabled': False, 'change_password_enabled': False, 'verify_account_enabled': False, 'create_account_enabled': False, @@ -49,6 +51,15 @@ class Category(PlatformMixin, ChoicesMixin, models.TextChoices): }, cls.NETWORKING: { 'domain_enabled': True, + 'brand_enabled': True, + 'brands': [ + ('huawei', 'Huawei'), + ('cisco', 'Cisco'), + ('juniper', 'Juniper'), + ('h3c', 'H3C'), + ('dell', 'Dell'), + ('other', 'Other'), + ], 'su_enabled': False, 'ping_enabled': True, 'ping_method': 'ping', 'gather_facts_enabled': False, @@ -125,7 +136,6 @@ class NetworkingTypes(PlatformMixin, ChoicesMixin, models.TextChoices): SWITCH = 'switch', _("Switch") ROUTER = 'router', _("Router") FIREWALL = 'firewall', _("Firewall") - OTHER_NETWORK = 'other', _("Other device") class DatabaseTypes(PlatformMixin, ChoicesMixin, models.TextChoices): diff --git a/apps/assets/migrations/0108_auto_20220915_1032.py b/apps/assets/migrations/0108_auto_20220915_1032.py new file mode 100644 index 000000000..21f663df8 --- /dev/null +++ b/apps/assets/migrations/0108_auto_20220915_1032.py @@ -0,0 +1,90 @@ +# 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.AddField( + model_name='platform', + name='brand', + field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Brand'), + ), + 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'), + ), + ] diff --git a/apps/assets/models/cmd_filter.py b/apps/assets/models/cmd_filter.py index 53189018c..916170cfd 100644 --- a/apps/assets/models/cmd_filter.py +++ b/apps/assets/models/cmd_filter.py @@ -101,7 +101,6 @@ class CommandFilterRule(OrgModelMixin): s = self.construct_command_regex(content=self.content) else: s = r'{0}'.format(self.content) - return s @classmethod diff --git a/apps/assets/models/platform.py b/apps/assets/models/platform.py index 8ca79254a..513e8a7c5 100644 --- a/apps/assets/models/platform.py +++ b/apps/assets/models/platform.py @@ -5,7 +5,7 @@ from assets.const import AllTypes from common.db.fields import JsonDictTextField -__all__ = ['Platform', 'PlatformProtocol'] +__all__ = ['Platform', 'PlatformProtocol', 'PlatformAutomation'] class PlatformProtocol(models.Model): @@ -20,6 +20,21 @@ class PlatformProtocol(models.Model): setting = models.JSONField(verbose_name=_('Setting'), default=dict) +class PlatformAutomation(models.Model): + 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")) + create_account_enabled = models.BooleanField(default=False, verbose_name=_("Create account enabled")) + create_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Create account method")) + change_password_enabled = models.BooleanField(default=False, verbose_name=_("Change password enabled")) + change_password_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Change password method")) + verify_account_enabled = models.BooleanField(default=False, verbose_name=_("Verify account enabled")) + verify_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Verify account method")) + gather_accounts_enabled = models.BooleanField(default=False, verbose_name=_("Gather facts enabled")) + gather_accounts_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Gather facts method")) + + class Platform(models.Model): """ 对资产提供 约束和默认值 @@ -37,24 +52,14 @@ class Platform(models.Model): comment = models.TextField(blank=True, null=True, verbose_name=_("Comment")) # 资产有关的 charset = models.CharField(default='utf8', choices=CHARSET_CHOICES, max_length=8, verbose_name=_("Charset")) + brand = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Brand")) # 厂商主要是给网络设备 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")) # 账号有关的 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")) - create_account_enabled = models.BooleanField(default=False, verbose_name=_("Create account enabled")) - create_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Create account method")) - change_password_enabled = models.BooleanField(default=False, verbose_name=_("Change password enabled")) - change_password_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Change password method")) - verify_account_enabled = models.BooleanField(default=False, verbose_name=_("Verify account enabled")) - verify_account_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Verify account method")) - gather_accounts_enabled = models.BooleanField(default=False, verbose_name=_("Gather facts enabled")) - gather_accounts_method = models.TextField(max_length=32, blank=True, null=True, verbose_name=_("Gather facts method")) + automation = models.OneToOneField(PlatformAutomation, on_delete=models.CASCADE, related_name='platform', blank=True, null=True, verbose_name=_("Automation")) @property def type_constraints(self): diff --git a/apps/assets/serializers/platform.py b/apps/assets/serializers/platform.py index 9559ea70d..9c94a45f2 100644 --- a/apps/assets/serializers/platform.py +++ b/apps/assets/serializers/platform.py @@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _ from common.drf.fields import LabeledChoiceField from common.drf.serializers import JMSWritableNestedModelSerializer -from ..models import Platform, PlatformProtocol +from ..models import Platform, PlatformProtocol, PlatformAutomation from ..const import Category, AllTypes @@ -26,43 +26,18 @@ class ProtocolSettingSerializer(serializers.Serializer): sftp_home = serializers.CharField(default='/tmp', label=_("SFTP home")) -class PlatformProtocolsSerializer(serializers.ModelSerializer): - setting = ProtocolSettingSerializer(required=False, allow_null=True) - +class PlatformAutomationSerializer(serializers.ModelSerializer): class Meta: - model = PlatformProtocol - fields = ['id', 'name', 'port', 'setting'] - - -class PlatformSerializer(JMSWritableNestedModelSerializer): - type = LabeledChoiceField(choices=AllTypes.choices, label=_("Type")) - category = LabeledChoiceField(choices=Category.choices, label=_("Category")) - protocols = PlatformProtocolsSerializer(label=_('Protocols'), many=True, required=False) - su_method = LabeledChoiceField( - choices=[('sudo', 'sudo su -'), ('su', 'su - ')], - label='切换方式', required=False, default='sudo' - ) - - class Meta: - model = Platform - fields_mini = ['id', 'name', 'internal'] - fields_small = fields_mini + [ - 'category', 'type', 'charset', - ] - fields = fields_small + [ - 'protocols_enabled', 'protocols', 'domain_enabled', + model = PlatformAutomation + fields = [ + 'id', 'ping_enabled', 'ping_method', 'gather_facts_enabled', 'gather_facts_method', - 'su_enabled', 'su_method', - 'gather_accounts_enabled', 'gather_accounts_method', 'create_account_enabled', 'create_account_method', - 'verify_account_enabled', 'verify_account_method', 'change_password_enabled', 'change_password_method', - 'comment', + 'verify_account_enabled', 'verify_account_method', + 'gather_accounts_enabled', 'gather_accounts_method', ] extra_kwargs = { - 'su_enabled': {'label': '启用切换账号'}, - 'domain_enabled': {'label': "启用网域"}, - 'domain_default': {'label': "默认网域"}, 'gather_facts_enabled': {'label': '启用收集信息'}, 'gather_facts_method': {'label': '收集信息方式'}, 'verify_account_enabled': {'label': '启用校验账号'}, @@ -75,16 +50,58 @@ class PlatformSerializer(JMSWritableNestedModelSerializer): 'gather_accounts_method': {'label': '收集账号方式'}, } - def validate(self, attrs): - fields_to_check = [ - ('verify_account_enabled', 'verify_account_method'), - ('create_account_enabled', 'create_account_method'), - ('change_password_enabled', 'change_password_method'), + +class PlatformProtocolsSerializer(serializers.ModelSerializer): + setting = ProtocolSettingSerializer(required=False, allow_null=True) + + class Meta: + model = PlatformProtocol + fields = ['id', 'name', 'port', 'setting'] + + +class PlatformSerializer(JMSWritableNestedModelSerializer): + type = LabeledChoiceField(choices=AllTypes.choices, label=_("Type")) + category = LabeledChoiceField(choices=Category.choices, label=_("Category")) + protocols = PlatformProtocolsSerializer(label=_('Protocols'), many=True, required=False) + automation = PlatformAutomationSerializer(label=_('Automation'), required=False) + su_method = LabeledChoiceField( + choices=[('sudo', 'sudo su -'), ('su', 'su - ')], + label='切换方式', required=False, default='sudo' + ) + brand = LabeledChoiceField(choices=[], label='厂商', required=False, allow_null=True) + + class Meta: + model = Platform + fields_mini = ['id', 'name', 'internal'] + fields_small = fields_mini + [ + 'category', 'type', 'charset', ] - for method_enabled, method_name in fields_to_check: - if attrs.get(method_enabled, False) and not attrs.get(method_name, False): - raise serializers.ValidationError({method_name: _('This field is required.')}) - return attrs + fields = fields_small + [ + 'protocols_enabled', 'protocols', 'domain_enabled', + 'su_enabled', 'su_method', 'brand', 'automation', 'comment', + ] + extra_kwargs = { + 'su_enabled': {'label': '启用切换账号'}, + 'domain_enabled': {'label': "启用网域"}, + 'domain_default': {'label': "默认网域"}, + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.set_brand_choices() + + def set_brand_choices(self): + field = self.fields.get('brand') + request = self.context.get('request') + if not field or not request: + return + category = request.query_params.get('category', '') + constraints = Category.platform_constraints().get(category) + if not constraints: + return + field.choices = constraints.get('brands', []) + if field.choices: + field.required = True class PlatformOpsMethodSerializer(serializers.Serializer):