def create(cls, name, ldap_server, isdefault=False, auth_method=None, comment=None): """ Create an External LDAP user domain. These are used as containers for retrieving user and groups from the configured LDAP server/s. If you have multiple authentication methods supported for your LDAP server, or have none configured, you can set the `auth_method` to a supported AuthenticationService. :param str name: name of external LDAP domain :param list(str,ActiveDirectoryServer) ldap_server: list of existing authentication servers in href or element format :param bool isdefault: set this to 'Default LDAP domain' :param str,AuthenticationService auth_method: authentication method to use. Usually set when multiple are defined in LDAP service or none are defined. :param str comment: optional comment :raises CreateElementFailed: failed to create :rtype: ExternalLdapUserDomain """ return ElementCreator(cls, json={ 'name': name, 'ldap_server': element_resolver(ldap_server), 'auth_method': element_resolver(auth_method), 'isdefault': isdefault, 'comment': comment })
def enable(self, license_key, license_token, sandbox_type='cloud_sandbox', service='Automatic', http_proxy=None, sandbox_data_center='Automatic'): """ Enable sandbox on this engine. Provide a valid license key and license token obtained from your engine licensing. Requires SMC version >= 6.3. .. note:: Cloud sandbox is a feature that requires an engine license. :param str license_key: license key for specific engine :param str license_token: license token for specific engine :param str sandbox_type: 'local_sandbox' or 'cloud_sandbox' :param str,SandboxService service: a sandbox service element from SMC. The service defines which location the engine is in and which data centers to use. The default is to use the 'US Data Centers' profile if undefined. :param str,SandboxDataCenter sandbox_data_center: sandbox data center to use if the service specified does not exist. Requires SMC >= 6.4.3 :return: None """ service = element_resolver(SandboxService(service), do_raise=False) or \ element_resolver(SandboxService.create(name=service, sandbox_data_center=SandboxDataCenter(sandbox_data_center))) self.update(sandbox_license_key=license_key, sandbox_license_token=license_token, sandbox_service=service, http_proxy=get_proxy(http_proxy)) self.engine.data.setdefault('sandbox_settings', {}).update(self.data) self.engine.data.update(sandbox_type=sandbox_type)
def advertise_network(self, network, route_map=None): """ Advertise a network through BGP. An advertised network can be either a Host, Network or a Group of Host/Networks. An optional RouteMap can be mapped to the advertised members as well. :param str,Element network: Advertise this network. Must be of type Host, Network or Group of Host, Network :param str,RouteMap route_map: An optional Route Map that will be applied to this network or group of networks :raises UpdateElementFailed: Failure to create :raises ElementNotFound: Specified network or route map not found :return: None .. note:: If str is provided for network or route_map, the str value should be the href for the element. """ resolved = element_resolver(network) announced_ne_setting = self.data.get('bgp', {}).get('announced_ne_setting') existing = [ref.get('announced_ne_ref') for ref in announced_ne_setting] if resolved not in existing: announced_ne_setting.append( {'announced_ne_ref': resolved, 'announced_rm_ref': element_resolver(route_map)})
def create(cls, name, gateway, network, input_speed=None, output_speed=None, domain_server_address=None, provider_name=None, probe_address=None, standby_mode_period=3600, standby_mode_timeout=30, active_mode_period=5, active_mode_timeout=1, comment=None): """ Create a new StaticNetlink to be used as a traffic handler. :param str name: name of netlink Element :param gateway_ref: gateway to map this netlink to. This can be an element or str href. :type gateway_ref: Router,Engine :param list ref: network/s associated with this netlink. :type ref: list(str,Element) :param int input_speed: input speed in Kbps, used for ratio-based load-balancing :param int output_speed: output speed in Kbps, used for ratio-based load-balancing :param list domain_server_address: dns address for netlink. Engine DNS can override this field :type dns_addresses: list(str,Element) :param str provider_name: optional name to identify provider for this netlink :param list probe_address: list of IP addresses to use as probing addresses to validate connectivity :type probe_ip_address: list(str) :param int standby_mode_period: Specifies the probe period when standby mode is used (in seconds) :param int standby_mode_timeout: probe timeout in seconds :param int active_mode_period: Specifies the probe period when active mode is used (in seconds) :param int active_mode_timeout: probe timeout in seconds :raises ElementNotFound: if using type Element parameters that are not found. :raises CreateElementFailed: failure to create netlink with reason :rtype: StaticNetlink .. note:: To monitor the status of the network links, you must define at least one probe IP address. """ json = {'name': name, 'gateway_ref': element_resolver(gateway), 'ref': element_resolver(network), 'input_speed': input_speed, 'output_speed': output_speed, 'probe_address': probe_address, 'nsp_name': provider_name, 'comment': comment, 'standby_mode_period': standby_mode_period, 'standby_mode_timeout': standby_mode_timeout, 'active_mode_period': active_mode_period, 'active_mode_timeout': active_mode_timeout} if domain_server_address: r = RankedDNSAddress([]) r.add(domain_server_address) json.update(domain_server_address=r.entries) return ElementCreator(cls, json)
def create(cls, name, gateway, network, input_speed=None, output_speed=None, domain_server_address=None, provider_name=None, probe_address=None, standby_mode_period=3600, standby_mode_timeout=30, active_mode_period=5, active_mode_timeout=1, comment=None): """ Create a new StaticNetlink to be used as a traffic handler. :param str name: name of netlink Element :param gateway_ref: gateway to map this netlink to. This can be an element or str href. :type gateway_ref: Router,Engine :param list ref: network/s associated with this netlink. :type ref: list(str,Element) :param int input_speed: input speed in Kbps, used for ratio-based load-balancing :param int output_speed: output speed in Kbps, used for ratio-based load-balancing :param list domain_server_address: dns addresses for netlink. Engine DNS can override this field :type dns_addresses: list(str,Element) :param str provider_name: optional name to identify provider for this netlink :param list probe_address: list of IP addresses to use as probing addresses to validate connectivity :type probe_ip_address: list(str) :param int standby_mode_period: Specifies the probe period when standby mode is used (in seconds) :param int standby_mode_timeout: probe timeout in seconds :param int active_mode_period: Specifies the probe period when active mode is used (in seconds) :param int active_mode_timeout: probe timeout in seconds :raises ElementNotFound: if using type Element parameters that are not found. :raises CreateElementFailed: failure to create netlink with reason :rtype: StaticNetlink .. note:: To monitor the status of the network links, you must define at least one probe IP address. """ json = {'name': name, 'gateway_ref': element_resolver(gateway), 'ref': element_resolver(network), 'input_speed': input_speed, 'output_speed': output_speed, 'probe_address': probe_address, 'nsp_name': provider_name, 'comment': comment, 'standby_mode_period': standby_mode_period, 'standby_mode_timeout': standby_mode_timeout, 'active_mode_period': active_mode_period, 'active_mode_timeout': active_mode_timeout} if domain_server_address: r = RankedDNSAddress([]) r.add(domain_server_address) json.update(domain_server_address=r.entries) return ElementCreator(cls, json)
def update_or_create(cls, with_status=False, **kwargs): if 'inbound_filters' in kwargs: kwargs.update(inbound_filters_ref= element_resolver(kwargs.pop('inbound_filters'))) if 'outbound_filters' in kwargs: kwargs.update(outbound_filters_ref= element_resolver(kwargs.pop('outbound_filters'))) return super(OSPFArea, cls).update_or_create(with_status=with_status, **kwargs)
def test_element_resolver(self): host = Host.create('hostelement', address='1.1.1.1') resolved = element_resolver([Host('hostelement'), 'http://2.2.2.2']) for r in resolved: self.assertIn(r, [host.href, 'http://2.2.2.2']) # Catches ElementNotFound in list with self.assertRaises(ElementNotFound): element_resolver(elements=[Host('foobarblah')])
def __init__(self, granted_elements=None, role_ref=None, granted_domain_ref=None): data = dict(granted_domain_ref=element_resolver(granted_domain_ref), role_ref=element_resolver(role_ref), granted_elements=element_resolver(granted_elements)) super(Permission, self).__init__(data=data)
def update_or_create(cls, filter_key=None, with_status=False, **kwargs): if 'inbound_filters' in kwargs: kwargs.update(inbound_filters_ref= element_resolver(kwargs.pop('inbound_filters'))) if 'outbound_filters' in kwargs: kwargs.update(outbound_filters_ref= element_resolver(kwargs.pop('outbound_filters'))) return super(OSPFArea, cls).update_or_create(filter_key, with_status, **kwargs)
def create(cls, name, interface_settings_ref=None, area_id=1, area_type="normal", outbound_filters=None, inbound_filters=None, shortcut_capable_area=False, ospfv2_virtual_links_endpoints_container=None, ospf_abr_substitute_container=None, comment=None, **kwargs): """ Create a new OSPF Area :param str name: name of OSPFArea configuration :param str,OSPFInterfaceSetting interface_settings_ref: an OSPFInterfaceSetting element or href. If None, uses the default system profile :param str name: area id :param str area_type: \\|normal\\|stub\\|not_so_stubby\\|totally_stubby\\| totally_not_so_stubby :param list outbound_filters: reference to an IPAccessList and or IPPrefixList. You can only have one outbound prefix or access list :param list inbound_filters: reference to an IPAccessList and or IPPrefixList. You can only have one outbound prefix or access list :param shortcut_capable_area: True|False :param list ospfv2_virtual_links_endpoints_container: virtual link endpoints :param list ospf_abr_substitute_container: substitute types: \\|aggregate\\|not_advertise\\|substitute_with :param str comment: optional comment :raises CreateElementFailed: failed to create with reason :rtype: OSPFArea """ interface_settings_ref = ( element_resolver(interface_settings_ref) or OSPFInterfaceSetting("Default OSPFv2 Interface Settings").href) if "inbound_filters_ref" in kwargs: inbound_filters = kwargs.get("inbound_filters_ref") if "outbound_filters_ref" in kwargs: outbound_filters = kwargs.get("outbound_filters_ref") json = { "name": name, "area_id": area_id, "area_type": area_type, "comment": comment, "inbound_filters_ref": element_resolver(inbound_filters), "interface_settings_ref": interface_settings_ref, "ospf_abr_substitute_container": ospf_abr_substitute_container, "ospfv2_virtual_links_endpoints_container": ospfv2_virtual_links_endpoints_container, "outbound_filters_ref": element_resolver(outbound_filters), "shortcut_capable_area": shortcut_capable_area, } return ElementCreator(cls, json)
def create(cls, name, interface_settings_ref=None, area_id=1, area_type='normal', outbound_filters=None, inbound_filters=None, shortcut_capable_area=False, ospfv2_virtual_links_endpoints_container=None, ospf_abr_substitute_container=None, comment=None, **kwargs): """ Create a new OSPF Area :param str name: name of OSPFArea configuration :param str,OSPFInterfaceSetting interface_settings_ref: an OSPFInterfaceSetting element or href. If None, uses the default system profile :param str name: area id :param str area_type: \|normal\|stub\|not_so_stubby\|totally_stubby\| totally_not_so_stubby :param list outbound_filters: reference to an IPAccessList and or IPPrefixList. You can only have one outbound prefix or access list :param list inbound_filters: reference to an IPAccessList and or IPPrefixList. You can only have one outbound prefix or access list :param shortcut_capable_area: True|False :param list ospfv2_virtual_links_endpoints_container: virtual link endpoints :param list ospf_abr_substitute_container: substitute types: \|aggregate\|not_advertise\|substitute_with :param str comment: optional comment :raises CreateElementFailed: failed to create with reason :rtype: OSPFArea """ interface_settings_ref = element_resolver(interface_settings_ref) or \ OSPFInterfaceSetting('Default OSPFv2 Interface Settings').href if 'inbound_filters_ref' in kwargs: inbound_filters = kwargs.get('inbound_filters_ref') if 'outbound_filters_ref' in kwargs: outbound_filters = kwargs.get('outbound_filters_ref') json = { 'name': name, 'area_id': area_id, 'area_type': area_type, 'comment': comment, 'inbound_filters_ref': element_resolver(inbound_filters), 'interface_settings_ref': interface_settings_ref, 'ospf_abr_substitute_container': ospf_abr_substitute_container, 'ospfv2_virtual_links_endpoints_container': ospfv2_virtual_links_endpoints_container, 'outbound_filters_ref': element_resolver(outbound_filters), 'shortcut_capable_area': shortcut_capable_area } return ElementCreator(cls, json)
def update_or_create(cls, with_status=False, **kwargs): if "inbound_filters" in kwargs: kwargs.update(inbound_filters_ref=element_resolver( kwargs.pop("inbound_filters"))) if "outbound_filters" in kwargs: kwargs.update(outbound_filters_ref=element_resolver( kwargs.pop("outbound_filters"))) return super(OSPFArea, cls).update_or_create(with_status=with_status, **kwargs)
def enable(self, autonomous_system, announced_networks, antispoofing_networks=None, router_id=None, bgp_profile=None): """ Enable BGP on this engine. On master engine, enable BGP on the virtual firewall. When adding networks to `announced_networks` or `antispoofing_networks`, the element types can be of type :class:`smc.elements.network.Host`, :class:`smc.elements.network.Network` or :class:`smc.elements.group.Group`. If passing a Group, it must have element types of host or network. :: engine.bgp.enable( autonomous_system=AutonomousSystem('aws_as'), announced_networks=[Network('bgpnet'),Network('inside')], router_id='10.10.10.10') :param str,AutonomousSystem autonomous_system: provide the AS element or str href for the element :param str,BGPProfile bgp_profile: provide the BGPProfile element or str href for the element; if None, use system default :param list announced_networks: list of networks to advertise via BGP :type announced_networks: list(str,Element). :param list antispoofing_networks: list of networks to advertise via BGP :type antispoofing_networks: list(str, Element) :param str router_id: router id for BGP, should be an IP address. If not set, automatic discovery will use default bound interface as ID. :raises ElementNotFound: OSPF, AS or Networks not found :return: None .. note:: For arguments that take str or Element, the str value should be the href of the element. """ autonomous_system = element_resolver(autonomous_system) if not bgp_profile: bgp_profile = BGPProfile('Default BGP Profile').href else: bgp_profile = element_resolver(bgp_profile) announced = [{ 'announced_ne_ref': network } for network in element_resolver(announced_networks)] self.data.setdefault('bgp', {}).update(enabled=True, bgp_as_ref=autonomous_system, bgp_profile_ref=bgp_profile, announced_ne_setting=announced, router_id=router_id) if antispoofing_networks: self.data.setdefault('antispoofing_ne_ref', []).extend( [element_resolver(net) for net in antispoofing_networks])
def create(cls, name, tls_version, use_only_subject_alt_name=False, accept_wildcard=False, check_revocation=True, tls_cryptography_suites=None, crl_delay=0, ocsp_delay=0, ignore_network_issues=False, tls_trusted_ca_ref=None, comment=None): """ Create a TLS Profile. By default the SMC will have a default NIST TLS Profile but it is also possible to create a custom profile to provide special TLS handling. :param str name: name of TLS Profile :param str tls_verison: supported tls verison, valid options are TLSv1.1, TLSv1.2, TLSv1.3 :param bool use_only_subject_alt_name: Use Only Subject Alt Name when the TLS identity is a DNS name :param bool accept_wildcard: Does server identity check accept wildcards :param bool check_revocation: Is certificate revocation checked :param str,TLSCryptographySuite tls_cryptography_suites: allowed cryptography suites for this profile. Uses NIST profile if not specified :param int crl_delay: Delay time (hours) for fetching CRL :param int ocsp_delay: Ignore OCSP failure for (hours) :param bool ignore_network_issues: Ignore revocation check failures due to network issues :param list tls_trusted_ca_ref: Trusted Certificate Authorities, empty list means trust any :param str comment: optional comment :raises CreateElementFailed: failed to create element with reason :raises ElementNotFound: specified element reference was not found :rtype: TLSProfile """ json = { 'name': name, 'tls_version': tls_version, 'use_only_subject_alt_name': use_only_subject_alt_name, 'accept_wildcard': accept_wildcard, 'check_revocation': check_revocation, 'tls_cryptography_suites': element_resolver(tls_cryptography_suites) or \ element_resolver(TLSCryptographySuite.objects.filter('NIST').first()), 'crl_delay': crl_delay, 'ocsp_delay': ocsp_delay, 'ignore_network_issues': ignore_network_issues, 'tls_trusted_ca_ref': element_resolver(tls_trusted_ca_ref) or [], 'comment': comment} return ElementCreator(cls, json)
def enable(self, autonomous_system, announced_networks, router_id=None, bgp_profile=None): """ Enable BGP on this engine. On master engine, enable BGP on the virtual firewall. When adding networks to `announced_networks`, the element types can be of type :class:`smc.elements.network.Host`, :class:`smc.elements.network.Network` or :class:`smc.elements.group.Group`. If passing a Group, it must have element types of host or network. Within announced_networks, you can pass a 2-tuple that provides an optional :class:`smc.routing.route_map.RouteMap` if additional policy is required for a given network. :: engine.dynamic_routing.bgp.enable( autonomous_system=AutonomousSystem('aws_as'), announced_networks=[Network('bgpnet'),Network('inside')], router_id='10.10.10.10') :param str,AutonomousSystem autonomous_system: provide the AS element or str href for the element :param str,BGPProfile bgp_profile: provide the BGPProfile element or str href for the element; if None, use system default :param list announced_networks: list of networks to advertise via BGP Announced networks can be single networks,host or group elements or a 2-tuple with the second tuple item being a routemap element :param str router_id: router id for BGP, should be an IP address. If not set, automatic discovery will use default bound interface as ID. :raises ElementNotFound: OSPF, AS or Networks not found :return: None .. note:: For arguments that take str or Element, the str value should be the href of the element. """ autonomous_system = element_resolver(autonomous_system) bgp_profile = element_resolver(bgp_profile) or BGPProfile( "Default BGP Profile").href announced = self._unwrap(announced_networks) self.data.update( enabled=True, bgp_as_ref=autonomous_system, bgp_profile_ref=bgp_profile, announced_ne_setting=announced, router_id=router_id, )
def __init__(self, data_context, host, netflow_collector_port, netflow_collector_service, netflow_collector_version, filter=None): dc = dict(data_context=element_resolver(data_context), filter=element_resolver(filter), host=element_resolver(host), netflow_collector_port=netflow_collector_port, netflow_collector_service=netflow_collector_service, netflow_collector_version=netflow_collector_version) super(NetflowCollector, self).__init__(data=dc)
def create(cls, name, interface_settings_ref=None, area_id=1, area_type='normal', outbound_filters=None, inbound_filters=None, shortcut_capable_area=False, ospfv2_virtual_links_endpoints_container=None, ospf_abr_substitute_container=None, comment=None, **kwargs): """ Create a new OSPF Area :param str name: name of OSPFArea configuration :param str,OSPFInterfaceSetting interface_settings_ref: an OSPFInterfaceSetting element or href. If None, uses the default system profile :param str name: area id :param str area_type: \|normal\|stub\|not_so_stubby\|totally_stubby\| totally_not_so_stubby :param list outbound_filters: reference to an IPAccessList and or IPPrefixList. You can only have one outbound prefix or access list :param list inbound_filters: reference to an IPAccessList and or IPPrefixList. You can only have one outbound prefix or access list :param shortcut_capable_area: True|False :param list ospfv2_virtual_links_endpoints_container: virtual link endpoints :param list ospf_abr_substitute_container: substitute types: \|aggregate\|not_advertise\|substitute_with :param str comment: optional comment :raises CreateElementFailed: failed to create with reason :rtype: OSPFArea """ interface_settings_ref = element_resolver(interface_settings_ref) or \ OSPFInterfaceSetting('Default OSPFv2 Interface Settings').href if 'inbound_filters_ref' in kwargs: inbound_filters = kwargs.get('inbound_filters_ref') if 'outbound_filters_ref' in kwargs: outbound_filters = kwargs.get('outbound_filters_ref') json = {'name': name, 'area_id': area_id, 'area_type': area_type, 'comment': comment, 'inbound_filters_ref': element_resolver(inbound_filters), 'interface_settings_ref': interface_settings_ref, 'ospf_abr_substitute_container': ospf_abr_substitute_container, 'ospfv2_virtual_links_endpoints_container': ospfv2_virtual_links_endpoints_container, 'outbound_filters_ref': element_resolver(outbound_filters), 'shortcut_capable_area': shortcut_capable_area} return ElementCreator(cls, json)
def create(self, name, address=None, enabled=True, ipsec_vpn=True, nat_t=False, force_nat_t=False, dynamic=False, ike_phase1_id_type=None, ike_phase1_id_value=None, connection_type_ref=None, **kw): """ Create an test_external endpoint. Define common settings for that specify the address, enabled, nat_t, name, etc. You can also omit the IP address if the endpoint is dynamic. In that case, you must also specify the ike_phase1 settings. :param str name: name of test_external endpoint :param str address: address of remote host :param bool enabled: True|False (default: True) :param bool ipsec_vpn: True|False (default: True) :param bool nat_t: True|False (default: False) :param bool force_nat_t: True|False (default: False) :param bool dynamic: is a dynamic VPN (default: False) :param int ike_phase1_id_type: If using a dynamic endpoint, you must set this value. Valid options: 0=DNS name, 1=Email, 2=DN, 3=IP Address :param str ike_phase1_id_value: value of ike_phase1_id. Required if ike_phase1_id_type and dynamic set. :param ConnectionType connection_type_ref: SMC>=6.5 setting. Specifies the mode for this endpoint; i.e. Active, Aggregate, Standby. (Default: Active) :raises CreateElementFailed: create element with reason :return: newly created element :rtype: ExternalEndpoint """ json = { "name": name, "address": address, "dynamic": dynamic, "enabled": enabled, "nat_t": nat_t, "force_nat_t": force_nat_t, "ipsec_vpn": ipsec_vpn, } json.update(kw) if dynamic: json.pop("address", None) if ike_phase1_id_value: json.update(ike_phase1_id_value=ike_phase1_id_value) if ike_phase1_id_type is not None: json.update(ike_phase1_id_type=ike_phase1_id_type) json.update(connection_type_ref=element_resolver( connection_type_ref)) if connection_type_ref else json.update( connection_type_ref=element_default(ConnectionType, "Active")) return ElementCreator(self.__class__, href=self.href, json=json)
def _create(self, common_name, public_key_algorithm='rsa', signature_algorithm='rsa_sha_512', key_length=2048, signing_ca=None): """ Internal method called as a reference from the engine.vpn node """ if signing_ca is None: signing_ca = VPNCertificateCA.objects.filter( 'Internal RSA').first() cert_auth = element_resolver(signing_ca) return SubElementCreator( GatewayCertificate, CertificateError, href=self.internal_gateway.get_relation('generate_certificate'), json={ 'common_name': common_name, 'public_key_algorithm': public_key_algorithm, 'signature_algorithm': signature_algorithm, 'public_key_length': key_length, 'certificate_authority_href': cert_auth })
def update_configuration(self, **kwargs): """ Update configuration using valid kwargs as defined in the enable constructor. :param dict kwargs: kwargs to satisfy valid args from `enable` :rtype: bool """ updated = False if 'announced_networks' in kwargs: kwargs.update(announced_ne_setting=kwargs.pop('announced_networks')) if 'bgp_profile' in kwargs: kwargs.update(bgp_profile_ref=kwargs.pop('bgp_profile')) if 'autonomous_system' in kwargs: kwargs.update(bgp_as_ref=kwargs.pop('autonomous_system')) announced_ne = kwargs.pop('announced_ne_setting', None) for name, value in kwargs.items(): _value = element_resolver(value) if self.data.get(name) != _value: self.data[name] = _value updated = True if announced_ne is not None: s = self.data.get('announced_ne_setting') ne = self._unwrap(announced_ne) if len(announced_ne) != len(s) or not self._equal(ne, s): self.data.update(announced_ne_setting=ne) updated = True return updated
def update_configuration(self, **kwargs): """ Update the SNMP configuration using any kwargs supported in the `enable` constructor. Return whether a change was made. You must call update on the engine to commit any changes. :param dict kwargs: keyword arguments supported by enable constructor :rtype: bool """ updated = False if 'snmp_agent' in kwargs: kwargs.update(snmp_agent_ref=kwargs.pop('snmp_agent')) snmp_interface = kwargs.pop('snmp_interface', None) for name, value in kwargs.items(): _value = element_resolver(value) if getattr(self.engine, name, None) != _value: self.engine.data[name] = _value updated = True if snmp_interface is not None: _snmp_interface = getattr(self.engine, 'snmp_interface', []) if not len(snmp_interface) and len(_snmp_interface): self.engine.data.update(snmp_interface=[]) updated = True elif len(snmp_interface): if set(self._nicids) ^ set(map(str, snmp_interface)): self.engine.data.update( snmp_interface=self._iface_dict(snmp_interface)) updated = True return updated
def add_mobile_gateway(self, gateway): """ Add a mobile VPN gateway to this policy VPN. Example of adding or removing a mobile VPN gateway:: policy_vpn = PolicyVPN('myvpn') policy_vpn.open() policy_vpn.add_mobile_vpn_gateway(ExternalGateway('extgw3')) for mobile_gateway in policy_vpn.mobile_gateway_node: if mobile_gateway.gateway == ExternalGateway('extgw3'): mobile_gateway.delete() policy_vpn.save() policy_vpn.close() :param Engine,ExternalGateway gateway: An external gateway, engine or href for the mobile gateway :raises PolicyCommandFailed: could not add gateway """ try: gateway = gateway.vpn.internal_gateway.href # Engine except AttributeError: gateway = element_resolver(gateway) # External Gateway self.make_request(PolicyCommandFailed, method='create', resource='mobile_gateway_node', json={ 'gateway': gateway, 'node_usage': 'mobile' })
def create(cls, name, min_dst_port, max_dst_port=None, min_src_port=None, max_src_port=None, protocol_agent=None, comment=None): """ Create the UDP Service :param str name: name of udp service :param int min_dst_port: minimum destination port value :param int max_dst_port: maximum destination port value :param int min_src_port: minimum source port value :param int max_src_port: maximum source port value :param str,ProtocolAgent protocol_agent: optional protocol agent for this service :param str comment: optional comment :raises CreateElementFailed: failure creating element with reason :return: instance with meta :rtype: UDPService """ max_dst_port = max_dst_port if max_dst_port is not None else '' json = {'name': name, 'min_dst_port': min_dst_port, 'max_dst_port': max_dst_port, 'min_src_port': min_src_port, 'max_src_port': max_src_port, 'protocol_agent_ref': element_resolver(protocol_agent) or None, 'comment': comment} return ElementCreator(cls, json)
def add_many(self, data): """ Add multiple entries to field. Entries should be list format. Entries can be of types relavant to the field type. For example, for source and destination fields, elements may be of type :py:mod:`smc.elements.network` or be the elements direct href, or a combination of both. Add several entries to existing rule:: policy = FirewallPolicy('policy') for rule in policy.fw_ipv4_nat_rules.all(): if rule.name == 'therule': rule.sources.add_many([Host('myhost'), 'http://1.1.1.1/hosts/12345']) rule.save() :param list data: list of sources .. note:: If submitting type Element and the element cannot be found, it will be skipped. """ assert isinstance(data, list), "Incorrect format. Expecting list." if self.is_none or self.is_any: self.clear() self.data[self.typeof] = [] data = element_resolver(data, do_raise=False) self.data[self.typeof] = data
def add(self, data): """ Add a single entry to field. Entries can be added to a rule using the href of the element or by loading the element directly. Element should be of type :py:mod:`smc.elements.network`. After modifying rule, call :py:meth:`~.save`. Example of adding entry by element:: policy = FirewallPolicy('policy') for rule in policy.fw_ipv4_nat_rules.all(): if rule.name == 'therule': rule.sources.add(Host('myhost')) rule.save() .. note:: If submitting type Element and the element cannot be found, it will be skipped. :param data: entry to add :type data: Element or str """ if self.is_none or self.is_any: self.clear() self.data[self.typeof] = [] try: self.get(self.typeof).append(element_resolver(data)) except ElementNotFound: pass
def create(cls, name, min_dst_port, max_dst_port=None, min_src_port=None, max_src_port=None, protocol_agent=None, comment=None): """ Create the UDP Service :param str name: name of udp service :param int min_dst_port: minimum destination port value :param int max_dst_port: maximum destination port value :param int min_src_port: minimum source port value :param int max_src_port: maximum source port value :param str,ProtocolAgent protocol_agent: optional protocol agent for this service :param str comment: optional comment :raises CreateElementFailed: failure creating element with reason :return: instance with meta :rtype: UDPService """ max_dst_port = max_dst_port if max_dst_port is not None else '' json = { 'name': name, 'min_dst_port': min_dst_port, 'max_dst_port': max_dst_port, 'min_src_port': min_src_port, 'max_src_port': max_src_port, 'protocol_agent_ref': element_resolver(protocol_agent) or None, 'comment': comment } return ElementCreator(cls, json)
def create(cls, name, member=None, comment=None): """ Create an internal group. An internal group will always be attached to the default (and only) InternalUserDomain within the SMC. Example of creating an internal user group:: InternalUserGroup.create(name='foogroup2', comment='mycomment') :param str name: Name of group :param list(InternalUser) member: list of internal users to add to this group :param str comment: optional comment :raises CreateElementFailed: failed to create user group :rtype: InternalUserGroup """ json = { 'name': name, 'unique_id': 'cn={},{}'.format(name, InternalUserDomain.user_dn), 'comment': comment } if member: json.update(member=element_resolver(member)) return ElementCreator(cls, json)
def add_mobile_gateway(self, gateway): """ Add a mobile VPN gateway to this policy VPN. Example of adding or removing a mobile VPN gateway:: policy_vpn = PolicyVPN('myvpn') policy_vpn.open() policy_vpn.add_mobile_vpn_gateway(ExternalGateway('extgw3')) for mobile_gateway in policy_vpn.mobile_gateway_node: if mobile_gateway.gateway == ExternalGateway('extgw3'): mobile_gateway.delete() policy_vpn.save() policy_vpn.close() :param Engine,ExternalGateway gateway: An external gateway, engine or href for the mobile gateway :raises PolicyCommandFailed: could not add gateway """ try: gateway = gateway.vpn.internal_gateway.href # Engine except AttributeError: gateway = element_resolver(gateway) # External Gateway self.make_request( PolicyCommandFailed, method='create', resource='mobile_gateway_node', json={'gateway': gateway, 'node_usage': 'mobile'})
def update_field(self, elements): """ Update the field with a list of provided values but only if the values are different. Return a boolean indicating whether a change was made indicating whether `save` should be called. If the field is currently set to any or none, then no comparison is made and field is updated. :param list elements: list of elements in href or Element format to compare to existing field :rtype: bool """ changed = False if isinstance(elements, list): if self.is_any or self.is_none: self.add_many(elements) changed = True else: _elements = element_resolver(elements, do_raise=False) if set(self.all_as_href()) ^ set(_elements): self.data[self.typeof] = _elements changed = True if changed and self.rule and (isinstance(self, (Source, Destination)) and \ self.rule.typeof in ('fw_ipv4_nat_rule', 'fw_ipv6_nat_rule')): # Modify NAT cell if necessary self.rule._update_nat_field(self) return changed
def create(cls, name, domain_settings_ref=None, external_distance=110, inter_distance=110, intra_distance=110): """ Create an OSPF Profile :param str name: name of profile :param str,OSPFDomainSetting domain_settings_ref: OSPFDomainSetting element or href :param int external_distance: route metric (E1-E2) :param int inter_distance: routes learned from different areas (O IA) :param int intra_distance: routes learned from same area (O) :raises CreateElementFailed: create failed with reason :return: instance with meta :rtype: OSPFProfile """ json = {'name': name, 'external_distance': external_distance, 'inter_distance': inter_distance, 'intra_distance': intra_distance} if not domain_settings_ref: domain_settings_ref = OSPFDomainSetting( 'Default OSPFv2 Domain Settings').href else: domain_settings_ref = element_resolver(domain_settings_ref) json.update(domain_settings_ref=domain_settings_ref) return ElementCreator(cls, json)
def generate(self, start_time=0, end_time=0, senders=None, wait_for_finish=False, timeout=5, **kw): # @ReservedAssignment """ Generate the report and optionally wait for results. You can optionally add filters to the report by providing the senders argument as a list of type Element:: report = ReportDesign('Firewall Weekly Summary') begin = datetime_to_ms(datetime.strptime("2018-02-03T00:00:00", "%Y-%m-%dT%H:%M:%S")) end = datetime_to_ms(datetime.strptime("2018-02-04T00:00:00", "%Y-%m-%dT%H:%M:%S")) report.generate(start_time=begin, end_time=end, senders=[Engine('vm')]) :param int period_begin: milliseconds time defining start time for report :param int period_end: milliseconds time defining end time for report :param senders: filter targets to use when generating report :type senders: list(Element) :param bool wait_for_finish: enable polling for results :param int timeout: timeout between polling :raises TaskRunFailed: refresh failed, possibly locked policy :rtype: TaskOperationPoller """ if start_time and end_time: kw.setdefault('params', {}).update( {'start_time': start_time, 'end_time': end_time}) if senders: kw.setdefault('json', {}).update({'senders': element_resolver(senders)}) return Task.execute(self, 'generate', timeout=timeout, wait_for_finish=wait_for_finish, **kw)
def create(cls, name, nat=False, mobile_vpn_toplogy_mode=None, vpn_profile=None): """ Create a new policy based VPN :param name: name of vpn policy :param bool nat: whether to apply NAT to the VPN (default False) :param mobile_vpn_toplogy_mode: whether to allow remote vpn :param VPNProfile vpn_profile: reference to VPN profile, or uses default :rtype: PolicyVPN """ vpn_profile = element_resolver(vpn_profile) or \ VPNProfile('VPN-A Suite').href json = { 'mobile_vpn_topology_mode': mobile_vpn_toplogy_mode, 'name': name, 'nat': nat, 'vpn_profile': vpn_profile } try: return ElementCreator(cls, json) except CreateElementFailed as err: raise CreatePolicyFailed(err)
def update_configuration(self, **kwargs): """ Update configuration using valid kwargs as defined in the enable constructor. :param dict kwargs: kwargs to satisfy valid args from `enable` :rtype: bool """ updated = False if 'announced_networks' in kwargs: kwargs.update( announced_ne_setting=kwargs.pop('announced_networks')) if 'bgp_profile' in kwargs: kwargs.update(bgp_profile_ref=kwargs.pop('bgp_profile')) if 'autonomous_system' in kwargs: kwargs.update(bgp_as_ref=kwargs.pop('autonomous_system')) announced_ne = kwargs.pop('announced_ne_setting', None) for name, value in kwargs.items(): _value = element_resolver(value) if self.data.get(name) != _value: self.data[name] = _value updated = True if announced_ne is not None: s = self.data.get('announced_ne_setting') ne = self._unwrap(announced_ne) if len(announced_ne) != len(s) or not self._equal(ne, s): self.data.update(announced_ne_setting=ne) updated = True return updated
def create(cls, name, address, ipv6_address=None, location=None, comment=None): """ Create a DHCP Server element. :param str name: Name of DHCP Server :param str address: IP address for DHCP Server element :param str ipv6_address: IPv6 addres fir DHCP Server :param str location: Specifies the location for the server if there is a NAT device between the server and other SMC components. :param str comment: Comment for DHCP Server element :raises CreateElementFailed: Failed to create with reason :rtype: DHCPServer """ json = { 'name': name, 'address': address, 'ipv6_address': ipv6_address, 'comment': comment } if location: json.update(location_ref=element_resolver(location)) return ElementCreator(cls, json)
def multilink_member(netlink, nat_range, netlink_network=None, netlink_role='active'): """ :param StaticNetlink netlink: netlink element for multilink member :param str nat_range: ip address range to use for NAT. This needs to be a range in the same network defined in the netlink :param str,Element netlink_network: netlink network when multiple networks are defined within a netlink. Only one network can be defined for each multilink member. :param str netlink_role: role for this netlink member. Values can be 'active' or 'standby' (default: 'active') :raises ElementNotFound: if provided netlink or netlink_network is not found. :return: member dict required for calling Multilink create :rtype: dict """ member = {} member.update(netlink_ref=netlink.href) if len(netlink.networks) > 1: if not netlink_network: raise MissingRequiredInput( 'Netlink %r has more than one network defined. You must ' 'specify which network to use with the netlink_network ' 'parameter' % netlink.name) netlink_network = element_resolver(netlink_network) member.update(network_ref=netlink_network) else: member.update(network_ref=netlink.networks[0].href) member.update(ip_range=nat_range, netlink_role=netlink_role) return member
def create(cls, name, neighbor_as, neighbor_ip, neighbor_port=179, comment=None): """ Create an external BGP Peer. :param str name: name of peer :param str,AutonomousSystem neighbor_as_ref: AutonomousSystem element or href. :param str neighbor_ip: ip address of BGP peer :param int neighbor_port: port for BGP, default 179. :raises CreateElementFailed: failed creating :return: instance with meta :rtype: ExternalBGPPeer """ json = { 'name': name, 'neighbor_ip': neighbor_ip, 'neighbor_port': neighbor_port, 'comment': comment } neighbor_as_ref = element_resolver(neighbor_as) json.update(neighbor_as=neighbor_as_ref) return ElementCreator(cls, json)
def update_members(self, members, append_lists=False, remove_members=False): """ Update group members with member list. Set append=True to append to existing members, or append=False to overwrite. :param list members: new members for group by href or Element :type members: list[str, Element] :param bool append_lists: whether to append :param bool remove_members: remove members from the group :return: bool was modified or not """ if members: elements = [element_resolver(element) for element in members] if remove_members: element = [e for e in self.members if e not in elements] if set(element) == set(self.members): remove_members = element = False append_lists = False elif append_lists: element = [e for e in elements if e not in self.members] else: element = list(set(elements)) if element or remove_members: self.update(element=element, append_lists=append_lists) return True return False
def enable(self, ospf_profile=None, router_id=None): """ Enable OSPF on this engine. For master engines, enable OSPF on the virtual firewall. Once enabled on the engine, add an OSPF area to an interface:: engine.ospf.enable() interface = engine.routing.get(0) interface.add_ospf_area(OSPFArea('myarea')) :param str,OSPFProfile ospf_profile: OSPFProfile element or str href; if None, use default profile :param str router_id: single IP address router ID :raises ElementNotFound: OSPF profile not found :return: None """ if not ospf_profile: ospf_profile = OSPFProfile('Default OSPFv2 Profile').href else: ospf_profile = element_resolver(ospf_profile) self.data.update(enabled=True, ospfv2_profile_ref=ospf_profile, router_id=router_id)
def create(cls, name, user_group=None, activation_date=None, expiration_date=None, comment=None): """ Create an internal user. Add a user example:: InternalUser.create(name='goog', comment='my comment') :param str name: name of user that is displayed in SMC :param list(str,InternalUserGroup) user_group: internal user groups which to add this user to. :param datetime activation_date: activation date as datetime object. Activation date only supports year and month/day :param datetime expiration_date: expiration date as datetime object. Expiration date only supports year and month/day :param str comment: optional comment :raises ElementNotFound: thrown if group specified does not exist :rtype: InternalUser """ json = { 'name': name, 'unique_id': 'cn={},{}'.format(name, InternalUserDomain.user_dn), 'comment': comment} limits = {'activation_date': activation_date, 'expiration_date': expiration_date} for attr, value in limits.items(): json[attr] = datetime_to_ms(value) if value else None if user_group: json.update(user_group=element_resolver(user_group)) return ElementCreator(cls, json)
def _create( self, common_name, public_key_algorithm="rsa", signature_algorithm="rsa_sha_512", key_length=2048, signing_ca=None, ): """ Internal method called as a reference from the engine.vpn node """ if signing_ca is None: signing_ca = VPNCertificateCA.objects.filter("Internal RSA").first() cert_auth = element_resolver(signing_ca) return ElementCreator( GatewayCertificate, exception=CertificateError, href=self.internal_gateway.get_relation("generate_certificate"), json={ "common_name": common_name, "public_key_algorithm": public_key_algorithm, "signature_algorithm": signature_algorithm, "public_key_length": key_length, "certificate_authority_href": cert_auth, }, )
def enable(self, autonomous_system, announced_networks, router_id=None, bgp_profile=None): """ Enable BGP on this engine. On master engine, enable BGP on the virtual firewall. When adding networks to `announced_networks`, the element types can be of type :class:`smc.elements.network.Host`, :class:`smc.elements.network.Network` or :class:`smc.elements.group.Group`. If passing a Group, it must have element types of host or network. Within announced_networks, you can pass a 2-tuple that provides an optional :class:`smc.routing.route_map.RouteMap` if additional policy is required for a given network. :: engine.dynamic_routing.bgp.enable( autonomous_system=AutonomousSystem('aws_as'), announced_networks=[Network('bgpnet'),Network('inside')], router_id='10.10.10.10') :param str,AutonomousSystem autonomous_system: provide the AS element or str href for the element :param str,BGPProfile bgp_profile: provide the BGPProfile element or str href for the element; if None, use system default :param list announced_networks: list of networks to advertise via BGP Announced networks can be single networks,host or group elements or a 2-tuple with the second tuple item being a routemap element :param str router_id: router id for BGP, should be an IP address. If not set, automatic discovery will use default bound interface as ID. :raises ElementNotFound: OSPF, AS or Networks not found :return: None .. note:: For arguments that take str or Element, the str value should be the href of the element. """ autonomous_system = element_resolver(autonomous_system) bgp_profile = element_resolver(bgp_profile) or \ BGPProfile('Default BGP Profile').href announced = self._unwrap(announced_networks) self.data.update( enabled=True, bgp_as_ref=autonomous_system, bgp_profile_ref=bgp_profile, announced_ne_setting=announced, router_id=router_id)
def create(cls, name, sandbox_data_center, portal_username=None, comment=None): """ Create a Sandbox Service element """ json = { 'name': name, 'sandbox_data_center': element_resolver(sandbox_data_center), 'portal_username': portal_username if portal_username else '', 'comment': comment} return ElementCreator(cls, json)
def create(cls, name, domain_settings_ref=None, external_distance=110, inter_distance=110, intra_distance=110, redistribution_entry=None, default_metric=None, comment=None): """ Create an OSPF Profile. If providing a list of redistribution entries, provide in the following dict format: {'enabled': boolean, 'metric_type': 'external_1' or 'external_2', 'metric': 2, 'type': 'kernel'} Valid types for redistribution entries are: kernel, static, connected, bgp, and default_originate. You can also provide a 'filter' key with either an IPAccessList or RouteMap element to use for further access control on the redistributed route type. If metric_type is not provided, external_1 (E1) will be used. An example of a redistribution_entry would be:: {u'enabled': True, u'metric': 123, u'metric_type': u'external_2', u'filter': RouteMap('myroutemap'), u'type': u'static'} :param str name: name of profile :param str,OSPFDomainSetting domain_settings_ref: OSPFDomainSetting element or href :param int external_distance: route metric (E1-E2) :param int inter_distance: routes learned from different areas (O IA) :param int intra_distance: routes learned from same area (O) :param list redistribution_entry: how to redistribute the OSPF routes. :raises CreateElementFailed: create failed with reason :rtype: OSPFProfile """ json = {'name': name, 'external_distance': external_distance, 'inter_distance': inter_distance, 'intra_distance': intra_distance, 'default_metric': default_metric, 'comment': comment} if redistribution_entry: json.update(redistribution_entry= _format_redist_entry(redistribution_entry)) domain_settings_ref = element_resolver(domain_settings_ref) or \ OSPFDomainSetting('Default OSPFv2 Domain Settings').href json.update(domain_settings_ref=domain_settings_ref) return ElementCreator(cls, json)
def update_or_create(cls, name, engine, translation_values=None, with_status=False): """ Update or create an Alias and it's mappings. :param str name: name of alias :param Engine engine: engine to modify alias translation values :param list(str,Element) translation_values: translation values as elements. Can be None if you want to unset any existing values :param bool with_status: if set to True, a 3-tuple is returned with (Element, modified, created), where the second and third tuple items are booleans indicating the status :raises ElementNotFound: specified engine or translation values are not found in the SMC :raises UpdateElementFailed: update failed with reason :raises CreateElementFailed: create failed with reason :rtype: Element """ updated, created = False, False alias = cls.get(name, raise_exc=False) if not alias: alias = cls.create(name) created = True elements = element_resolver(translation_values) if translation_values \ else [] if not created: # possible update # Does alias already exist with a value alias_value = [_alias for _alias in engine.data.get('alias_value', []) if _alias.get('alias_ref') == alias.href] if alias_value: if not elements: alias_value[0].update(translated_element=None) updated = True else: t_values = alias_value[0].get('translated_element') if set(t_values) ^ set(elements): t_values[:] = elements updated = True if elements and (created or not updated): engine.data.setdefault('alias_value', []).append( {'alias_ref': alias.href, 'translated_element': elements}) updated = True if updated: engine.update() if with_status: return alias, updated, created return alias
def remove_category(self, categories): """ Remove a category from this Category Tag (group). :param list categories: categories to remove :type categories: list(str,Element) :return: None """ categories = element_resolver(categories) diff = [category for category in self.data['category_child_ref'] if category not in categories] self.update(category_child_ref=diff)
def add_site_element(self, element): """ Add a site element or list of elements to this VPN. :param list element: list of Elements or href's of vpn site elements :type element: list(str,Network) :raises UpdateElementFailed: fails due to reason :return: None """ element = element_resolver(element) self.data['site_element'].extend(element) self.update()
def remove_tls_credential(self, credentials): """ Remove a list of TLSServerCredentials on this engine. :param credentials: list of credentials to remove from the engine :type credentials: list(str,TLSServerCredential) :return: None """ for cred in credentials: href = element_resolver(cred) if href in self.engine.server_credential: self.engine.server_credential.remove(href)
def add_tls_credential(self, credentials): """ Add a list of TLSServerCredential to this engine. TLSServerCredentials can be in element form or can also be the href for the element. :param credentials: list of pre-created TLSServerCredentials :type credentials: list(str,TLSServerCredential) :return: None """ for cred in credentials: href = element_resolver(cred) if href not in self.engine.server_credential: self.engine.server_credential.append(href)
def update_protocol_agent(self, protocol_agent): """ Update this service to use the specified protocol agent. After adding the protocol agent to the service you must call `update` on the element to commit. :param str,ProtocolAgent protocol_agent: protocol agent element or href :return: None """ if not protocol_agent: for pa in ('paValues', 'protocol_agent_ref'): self.data.pop(pa, None) else: self.data.update(protocol_agent_ref=element_resolver(protocol_agent))
def add_permission(self, elements): """ Add permission/s to this ACL. By default this change is committed after the method is called. :param list elements: Elements to grant access to. Can be engines, policies, or other ACLs :type elements: list(str,Element) :raises UpdateElementFailed: Failed updating permissions :return: None """ elements = element_resolver(elements) self.data['granted_element'].extend(elements) self.update()
def create(cls, name, ldap_server, isdefault=False, auth_method=None, comment=None): """ Create an External LDAP user domain. These are used as containers for retrieving user and groups from the configured LDAP server/s. If you have multiple authentication methods supported for your LDAP server, or have none configured, you can set the `auth_method` to a supported AuthenticationMethod. :param str name: name of external LDAP domain :param list(str,ActiveDirectoryServer) ldap_server: list of existing authentication servers in href or element format :param bool isdefault: set this to 'Default LDAP domain' :param str,AuthenticationMethod auth_method: authentication method to use. Usually set when multiple are defined in LDAP service or none are defined. :param str comment: optional comment :raises CreateElementFailed: failed to create :rtype: ExternalLdapUserDomain """ return ElementCreator(cls, json={'name': name, 'ldap_server': element_resolver(ldap_server), 'auth_method': element_resolver(auth_method), 'isdefault': isdefault, 'comment': comment})
def remove_permission(self, elements): """ Remove permission/s to this ACL. Change is committed at end of method call. :param list elements: list of element/s to remove :type elements: list(str,Element) :raises UpdateElementFailed: Failed modifying permissions :return: None """ elements = element_resolver(elements) for element in elements: if element in self.granted_element: self.data['granted_element'].remove(element) self.update()
def add_category_tag(self, tags, append_lists=True): """ Add this category to a category tag (group). This provides drop down filters in the SMC UI by category tag. :param list tags: category tag by name :param bool append_lists: append to existing tags or overwrite default: append) :type tags: list(str) :return: None """ tags = element_resolver(tags) self.update( category_parent_ref=tags, append_lists=append_lists)
def enable(self, policy): """ Set a layer 2 interface policy. :param str,Element policy: an InterfacePolicy or str href :raises LoadPolicyFailed: Invalid policy specified :raises ElementNotFound: InterfacePolicy not found :return: None """ if hasattr(policy, 'href'): if not isinstance(policy, InterfacePolicy): raise LoadPolicyFailed('Invalid policy type specified. The policy' 'type must be InterfacePolicy') self.update(l2_interface_policy_ref=element_resolver(policy))
def create(cls, name, granted_element=None): """ Create a new ACL :param str name: Name of ACL :param list granted_elements: Elements to grant access to. Can be engines, policies or other acl's. :type granted_elements: list(str,Element) :raises CreateElementFailed: failed creating ACL :return: instance with meta :rtype: AccessControlList """ granted_element = element_resolver(granted_element) json = {'name': name, 'granted_element': granted_element} return ElementCreator(cls, json)
def update_antispoofing(self, networks=None): """ Pass a list of networks to update antispoofing networks with. You can clear networks by providing an empty list. If networks are provided but already exist, no update is made. :param list networks: networks, groups or hosts for antispoofing :rtype: bool """ if not networks and len(self.data.get('antispoofing_ne_ref')): self.data.update(antispoofing_ne_ref=[]) return True _networks = element_resolver(networks) if set(_networks) ^ set(self.data.get('antispoofing_ne_ref')): self.data.update(antispoofing_ne_ref=_networks) return True return False