class IPAddressSerializer(BonkTriggerMixin, HistorySerializerMixin): id = serializers.CharField(required=False) tags = serializers.DictField(required=False) state = serializers.ChoiceField(required=True, choices=['allocated', 'reserved', 'quarantine']) vrf = serializers.IntegerField(required=True, validators=[validate_vrf]) ip = serializers.IPAddressField(required=True) name = serializers.CharField(required=True, validators=[validate_fqdn]) dhcp_mac = serializers.ListField(child=serializers.CharField(validators=[validate_mac]), required=False) reference = serializers.CharField(required=False) permissions = PermissionsSerializer(required=False) ttl = serializers.IntegerField(required=False, validators=[validate_ttl]) class Meta(RethinkSerializer.Meta): table_name = 'ip_address' slug_field = 'vrf_ip' indices = [ 'ip', 'name', ('vrf_ip', (r.row['vrf'], r.row['ip'])), ('permissions_read', r.row['permissions']['read'], {'multi': True}), ('permissions_create', r.row['permissions']['create'], {'multi': True}), ('permissions_write', r.row['permissions']['write'], {'multi': True}), ] unique_together = [ ('vrf', 'ip'), ] def create_link(self, instance): return reverse('bonk:address_detail', kwargs={ 'vrf': instance['vrf'], 'ip': instance['ip'], }, request=self.context.get('request')) @classmethod def filter_by_prefix(cls, prefix, reql=False): return cls.filter(lambda a: r.ip_prefix_contains( r.ip_prefix(prefix['network'], prefix['length']), r.ip_address(a['ip']) ), reql=reql) def validate_name(self, value): possibles = [] for part in value.split(".")[:0:-1]: suffix = "" if len(possibles) == 0 else ("." + possibles[-1]) possibles.append(part + suffix) try: zone = DNSZoneSerializer.filter(lambda zone: r.expr(possibles).contains(zone['name']), reql=True).order_by(r.desc(r.row['name'].count())).nth(0).run(self.conn) except r.errors.ReqlNonExistenceError: raise serializers.ValidationError("no zone matching %s could be found" % value) if 'request' in self.context and not self.context['request'].user.is_superuser: user_groups = set(self.context['request'].user.groups.all().values_list('name', flat=True)) if self.instance is not None and len(user_groups.intersection(set( self.instance.get('permissions', {}).get('write', []) ))) > 0: pass elif len(user_groups.intersection(set( zone.get('permissions', {}).get('create', []) + zone.get('permissions', {}).get('write', []) ))) == 0: raise serializers.ValidationError("you do not have permission to create names in %s" % zone['name']) try: ip_address = IPAddressSerializer.get(name=value) if self.instance is None or ip_address['id'] != self.instance['id']: raise serializers.ValidationError("%r is already in use by %s" % (value, ip_address['ip'])) except RethinkObjectNotFound: pass return value def validate(self, data): data = super(IPAddressSerializer, self).validate(data) full = self.get_updated_object(data) try: prefix = IPPrefixSerializer.get_by_ip(full['vrf'], full['ip']) except RethinkObjectNotFound: raise serializers.ValidationError("no prefix found for IP %s" % full['ip']) return data
class IPPrefixDDNSSerializer(DDNSSerializer): zone = serializers.CharField(required=True) server = serializers.IPAddressField(required=True)
class IPPrefixSerializer(BonkTriggerMixin, HistorySerializerMixin): id = serializers.CharField(required=False) tags = serializers.DictField(required=False) vrf = serializers.IntegerField(required=True, validators=[validate_vrf]) network = serializers.IPAddressField(required=True) length = serializers.IntegerField(required=True) asn = serializers.IntegerField(required=False) name = serializers.CharField(required=False) state = serializers.ChoiceField(required=True, choices=['allocated', 'reserved', 'quarantine']) permissions = PermissionsSerializer(required=False) gateway = serializers.IPAddressField(required=False) dhcp = IPPrefixDHCPSerializer(required=False) ddns = IPPrefixDDNSSerializer(required=False) reference = serializers.CharField(required=False) inventory_id = serializers.CharField(required=False) class Meta(RethinkSerializer.Meta): table_name = 'ip_prefix' slug_field = 'vrf_network_length' indices = [ 'name', ('vrf_network_length', (r.row['vrf'], r.row['network'], r.row['length'])), ('permissions_read', r.row['permissions']['read'], {'multi': True}), ('permissions_create', r.row['permissions']['create'], {'multi': True}), ('permissions_write', r.row['permissions']['write'], {'multi': True}), ] unique = [ 'name' ] unique_together = [ ('vrf', 'network', 'length'), ] def create_link(self, instance): return reverse('bonk:prefix_detail', kwargs={ 'vrf': instance['vrf'], 'network': instance['network'], 'length': instance['length'], }, request=self.context.get('request')) @classmethod def filter_by_block(cls, block, reql=False): return cls.filter(lambda p: r.ip_prefix_contains( r.ip_prefix(block['network'], block['length']), r.ip_address(p['network']) ), reql=reql) @classmethod def get_by_ip(cls, vrf, ip, reql=False): query = cls.filter(lambda p: r.ip_prefix_contains( r.ip_prefix(p['network'], p['length']), r.ip_address(ip) ), reql=True) \ .filter({'vrf': vrf}) \ .order_by(r.desc("length")).nth(0) if reql: return query else: try: return query.run(get_connection()) except r.errors.ReqlNonExistenceError: raise RethinkObjectNotFound("no prefix found for IP %s" % ip) def validate(self, data): data = super(IPPrefixSerializer, self).validate(data) full = self.get_updated_object(data) try: block = IPBlockSerializer.get_by_ip(full['vrf'], full['network']) except RethinkObjectNotFound: raise serializers.ValidationError("no block exists matching prefix %s/%d" % (full['network'], full['length'])) if block['length'] > full['length']: raise serializers.ValidationError("prefix %s/%d exceeds block of %s/%d" % (full['network'], full['length'], block['network'], block['length'])) if (self.instance is None and self.context['request'].user is not None and not self.context['request'].user.is_superuser ): allowed = set( block.get('permissions', {}).get('write', []) + block.get('permissions', {}).get('create', []) ) groups = set(self.context['request'].user.groups.all().values_list('name', flat=True)) if len(groups.intersection(allowed)) == 0: raise serializers.ValidationError("you do not have permissions to block %s/%d" % (block['network'], block['length'])) underlappers = [x for x in self.filter_by_block(full) if x[self.Meta.pk_field] != full.get(self.Meta.pk_field, None)] if len(underlappers) > 0: raise serializers.ValidationError("prefix %s/%d overlaps with %r" % (full['network'], full['length'], underlappers)) try: overlapper = IPPrefixSerializer.get_by_ip(full['vrf'], full['network']) if overlapper[self.Meta.pk_field] != full.get(self.Meta.pk_field, None): raise serializers.ValidationError("prefix %s/%d includes this prefix %s/%d" % (overlapper['network'], overlapper['length'], full['network'], full['length'])) except RethinkObjectNotFound: pass network = netaddr.IPNetwork("%s/%d" % (full['network'], full['length'])) if str(network.network) != full['network']: raise serializers.ValidationError("network is not the network address for %s/%d" % (full['network'], full['length'])) return data def create(self, data): import bonk.tasks data = super(IPPrefixSerializer, self).create(data) block = IPBlockSerializer.get_by_ip(data['vrf'], data['network']) if 'announced_by' in block and data['state'] == 'allocated': bonk.tasks.trigger_prefix_create.apply_async((data, block)) return data def update(self, instance, data): import bonk.tasks ret = super(IPPrefixSerializer, self).update(instance, data) block = IPBlockSerializer.get_by_ip(ret['vrf'], ret['network']) if 'announced_by' in block: if instance['state'] != 'allocated' and ret['state'] == 'allocated': bonk.tasks.trigger_prefix_create.apply_async((ret, block)) elif instance['state'] == 'allocated' and ret['state'] != 'allocated': bonk.tasks.trigger_prefix_delete.apply_async((ret, block)) return ret def delete(self): import bonk.tasks block = IPBlockSerializer.get_by_ip(self.instance['vrf'], self.instance['network']) if 'announced_by' in block and self.instance['state'] == 'allocated': bonk.tasks.trigger_prefix_delete.apply_async((self.instance, block)) for address in IPAddressSerializer.filter_by_prefix(self.instance): ip = IPAddressSerializer(address) ip.delete() ret = super(IPPrefixSerializer, self).delete() return ret
class DeviceCreateSerializer(serializers.ModelSerializer): customer = serializers.CharField(required=True, max_length=100, help_text="客户", error_messages={ "blank": "请输入客户名", "required": "请输入客户名" }) customer_token = serializers.CharField(max_length=30, required=True, help_text="商户编码", error_messages={ "blank": "请输入商户编码", "required": "请输入商户编码" }) main_record = serializers.CharField(max_length=100, required=True, help_text="主解析记录", error_messages={ "blank": "请输入主记录", "required": "请输入主记录" }) sub_record = serializers.CharField(max_length=100, required=True, help_text="副解析记录", error_messages={ "blank": "请输入副记录", "required": "请输入副记录" }) cdn_record = serializers.CharField(max_length=100, required=True, help_text="cdn解析记录", error_messages={ "blank": "请输入cdn记录", "required": "请输入cdn记录" }) main_ip = serializers.IPAddressField(required=True, help_text="主ip", error_messages={ "blank": "请输入主ip", "required": "请输入主ip" }) back_ip = serializers.IPAddressField(required=True, help_text="副ip", error_messages={ "blank": "请输入副ip", "required": "请输入副ip" }) apapa_ip = serializers.IPAddressField(required=False, allow_blank=True, allow_null=True, help_text="APAPAip") cdn_ip = serializers.IPAddressField(required=False, allow_blank=True, allow_null=True, help_text="CDNip") lan_ip = serializers.IPAddressField(read_only=False, allow_blank=True, allow_null=True, help_text='LANip') creater = serializers.CharField(max_length=30, required=True, help_text="搭建人", error_messages={ "blank": "请输入创建人", "required": "请输入创建人" }) def validate_custumer_token(self, custumer_token): if DeviceInfo.objects.filter(custumer_token=custumer_token).count(): raise serializers.ValidationError("商户编码已经存在") return custumer_token def validate_main_ip(self, main_ip): if DeviceInfo.objects.filter(~Q(customer_token=self.instance), main_ip=main_ip): instance = DeviceInfo.objects.filter( ~Q(customer_token=self.instance), main_ip=main_ip) raise serializers.ValidationError("该ip和{}客户主ip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(back_ip=main_ip): instance = DeviceInfo.objects.filter(back_ip=main_ip) raise serializers.ValidationError("该ip和{}客户副ip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(apapa_ip=main_ip): instance = DeviceInfo.objects.filter(apapa_ip=main_ip) raise serializers.ValidationError("该ip和{}客户apapaip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(cdn_ip=main_ip): instance = DeviceInfo.objects.filter(cdn_ip=main_ip) raise serializers.ValidationError("该ip和{}客户cdnip冲突,请查看".format( instance[0].customer_token)) return main_ip def validate_back_ip(self, back_ip): if DeviceInfo.objects.filter(main_ip=back_ip): instance = DeviceInfo.objects.filter(main_ip=back_ip) raise serializers.ValidationError("该ip和{}客户主ip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(~Q(customer_token=self.instance), back_ip=back_ip): instance = DeviceInfo.objects.filter( ~Q(customer_token=self.instance), back_ip=back_ip) raise serializers.ValidationError("该ip和{}客户副ip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(apapa_ip=back_ip): instance = DeviceInfo.objects.filter(apapa_ip=back_ip) raise serializers.ValidationError("该ip和{}客户apapaip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(cdn_ip=back_ip): instance = DeviceInfo.objects.filter(cdn_ip=back_ip) raise serializers.ValidationError("该ip和{}客户cdnip冲突,请查看".format( instance[0].customer_token)) return back_ip def validate_apapa_ip(self, apapa_ip): if apapa_ip: if DeviceInfo.objects.filter(main_ip=apapa_ip): instance = DeviceInfo.objects.filter(main_ip=apapa_ip) raise serializers.ValidationError("该ip和{}客户主ip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(back_ip=apapa_ip): instance = DeviceInfo.objects.filter(back_ip=apapa_ip) raise serializers.ValidationError("该ip和{}客户副ip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(~Q(customer_token=self.instance), apapa_ip=apapa_ip): instance = DeviceInfo.objects.filter( ~Q(customer_token=self.instance), apapa_ip=apapa_ip) raise serializers.ValidationError( "该ip和{}客户apapaip冲突,请查看".format(instance[0].customer_token)) if DeviceInfo.objects.filter(cdn_ip=apapa_ip): instance = DeviceInfo.objects.filter(cdn_ip=apapa_ip) raise serializers.ValidationError("该ip和{}客户cdnip冲突,请查看".format( instance[0].customer_token)) return apapa_ip def validate_cdn_ip(self, cdn_ip): if cdn_ip: if DeviceInfo.objects.filter(main_ip=cdn_ip): instance = DeviceInfo.objects.filter(main_ip=cdn_ip) raise serializers.ValidationError("该ip和{}客户主ip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(back_ip=cdn_ip): instance = DeviceInfo.objects.filter(back_ip=cdn_ip) raise serializers.ValidationError("该ip和{}客户副ip冲突,请查看".format( instance[0].customer_token)) if DeviceInfo.objects.filter(apapa_ip=cdn_ip): instance = DeviceInfo.objects.filter(apapa_ip=cdn_ip) raise serializers.ValidationError( "该ip和{}客户apapaip冲突,请查看".format(instance[0].customer_token)) if DeviceInfo.objects.filter(~Q(customer_token=self.instance), cdn_ip=cdn_ip): instance = DeviceInfo.objects.filter( ~Q(customer_token=self.instance), cdn_ip=cdn_ip) raise serializers.ValidationError("该ip和{}客户cdnip冲突,请查看".format( instance[0].customer_token)) return cdn_ip class Meta: model = DeviceInfo fields = "__all__"
class ConnectionRequestSerializerCreate(serializers.Serializer): ip_address = serializers.IPAddressField(protocol='both') node_identifier = serializers.CharField(max_length=VERIFY_KEY_LENGTH) port = serializers.IntegerField(allow_null=True, max_value=65535, min_value=0, required=False) protocol = serializers.ChoiceField(choices=PROTOCOL_CHOICES) def create(self, validated_data): """ Process validated connection request """ config_data = validated_data if config_data['node_type'] == BANK: create_bank_from_config_data(config_data=validated_data) if config_data['node_type'] == CONFIRMATION_VALIDATOR: create_validator_from_config_data(config_data=validated_data) return True @staticmethod def get_node_config(data): """ Attempt to connect to node Return nodes config data after validation """ ip_address = data['ip_address'] protocol = data['protocol'] try: address = format_address(ip_address=ip_address, port=data.get('port'), protocol=protocol) config_address = f'{address}/config' config_data = fetch(url=config_address, headers={}) if config_data['node_type'] == BANK: config_serializer = BankConfigurationSerializer( data=config_data) elif config_data['node_type'] == CONFIRMATION_VALIDATOR: config_serializer = ValidatorConfigurationSerializer( data=config_data) elif config_data['node_type'] == PRIMARY_VALIDATOR: raise serializers.ValidationError( 'Unable to accept connection requests from primary validators' ) else: raise serializers.ValidationError('Invalid node_type') config_node_identifier = config_data['node_identifier'] signed_node_identifier = data['node_identifier'] if config_node_identifier != signed_node_identifier: raise serializers.ValidationError( f'Node config node_identifier of {config_node_identifier} does not match ' f'signed node_identifier of {signed_node_identifier}') except Exception as e: logger.exception(e) raise serializers.ValidationError(e) if config_serializer.is_valid(): return config_data else: logger.exception(config_serializer.errors) raise serializers.ValidationError(config_serializer.errors) def update(self, instance, validated_data): raise RuntimeError('Method unavailable') def validate(self, data): """ Attempt to connect to node """ ip_address = data['ip_address'] protocol = data['protocol'] if Bank.objects.filter(ip_address=ip_address, protocol=protocol).exists(): raise serializers.ValidationError('Already connected to bank') if SelfConfiguration.objects.filter(ip_address=ip_address, protocol=protocol).exists(): raise serializers.ValidationError('Unable to connect to self') if Validator.objects.filter(ip_address=ip_address, protocol=protocol).exists(): raise serializers.ValidationError('Already connected to validator') return self.get_node_config(data) @staticmethod def validate_node_identifier(node_identifier): """ Validate node_identifier length """ if len(node_identifier) != VERIFY_KEY_LENGTH: raise serializers.ValidationError( f'node_identifier must be {VERIFY_KEY_LENGTH} characters long') if Bank.objects.filter(node_identifier=node_identifier).exists(): raise serializers.ValidationError( 'Bank with that node identifier already exists') if Validator.objects.filter(node_identifier=node_identifier).exists(): raise serializers.ValidationError( 'Validator with that node identifier already exists') return node_identifier
class IPLocationSerializer(natrix_serializers.NatrixSerializer): """IP and Location information """ ip = rest_serializers.IPAddressField() location = LocationSerializer(required=False, allow_null=True)
class TerminalInfo(natrix_serializers.NatrixSerializer): mac = rest_serializers.CharField(max_length=32) ip = rest_serializers.IPAddressField()
class UserSerializerrr(serializers.ModelSerializer): snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all()) article_slugs = serializers.SlugRelatedField(read_only=True, slug_field='slug', many=True, source='articles') last_connected_ip = serializers.IPAddressField(help_text="i'm out of ideas", protocol='ipv4', read_only=True) last_connected_at = serializers.DateField(help_text="really?", read_only=True) other_stuff = serializers.SerializerMethodField( help_text="the decorator should determine the serializer class for this") hint_example = MethodFieldExampleSerializer() @swagger_serializer_method(serializer_or_field=OtherStuffSerializer) def get_other_stuff(self, obj): """ method_field that uses a serializer internally. By using the decorator, we can tell drf-yasg how to represent this in Swagger :param obj: :return: """ return OtherStuffSerializer().data help_text_example_1 = serializers.SerializerMethodField( help_text="help text on field is set, so this should appear in swagger" ) @swagger_serializer_method(serializer_or_field=serializers.IntegerField( help_text="decorated instance help_text shouldn't appear in swagger because field has priority")) def get_help_text_example_1(self): """ method docstring shouldn't appear in swagger because field has priority :return: """ return 1 help_text_example_2 = serializers.SerializerMethodField() @swagger_serializer_method(serializer_or_field=serializers.IntegerField( help_text="instance help_text is set, so should appear in swagger")) def get_help_text_example_2(self): """ method docstring shouldn't appear in swagger because decorator has priority :return: """ return 1 help_text_example_3 = serializers.SerializerMethodField() @swagger_serializer_method(serializer_or_field=serializers.IntegerField()) def get_help_text_example_3(self): """ docstring is set so should appear in swagger as fallback :return: """ return 1 class Meta: model = User fields = ('id', 'username', 'email', 'articles', 'snippets', 'last_connected_ip', 'last_connected_at', 'article_slugs', 'other_stuff', 'hint_example', 'help_text_example_1', 'help_text_example_2', 'help_text_example_3')
class InstanceSerializer(serializers.Serializer): id = serializers.CharField(read_only=True) url = CustomHyperlinkedIdentityField(view_name='instance-detail', lookup_field='id', lookup_url_kwarg='pk', parent_url_kwargs=['cloud_pk']) name = serializers.CharField() public_ips = serializers.ListField(serializers.IPAddressField()) private_ips = serializers.ListField(serializers.IPAddressField()) instance_type_id = ProviderPKRelatedField( label="Instance Type", queryset='compute.instance_types', display_fields=['name'], display_format="{0}", required=True) instance_type_url = CustomHyperlinkedIdentityField( view_name='instance_type-detail', lookup_field='instance_type_id', lookup_url_kwarg='pk', parent_url_kwargs=['cloud_pk']) image_id = ProviderPKRelatedField(label="Image", queryset='compute.images', display_fields=['name', 'id'], display_format="{0} ({1})", required=True) image_id_url = CustomHyperlinkedIdentityField( view_name='machine_image-detail', lookup_field='image_id', lookup_url_kwarg='pk', parent_url_kwargs=['cloud_pk']) key_pair_name = ProviderPKRelatedField(label="Keypair Name", queryset='security.key_pairs', display_fields=['id'], display_format="{0}", required=True) zone_id = PlacementZonePKRelatedField(label="Placement Zone", queryset='non_empty_value', display_fields=['id'], display_format="{0}", required=True) security_group_ids = ProviderPKRelatedField( label="Security Groups", queryset='security.security_groups', display_fields=['name'], display_format="{0}", many=True) user_data = serializers.CharField(write_only=True, style={'base_template': 'textarea.html'}) def create(self, validated_data): provider = view_helpers.get_cloud_provider(self.context.get('view')) name = validated_data.get('name') image_id = validated_data.get('image_id') instance_type = validated_data.get('instance_type_id') kp_name = validated_data.get('key_pair_name') zone_id = validated_data.get('zone_id') security_group_ids = validated_data.get('security_group_ids') user_data = validated_data.get('user_data') try: return provider.compute.instances.create( name, image_id, instance_type, zone=zone_id, key_pair=kp_name, security_groups=security_group_ids, user_data=user_data) except Exception as e: raise serializers.ValidationError("{0}".format(e)) def update(self, instance, validated_data): try: if instance.name != validated_data.get('name'): instance.name = validated_data.get('name') return instance except Exception as e: raise serializers.ValidationError("{0}".format(e))
class CreateVirtualConfigSerializer(serializers.Serializer): domain = serializers.CharField( help_text='Domain name.', label='Domain', max_length=254, min_length=3, required=True ) ip = serializers.IPAddressField( help_text='IP Address.', label='IP Address', required=True ) port = serializers.ChoiceField( choices=[ 80, 443 ], help_text='Port.', label='Port', required=True ) user = serializers.RegexField( help_text='System user name.', label='User', max_length=32, min_length=2, regex='^[a-z][a-z0-9]+$', required=True ) def validate_domain(self, value): if not validators.domain(value): raise serializers.ValidationError( f"Domain '{value}' is invalid.", code='invalid' ) return value def validate_ip(self, value): ip = ipaddress.ip_address(value) if ip.version == 4: file = str(ip).replace('.', '_') else: file = str(ip).replace(':', '_') if not os.path.exists(f"{SystemPath.ip_base_dir()}{file}"): raise serializers.ValidationError( f"System IP '{ip}' Address does not exist.", code='not_found' ) return ip def validate_user(self, value): try: pwd.getpwnam(value).pw_uid except KeyError: raise serializers.ValidationError( f"System User '{value}' does not exist.", code='not_found' ) return value def validate(self, attrs): domain = attrs.get('domain') user = attrs.get('user') port = attrs.get('port') if not os.path.exists(f"{NginxPath.conf_dir()}.isInstalled"): raise serializers.ValidationError( 'Nginx Server has not yet been installed.', code='not_installed' ) elif os.path.exists(f"{NginxPath.sites_dir()}{domain}.{port}.conf"): raise serializers.ValidationError( 'Nginx Virtual Configuration already exists.', code='exists' ) elif not os.path.exists(f"{WebPath.www_dir(user)}/{domain}"): raise serializers.ValidationError( f"Web Domain '{domain}' does not exist.", code='not_found' ) return attrs def create(self, validated_data): validated_domain = validated_data['domain'] validated_ip = validated_data['ip'] validated_port = validated_data['port'] validated_user = validated_data['user'] path_config = f"{NginxPath.sites_dir()}{validated_domain}.{validated_port}.conf" path_config_enabled = f"{NginxPath.sites_enabled_dir()}{validated_domain}.{validated_port}.conf" ip = (str(validated_ip) if validated_ip.version == 4 else f"[{validated_ip}]") content = render_to_string(f"nginx/virtualhost_{validated_port}.tmpl") \ .replace('[WEB-DOMAIN]', validated_domain) \ .replace('[WEB-VHOST]', WebPath.www_dir(validated_user)) \ .replace('[WEB-VHOST-SSL]', WebPath.ssl_dir(validated_user)) \ .replace('[SYSTEM-IPADDRESS]', ip) handle = open(path_config, 'w') handle.write(content) handle.close() os.symlink(path_config, path_config_enabled) path_sites_conf = f"{NginxPath.sites_conf_dir()}{validated_domain}" if not os.path.exists(path_sites_conf): os.makedirs(path_sites_conf, 0o755) shutil.chown(path_sites_conf, user='******', group='root') return validated_data
class ServerAutoReportSerializer(serializers.Serializer): """ 服务器同步序列化类 """ ip = serializers.IPAddressField(required=True) hostname = serializers.CharField(required=True, max_length=20) cpu = serializers.CharField(required=True, max_length=50) mem = serializers.CharField(required=True, max_length=20) disk = serializers.CharField(required=True, max_length=200) os = serializers.CharField(required=True, max_length=50) sn = serializers.CharField(required=True, max_length=50) manufacturer= serializers.CharField(required=True) model_name = serializers.CharField(required=True) uuid = serializers.CharField(required=True, max_length=50) network = serializers.JSONField(required=True) def validate_manufacturer(self, value): try: return Manufacturer.objects.get(vendor_name__exact=value) except Manufacturer.DoesNotExist: return self.create_manufacturer(value) def validate(self, attrs): manufacturer_obj = attrs["manufacturer"] try: attrs["model_name"] = manufacturer_obj.productmodel_set.get(model_name__exact=attrs["model_name"]) except ProductModel.DoesNotExist: attrs["model_name"] = self.create_product_model(manufacturer_obj, attrs["model_name"]) return attrs def create_server(self, validated_data): network = validated_data.pop("network") server_obj = Server.objects.create(**validated_data) self.check_server_network_device(server_obj, network) return server_obj def create(self, validated_data): uuid = validated_data["uuid"].lower() sn = validated_data["sn"].lower() try: if sn == uuid or sn == "" or sn.startswith("vmware"): server_obj = Server.objects.get(uuid__icontains=uuid) else: server_obj = Server.objects.get(sn__icontains=sn) except Server.DoesNotExist: return self.create_server(validated_data) else: return self.update_server(server_obj, validated_data) def update_server(self, instance, validated_data): instance.hostname = validated_data.get("hostname", instance.hostname) instance.cpu = validated_data.get("cpu", instance.cpu) instance.ip = validated_data.get("ip", instance.ip) instance.mem = validated_data.get("mem", instance.mem) instance.disk = validated_data.get("disk", instance.disk) instance.os = validated_data.get("os", instance.os) instance.save() self.check_server_network_device(instance, validated_data["network"]) return instance def check_server_network_device(self,server_obj, network): """ 检查批定服务器有没有这些网卡设备,并作关联 """ network_device_queryset = server_obj.networkdevice_set.all() current_network_device_queryset = [] for device in network: try: network_device_obj = network_device_queryset.get(name__exact=device["name"]) except NetworkDevice.DoesNotExist: network_device_obj = self.create_network_device(server_obj, device) self.check_ip(network_device_obj, device["ips"]) current_network_device_queryset.append(network_device_obj) for network_device_obj in list(set(network_device_queryset) - set(current_network_device_queryset)): network_device_obj.delete() def check_ip(self, network_device_obj, ifnets): ip_queryset = network_device_obj.ip_set.all() current_ip_queryset = [] for ifnet in ifnets: try: ip_obj = ip_queryset.get(ip_addr__exact=ifnet["ip_addr"]) except IP.DoesNotExist: ip_obj = self.create_ip(network_device_obj, ifnet) current_ip_queryset.append(ip_obj) for ip_obj in list(set(ip_queryset) - set(current_ip_queryset)): ip_obj.delete() def create_ip(self, network_device_obj, ifnet): ifnet["device"] = network_device_obj return IP.objects.create(**ifnet) def create_network_device(self,server_obj, device): device.pop("ips") device["host"] = server_obj network_device_obj = NetworkDevice.objects.create(**device) return network_device_obj def create_manufacturer(self, vendor_name): return Manufacturer.objects.create(vendor_name=vendor_name) def create_product_model(self,manufacturer_obj, model_name): return ProductModel.objects.create(model_name=model_name, vendor=manufacturer_obj) def to_representation(self, instance): ret = { "hostname": instance.hostname, "ip": instance.ip } return ret
class VirtualMachineSerializer(structure_serializers.BaseResourceSerializer): endpoints = InstanceEndpointsSerializer(many=True, read_only=True) service = serializers.HyperlinkedRelatedField( source='service_project_link.service', view_name='azure-detail', read_only=True, lookup_field='uuid') service_project_link = serializers.HyperlinkedRelatedField( view_name='azure-spl-detail', queryset=models.AzureServiceProjectLink.objects.all(), allow_null=True, required=False, ) image = serializers.HyperlinkedRelatedField( view_name='azure-image-detail', lookup_field='uuid', queryset=models.Image.objects.all(), write_only=True) size = serializers.HyperlinkedRelatedField(view_name='azure-size-detail', lookup_field='uuid', queryset=SizeQueryset(), write_only=True) external_ips = serializers.ListField( child=serializers.IPAddressField(), read_only=True, ) user_username = serializers.CharField(required=True) user_password = serializers.CharField(required=True, style={'input_type': 'password'}) rdp = serializers.HyperlinkedIdentityField( view_name='azure-virtualmachine-rdp', lookup_field='uuid') class Meta(structure_serializers.BaseResourceSerializer.Meta): model = models.VirtualMachine view_name = 'azure-virtualmachine-detail' fields = structure_serializers.BaseResourceSerializer.Meta.fields + ( 'image', 'size', 'user_username', 'user_password', 'user_data', 'rdp', 'external_ips', 'internal_ips', 'runtime_state', 'start_time', 'cores', 'ram', 'disk', 'image_name', 'endpoints', ) protected_fields = structure_serializers.BaseResourceSerializer.Meta.protected_fields + ( 'image', 'size', 'user_username', 'user_password', 'user_data') read_only_fields = structure_serializers.BaseResourceSerializer.Meta.read_only_fields + ( 'external_ips', 'internal_ips', 'runtime_state', 'start_time', 'cores', 'ram', 'disk', 'image_name') def validate(self, attrs): attrs = super(VirtualMachineSerializer, self).validate(attrs) if not re.match(r'[a-zA-Z][a-zA-Z0-9-]{0,13}[a-zA-Z0-9]$', attrs['name']): raise serializers.ValidationError({ 'name': _("The name can contain only letters, numbers, and hyphens. " "The name must be shorter than 15 characters and start with " "a letter and must end with a letter or a number.") }) # passwords must contain characters from at least three of the following four categories: groups = (r'[a-z]', r'[A-Z]', r'[0-9]', r'[^a-zA-Z\d\s:]') password = attrs['user_password'] if not 6 <= len(password) <= 72 or sum( bool(re.search(g, password)) for g in groups) < 3: raise serializers.ValidationError({ 'user_password': _("The supplied password must be 6-72 characters long " "and contain 3 of the following: a lowercase character, " "an uppercase character, a number, a special character.") }) if re.match(r'Administrator|Admin', attrs['user_username'], re.I): raise serializers.ValidationError( {'user_username': _('Invalid administrator username.')}) return attrs @transaction.atomic def create(self, validated_data): image = validated_data['image'] validated_data['image_name'] = image.name size = validated_data['size'] validated_data['cores'] = size.cores validated_data['ram'] = size.ram validated_data['disk'] = size.disk return super(VirtualMachineSerializer, self).create(validated_data)
class RequestAssetPermTicketSerializer(serializers.ModelSerializer): actions = ActionsField(source='meta.actions', choices=Action.DB_CHOICES, default=Action.CONNECT) ips = serializers.ListField(child=serializers.IPAddressField(), source='meta.ips', default=list, label=_('IP group')) hostname = serializers.CharField(max_length=256, source='meta.hostname', default='', allow_blank=True, label=_('Hostname')) system_user = serializers.CharField(max_length=256, source='meta.system_user', default='', allow_blank=True, label=_('System user')) date_start = serializers.DateTimeField(source='meta.date_start', allow_null=True, required=False, label=_('Date start')) date_expired = serializers.DateTimeField(source='meta.date_expired', allow_null=True, required=False, label=_('Date expired')) confirmed_assets = serializers.ListField(child=serializers.UUIDField(), source='meta.confirmed_assets', default=list, required=False, label=_('Confirmed assets')) confirmed_system_users = serializers.ListField( child=serializers.UUIDField(), source='meta.confirmed_system_users', default=list, required=False, label=_('Confirmed system user')) assets_waitlist_url = serializers.SerializerMethodField() system_users_waitlist_url = serializers.SerializerMethodField() class Meta: model = Ticket mini_fields = ['id', 'title'] small_fields = [ 'status', 'action', 'date_created', 'date_updated', 'system_users_waitlist_url', 'type', 'type_display', 'action_display', 'ips', 'confirmed_assets', 'date_start', 'date_expired', 'confirmed_system_users', 'hostname', 'assets_waitlist_url', 'system_user', 'org_id', 'actions', 'comment' ] m2m_fields = [ 'user', 'user_display', 'assignees', 'assignees_display', 'assignee', 'assignee_display' ] fields = mini_fields + small_fields + m2m_fields read_only_fields = [ 'user_display', 'assignees_display', 'type', 'user', 'status', 'date_created', 'date_updated', 'action', 'id', 'assignee', 'assignee_display', ] extra_kwargs = { 'status': { 'label': _('Status') }, 'action': { 'label': _('Action') }, 'user_display': { 'label': _('User') }, 'org_id': { 'required': True } } def validate(self, attrs): org_id = attrs.get('org_id') assignees = attrs.get('assignees') instance = self.instance if instance is not None: if org_id and not assignees: assignees = list(instance.assignees.all()) elif assignees and not org_id: org_id = instance.org_id elif assignees and org_id: pass else: return attrs user = self.context['request'].user org = Organization.get_instance(org_id) if org is None: raise serializers.ValidationError(_('Invalid `org_id`')) q = Q(role=User.ROLE.ADMIN) if not org.is_default(): q |= Q(m2m_org_members__role=ORG_ROLE.ADMIN, orgs__id=org_id, orgs__members=user) q &= Q(id__in=[assignee.id for assignee in assignees]) count = User.objects.filter(q).distinct().count() if count != len(assignees): raise serializers.ValidationError( _('Field `assignees` must be organization admin or superuser')) return attrs def get_system_users_waitlist_url(self, instance: Ticket): if not self._is_assignee(instance): return None return reverse('api-assets:system-user-list') def get_assets_waitlist_url(self, instance: Ticket): if not self._is_assignee(instance): return None asset_api = reverse('api-assets:asset-list') query = '' meta = instance.meta hostname = meta.get('hostname') if hostname: query = '?search=%s' % hostname return asset_api + query def _recommend_assets(self, data, instance): confirmed_assets = data.get('confirmed_assets') if not confirmed_assets and self._is_assignee(instance): ips = data.get('ips') hostname = data.get('hostname') limit = 5 q = Q(id=None) if ips: limit = len(ips) + 2 q |= Q(ip__in=ips) if hostname: q |= Q(hostname__icontains=hostname) data['confirmed_assets'] = list( map(lambda x: str(x), chain( *Asset.objects.filter(q)[0:limit].values_list('id')))) def to_representation(self, instance): data = super().to_representation(instance) self._recommend_assets(data, instance) return data def _create_body(self, validated_data): meta = validated_data['meta'] type = Ticket.TYPE.get(validated_data.get('type', '')) date_start = dt_parser(meta.get('date_start')).strftime( settings.DATETIME_DISPLAY_FORMAT) date_expired = dt_parser(meta.get('date_expired')).strftime( settings.DATETIME_DISPLAY_FORMAT) validated_data['body'] = _(''' Type: {type}<br> User: {username}<br> Ip group: {ips}<br> Hostname: {hostname}<br> System user: {system_user}<br> Date start: {date_start}<br> Date expired: {date_expired}<br> ''').format(type=type, username=validated_data.get('user', ''), ips=', '.join(meta.get('ips', [])), hostname=meta.get('hostname', ''), system_user=meta.get('system_user', ''), date_start=date_start, date_expired=date_expired) def create(self, validated_data): # `type` 与 `user` 用户不可提交, validated_data['type'] = self.Meta.model.TYPE.REQUEST_ASSET_PERM validated_data['user'] = self.context['request'].user # `confirmed` 相关字段只能审批人修改,所以创建时直接清理掉 self._pop_confirmed_fields() self._create_body(validated_data) return super().create(validated_data) def save(self, **kwargs): """ 做了一些数据转换 """ meta = self.validated_data.get('meta', {}) org_id = self.validated_data.get('org_id') if org_id is not None and org_id == Organization.DEFAULT_ID: self.validated_data['org_id'] = '' # 时间的转换,好烦😭,可能有更好的办法吧 date_start = meta.get('date_start') if date_start: meta['date_start'] = dt_formater(date_start) date_expired = meta.get('date_expired') if date_expired: meta['date_expired'] = dt_formater(date_expired) # UUID 的转换 confirmed_system_users = meta.get('confirmed_system_users') if confirmed_system_users: meta['confirmed_system_users'] = [ str(system_user) for system_user in confirmed_system_users ] confirmed_assets = meta.get('confirmed_assets') if confirmed_assets: meta['confirmed_assets'] = [ str(asset) for asset in confirmed_assets ] with tmp_to_root_org(): return super().save(**kwargs) def update(self, instance, validated_data): new_meta = validated_data['meta'] if not self._is_assignee(instance): self._pop_confirmed_fields() # Json 字段保存的坑😭 old_meta = instance.meta meta = {} meta.update(old_meta) meta.update(new_meta) validated_data['meta'] = meta return super().update(instance, validated_data) def _pop_confirmed_fields(self): meta = self.validated_data['meta'] meta.pop('confirmed_assets', None) meta.pop('confirmed_system_users', None) def _is_assignee(self, obj: Ticket): user = self.context['request'].user return obj.is_assignee(user)
class LastSeenSerializer(serializers.Serializer): ip_of_seen = serializers.IPAddressField(required=True)
class ParticipantSerializer(serializers.Serializer): name = serializers.CharField(max_length=50) ip_address = serializers.IPAddressField() session_id = serializers.CharField(max_length=50)
class RadiusAccountingSerializer(serializers.ModelSerializer): framed_ip_address = serializers.IPAddressField(required=False, allow_blank=True) framed_ipv6_address = serializers.IPAddressField(required=False, allow_blank=True, protocol='IPv6') session_time = serializers.IntegerField(required=False, default=0) stop_time = serializers.DateTimeField(required=False) update_time = serializers.DateTimeField(required=False) input_octets = serializers.IntegerField(required=False, default=0) output_octets = serializers.IntegerField(required=False, default=0) # this is needed otherwise serialize will ignore status_type from accounting packet # as it's not a model field status_type = serializers.ChoiceField(write_only=True, required=True, choices=STATUS_TYPE_CHOICES) def _disable_token_auth(self, user): try: radius_token = RadiusToken.objects.get(user__username=user) except RadiusToken.DoesNotExist: pass else: radius_token.can_auth = False radius_token.save() def run_validation(self, data): for field in ['session_time', 'input_octets', 'output_octets']: if data.get('status_type', None) == 'Start' and data[field] == '': data[field] = 0 return super().run_validation(data) def validate(self, data): """ We need to set some timestamps according to the accounting packet type * update_time: set everytime a Interim-Update / Stop packet is received * stop_time: set everytime a Stop packet is received * session_time: calculated if not present in the accounting packet :param data: accounting packet :return: Dict accounting packet """ time = timezone.now() status_type = data.pop('status_type') if status_type == 'Interim-Update': data['update_time'] = time if status_type == 'Stop': data['update_time'] = time data['stop_time'] = time # disable radius_token auth capability self._disable_token_auth(data['username']) return data def create(self, validated_data): if app_settings.API_ACCOUNTING_AUTO_GROUP: username = validated_data.get('username', '') try: user = User.objects.get(username=username) except User.DoesNotExist: logging.warning( _(f'No corresponding user found for username: {username}')) else: group = user.radiususergroup_set.order_by('priority').first() groupname = group.groupname if group else None validated_data.update(groupname=groupname) return super().create(validated_data) class Meta: model = RadiusAccounting fields = '__all__' read_only_fields = ('organization', )