Source code for smc.core.collection

"""
.. versionchanged:: 0.7.0

Collections classes for interfaces provide searching and methods to simplify
creation based on interface types.

You can iterate any interface type by specifying the type::
    
    >>> for interface in engine.tunnel_interface:
    ...   interface
    ... 
    TunnelInterface(name=Tunnel Interface 1008)
    TunnelInterface(name=Tunnel Interface 1003)
    TunnelInterface(name=Tunnel Interface 1000)

Or iterate all interfaces which will also return their types::
    
    >>> for interface in engine.interface:
    ...   interface
    ... 
    Layer3PhysicalInterface(name=Interface 3)
    TunnelInterface(name=Tunnel Interface 1000)
    Layer3PhysicalInterface(name=Interface 61)
    Layer3PhysicalInterface(name=Interface 56)
    Layer3PhysicalInterface(name=Interface 15)
    Layer2PhysicalInterface(name=Interface 7 (Capture))
    ModemInterfaceDynamic(name=Modem 0)
    TunnelInterface(name=Tunnel Interface 1030)
    SwitchPhysicalInterfaceDynamic(name=Switch 0)
    ...        
    
Accessing interface methods for creating interfaces can also be done in multiple
ways. The simplest is to use an engine reference to use this collection. The engine
reference specifies the type of interface and indicates how it will be created
for the engine. 

For example, creating an interface on a virtual engine::
    
    engine.virtual_physical_interface.add_layer3_interface(
        interface_id=1,
        address='14.14.14.119',
        network_value='14.14.14.0/24',
        comment='my comment',
        zone_ref='myzone')
    
The helper methods use the interface API to create the interface that is then
submitted to the engine.
You can optionally create the interface manually using the API which provides more
customization capabilities.

Example of creating a VirtualPhysicalInterface for a virtual engine manually::

    payload = {'comment': 'comment on this interface',
               'interfaces': [{'nodes': [{'address': '13.13.13.13', 'network_value': '13.13.13.0/24'}]}]}
     
    vinterface = VirtualPhysicalInterface(interface_id=1, **payload)
    
Pass this to update_or_create in the event that you want to potentially modify an existing
interface should the same interface ID exist::

    engine.virtual_physical_interface.update_or_create(
        vinterface)

Or create a new interface (this will fail if the interface exists)::

    engine.add_interface(vinterface)

Collections also provide a simple helper when you want to provide a pre-configured interface
and apply an update_or_create logic. In the update or create case, if the interface exists
any fields that have changed will be updated. If the interface does not exist it is created.
Provide `with_status` to obtain the interface and status of the operation. The update or 
create will return a tuple of (Interface, modified, created), where created and modified are
booleans indicating the operations performed::

    >>> from smc.core.engine import Engine
    >>> from smc.core.interfaces import Layer3PhysicalInterface
    >>> engine = Engine('myfw')
    >>> interface = engine.interface.get(0)
    >>> interface
    Layer3PhysicalInterface(name=Interface 0)
    >>> interface.addresses
    [(u'11.11.11.11', u'11.11.11.0/24', u'0')]
    >>> myinterface = Layer3PhysicalInterface(interface_id=0,
    interfaces=[{'nodes': [{'address': '66.66.66.66', 'network_value': '66.66.66.0/24'}]}], comment='changed today')
    ...
    >>> interface, modified, created = engine.physical_interface.update_or_create(myinterface)
    >>> interface
    Layer3PhysicalInterface(name=Interface 0)
    >>> modified
    True
    >>> created
    False
    >>> interface.addresses
    [(u'66.66.66.66', u'66.66.66.0/24', u'0')]
    >>> interface.comment
    u'changed today'

"""
from smc.core.interfaces import TunnelInterface, \
   InterfaceEditor, Layer3PhysicalInterface,\
    ClusterPhysicalInterface, Layer2PhysicalInterface, VirtualPhysicalInterface
from smc.core.sub_interfaces import LoopbackClusterInterface, LoopbackInterface
from smc.base.structs import BaseIterable
from smc.api.exceptions import UnsupportedInterfaceType, InterfaceNotFound


def get_all_loopbacks(engine):
    """
    Get all loopback interfaces for a given engine
    """
    data = []
    if 'fw_cluster' in engine.type:
        for cvi in engine.data.get('loopback_cluster_virtual_interface', []): 
            data.append(
                LoopbackClusterInterface(cvi, engine))
    for node in engine.nodes:
        for lb in node.data.get('loopback_node_dedicated_interface', []):
            data.append(LoopbackInterface(lb, engine))
    return data


[docs]class LoopbackCollection(BaseIterable): """ An loopback collection provides top level search capabilities to iterate or get loopback interfaces from a given engine. All loopback interfaces can be fetched from the engine:: >>> engine = Engine('dingo') >>> for lb in engine.loopback_interface: ... lb ... LoopbackInterface(address=172.20.1.1, nodeid=1, rank=1) LoopbackInterface(address=172.31.1.1, nodeid=1, rank=2) Or directly from the nodes:: >>> for node in engine.nodes: ... for lb in node.loopback_interface: ... lb ... LoopbackInterface(address=172.20.1.1, nodeid=1, rank=1) LoopbackInterface(address=172.31.1.1, nodeid=1, rank=2) """ def __init__(self, engine): self._engine = engine loopbacks = get_all_loopbacks(engine) super(LoopbackCollection, self).__init__(loopbacks)
[docs] def get(self, address): """ Get a loopback address by it's address. Find all loopback addresses by iterating at either the node level or the engine:: loopback = engine.loopback_interface.get('127.0.0.10') :param str address: ip address of loopback :raises InterfaceNotFound: invalid interface specified :rtype: LoopbackInterface """ loopback = super(LoopbackCollection, self).get(address=address) if loopback: return loopback raise InterfaceNotFound('Loopback address specified was not found')
def __getattr__(self, key): # Dispatch to instance methods but only for adding interfaces. # Makes this work: engine.loopback_interface.add if key.startswith('add_'): if 'fw_cluster' not in self._engine.type: return getattr(LoopbackInterface(None, self._engine), key) else: # Cluster return getattr(LoopbackClusterInterface(None, self._engine), key) raise AttributeError('Cannot proxy to given method: %s for the ' 'following engine type: %s' % (key, self._engine.type))
[docs]class InterfaceCollection(BaseIterable): """ An interface collection provides top level search capabilities to iterate or get interfaces of the specified type. This also delegates all 'add' methods of an interface to the interface type specified. Collections are returned from an engine reference and not called directly. For example, you can use this to obtain all interfaces of a given type from an engine:: >>> for interface in engine.interface.all(): ... print(interface.name, interface.addresses) ('Tunnel Interface 2001', [('169.254.9.22', '169.254.9.20/30', '2001')]) ('Tunnel Interface 2000', [('169.254.11.6', '169.254.11.4/30', '2000')]) ('Interface 2', [('192.168.1.252', '192.168.1.0/24', '2')]) ('Interface 1', [('10.0.0.254', '10.0.0.0/24', '1')]) ('Interface 0', [('172.18.1.254', '172.18.1.0/24', '0')]) Or only physical interface types:: for interface in engine.physical_interfaces: print(interface) Get a specific interface directly:: engine.interface.get(10) Or use delegation to create interfaces:: engine.physical_interface.add(2) engine.physical_interface.add_layer3_interface(....) ... .. note:: This can raise UnsupportedInterfaceType for unsupported engine types based on the interface context. """ def __init__(self, engine, rel='interfaces'): self._engine = engine self._rel = rel self.href = engine.get_relation(rel, UnsupportedInterfaceType) # Pass the interface iterator to the top level iterator super(InterfaceCollection, self).__init__(InterfaceEditor(engine))
[docs] def get(self, interface_id): """ Get the interface by id, if known. The interface is retrieved from the top level Physical or Tunnel Interface. If the interface is an inline interface, you can specify only one of the two inline pairs and the same interface will be returned. If interface type is unknown, use engine.interface for retrieving:: >>> engine = Engine('sg_vm') >>> intf = engine.interface.get(0) >>> print(intf, intf.addresses) (PhysicalInterface(name=Interface 0), [('172.18.1.254', '172.18.1.0/24', '0')]) Get an inline interface:: >>> intf = engine.interface.get('2-3') .. note:: For the inline interface example, you could also just specify '2' or '3' and the fetch will return the pair. :param str,int interface_id: interface ID to retrieve :raises InterfaceNotFound: invalid interface specified :return: interface object by type (Physical, Tunnel, VlanInterface) """ return self.items.get(interface_id)
def __iter__(self): for interface in super(InterfaceCollection, self).__iter__(): if self._rel != 'interfaces': if interface.typeof == self._rel: yield interface else: yield interface def __contains__(self, interface_id): try: return self.get(interface_id) except InterfaceNotFound: return False
[docs] def update_or_create(self, interface): """ Collections class update or create method that can be used as a shortcut to updating or creating an interface. The interface must first be defined and provided as the argument. The interface method must have an `update_interface` method which resolves differences and adds as necessary. :param Interface interface: an instance of an interface type, either PhysicalInterface or TunnelInterface :raises EngineCommandFailed: Failed to create new interface :raises UpdateElementFailed: Failure to update element with reason :rtype: tuple :return: A tuple with (Interface, modified, created), where created and modified are booleans indicating the operations performed """ created, modified = (False, False) try: intf = self._engine.interface.get( interface.interface_id) interface, updated = intf.update_interface(interface) if updated: modified = True except InterfaceNotFound: self._engine.add_interface(interface) interface = self._engine.interface.get(interface.interface_id) created = True return interface, modified, created
[docs]class TunnelInterfaceCollection(InterfaceCollection): """ TunnelInterface Collection provides an interface to retrieving existing interfaces and helper methods to shortcut the creation of an interface. """ def __init__(self, engine): super(TunnelInterfaceCollection, self).__init__(engine, 'tunnel_interface')
[docs] def add_cluster_virtual_interface(self, interface_id, cluster_virtual=None, network_value=None, nodes=None, zone_ref=None, comment=None): """ Add a tunnel interface on a clustered engine. For tunnel interfaces on a cluster, you can specify a CVI only, NDI interfaces, or both. This interface type is only supported on layer 3 firewall engines. :: Add a tunnel CVI and NDI: engine.tunnel_interface.add_cluster_virtual_interface( interface_id_id=3000, cluster_virtual='4.4.4.1', network_value='4.4.4.0/24', nodes=nodes) Add tunnel NDI's only: engine.tunnel_interface.add_cluster_virtual_interface( interface_id=3000, nodes=nodes) Add tunnel CVI only: engine.tunnel_interface.add_cluster_virtual_interface( interface_id=3000, cluster_virtual='31.31.31.31', network_value='31.31.31.0/24', zone_ref='myzone') :param str,int interface_id: tunnel identifier (akin to interface_id) :param str cluster_virtual: CVI ipaddress (optional) :param str network_value: CVI network; required if ``cluster_virtual`` set :param list nodes: nodes for clustered engine with address,network_value,nodeid :param str zone_ref: zone reference, can be name, href or Zone :param str comment: optional comment """ interfaces = [{'cluster_virtual': cluster_virtual, 'network_value': network_value, 'nodes': nodes if nodes else []}] interface = {'interface_id': interface_id, 'interfaces': interfaces, 'zone_ref': zone_ref, 'comment': comment} tunnel_interface = TunnelInterface(**interface) self._engine.add_interface(tunnel_interface)
[docs] def add_layer3_interface(self, interface_id, address, network_value, zone_ref=None, comment=None): """ Creates a tunnel interface with sub-type single_node_interface. This is to be used for single layer 3 firewall instances. :param str,int interface_id: the tunnel id for the interface, used as nicid also :param str address: ip address of interface :param str network_value: network cidr for interface; format: 1.1.1.0/24 :param str zone_ref: zone reference for interface can be name, href or Zone :param str comment: optional comment :raises EngineCommandFailed: failure during creation :return: None """ interfaces = [{'nodes': [{'address': address, 'network_value': network_value}]}] interface = {'interface_id': interface_id, 'interfaces': interfaces, 'zone_ref': zone_ref, 'comment': comment} tunnel_interface = TunnelInterface(**interface) self._engine.add_interface(tunnel_interface)
[docs]class PhysicalInterfaceCollection(InterfaceCollection): """ PhysicalInterface Collection provides an interface to retrieving existing interfaces and helper methods to shortcut the creation of an interface. """ def __init__(self, engine): super(PhysicalInterfaceCollection, self).__init__(engine, 'physical_interface')
[docs] def add(self, interface_id, virtual_mapping=None, virtual_resource_name=None, zone_ref=None, comment=None): """ Add single physical interface with interface_id. Use other methods to fully add an interface configuration based on engine type. Virtual mapping and resource are only used in Virtual Engines. :param str,int interface_id: interface identifier :param int virtual_mapping: virtual firewall id mapping See :class:`smc.core.engine.VirtualResource.vfw_id` :param str virtual_resource_name: virtual resource name See :class:`smc.core.engine.VirtualResource.name` :raises EngineCommandFailed: failure creating interface :return: None """ interface = Layer3PhysicalInterface(engine=self._engine, interface_id=interface_id, zone_ref=zone_ref, comment=comment, virtual_resource_name=virtual_resource_name, virtual_mapping=virtual_mapping) return self._engine.add_interface(interface)
[docs] def add_capture_interface(self, interface_id, logical_interface_ref, inspect_unspecified_vlans=True, zone_ref=None, comment=None): """ Add a capture interface. Capture interfaces are supported on Layer 2 FW and IPS engines. ..note:: Capture interface are supported on Layer 3 FW/clusters for NGFW engines version >= 6.3 and SMC >= 6.3. :param str,int interface_id: interface identifier :param str logical_interface_ref: logical interface name, href or LogicalInterface. If None, 'default_eth' logical interface will be used. :param str zone_ref: zone reference, can be name, href or Zone :raises EngineCommandFailed: failure creating interface :return: None See :class:`smc.core.sub_interfaces.CaptureInterface` for more information """ capture = {'interface_id': interface_id, 'interface': 'capture_interface', 'logical_interface_ref': logical_interface_ref, 'inspect_unspecified_vlans': inspect_unspecified_vlans, 'zone_ref': zone_ref, 'comment': comment} interface = Layer2PhysicalInterface(engine=self._engine, **capture) return self._engine.add_interface(interface)
[docs] def add_layer3_interface(self, interface_id, address, network_value, zone_ref=None, comment=None, **kw): """ Add a layer 3 interface on a non-clustered engine. For Layer 2 FW and IPS engines, this interface type represents a layer 3 routed (node dedicated) interface. For clusters, use the cluster related methods such as :func:`add_cluster_virtual_interface` :param str,int interface_id: interface identifier :param str address: ip address :param str network_value: network/cidr (12.12.12.0/24) :param str zone_ref: zone reference, can be name, href or Zone :param kw: keyword arguments are passed to the sub-interface during create time. If the engine is a single FW, the sub-interface type is :class:`smc.core.sub_interfaces.SingleNodeInterface`. For all other engines, the type is :class:`smc.core.sub_interfaces.NodeInterface` For example, pass 'backup_mgt=True' to enable this interface as the management backup. :raises EngineCommandFailed: failure creating interface :return: None .. note:: If an existing ip address exists on the interface and zone_ref is provided, this value will overwrite any previous zone definition. """ interfaces = {'interface_id': interface_id, 'interfaces': [{'nodes': [{'address': address, 'network_value': network_value}]}], 'zone_ref': zone_ref, 'comment': comment} interfaces.update(kw) if 'single_fw' in self._engine.type: # L2FW / IPS interfaces.update(interface='single_node_interface') try: interface = self._engine.interface.get(interface_id) interface._add_interface(**interfaces) return interface.update() except InterfaceNotFound: interface = Layer3PhysicalInterface(**interfaces) return self._engine.add_interface(interface)
[docs] def add_layer3_vlan_interface(self, interface_id, vlan_id, address=None, network_value=None, virtual_mapping=None, virtual_resource_name=None, zone_ref=None, comment=None, **kw): """ Add a Layer 3 VLAN interface. Optionally specify an address and network if assigning an IP to the VLAN. This method will also assign an IP address to an existing VLAN, or add an additional address to an existing VLAN. This method may commonly be used on a Master Engine to create VLANs for virtual firewall engines. Example of creating a VLAN and passing kwargs to define a DHCP server service on the VLAN interface:: engine = Engine('engine1') engine.physical_interface.add_layer3_vlan_interface(interface_id=20, vlan_id=20, address='20.20.20.20', network_value='20.20.20.0/24', comment='foocomment', dhcp_server_on_interface={ 'default_gateway': '20.20.20.1', 'default_lease_time': 7200, 'dhcp_address_range': '20.20.20.101-20.20.20.120', 'dhcp_range_per_node': [], 'primary_dns_server': '8.8.8.8'}) :param str,int interface_id: interface identifier :param int vlan_id: vlan identifier :param str address: optional IP address to assign to VLAN :param str network_value: network cidr if address is specified. In format: 10.10.10.0/24. :param str zone_ref: zone to use, by name, href, or Zone :param str comment: optional comment for VLAN level of interface :param int virtual_mapping: virtual engine mapping id See :class:`smc.core.engine.VirtualResource.vfw_id` :param str virtual_resource_name: name of virtual resource See :class:`smc.core.engine.VirtualResource.name` :param dict kw: keyword arguments are passed to top level of VLAN interface, not the base level physical interface. This is useful if you want to pass in a configuration that enables the DHCP server on a VLAN for example. :raises EngineCommandFailed: failure creating interface :return: None """ interfaces = {'nodes': [{'address': address, 'network_value': network_value}] if address and network_value else [], 'zone_ref': zone_ref, 'virtual_mapping': virtual_mapping, 'virtual_resource_name': virtual_resource_name, 'comment': comment} interfaces.update(**kw) _interface = {'interface_id': interface_id, 'interfaces': [interfaces]} if 'single_fw' in self._engine.type: # L2FW / IPS _interface.update(interface='single_node_interface') try: interface = self._engine.interface.get(interface_id) vlan = interface.vlan_interface.get(vlan_id) # Interface exists, so we need to update but check if VLAN already exists if vlan is None: interfaces.update(vlan_id=vlan_id) interface._add_interface(**_interface) else: _interface.update(interface_id='{}.{}'.format(interface_id, vlan_id)) vlan._add_interface(**_interface) return interface.update() except InterfaceNotFound: interfaces.update(vlan_id=vlan_id) interface = Layer3PhysicalInterface(**_interface) return self._engine.add_interface(interface)
[docs] def add_layer3_cluster_interface(self, interface_id, cluster_virtual=None, network_value=None, macaddress=None, nodes=None, cvi_mode='packetdispatch', zone_ref=None, comment=None, **kw): """ Add cluster virtual interface. A "CVI" interface is used as a VIP address for clustered engines. Providing 'nodes' will create the node specific interfaces. You can also add a cluster address with only a CVI, or only NDI's. Add CVI only:: engine.physical_interface.add_cluster_virtual_interface( interface_id=30, cluster_virtual='30.30.30.1', network_value='30.30.30.0/24', macaddress='02:02:02:02:02:06') Add NDI's only:: engine.physical_interface.add_cluster_virtual_interface( interface_id=30, nodes=nodes) Add CVI and NDI's:: engine.physical_interface.add_cluster_virtual_interface( cluster_virtual='5.5.5.1', network_value='5.5.5.0/24', macaddress='02:03:03:03:03:03', nodes=[{'address':'5.5.5.2', 'network_value':'5.5.5.0/24', 'nodeid':1}, {'address':'5.5.5.3', 'network_value':'5.5.5.0/24', 'nodeid':2}]) .. versionchanged:: 0.6.1 Renamed from add_cluster_virtual_interface :param str,int interface_id: physical interface identifier :param str cluster_virtual: CVI address (VIP) for this interface :param str network_value: network value for VIP; format: 10.10.10.0/24 :param str macaddress: mandatory mac address if cluster_virtual and cluster_mask provided :param list nodes: list of dictionary items identifying cluster nodes :param str cvi_mode: packetdispatch is recommended setting :param str zone_ref: zone reference, can be name, href or Zone :param kw: key word arguments are valid NodeInterface sub-interface settings passed in during create time. For example, 'backup_mgt=True' to enable this interface as the management backup. :raises EngineCommandFailed: failure creating interface :return: None """ interfaces = [{'nodes': nodes if nodes else [], 'cluster_virtual': cluster_virtual, 'network_value': network_value}] try: interface = self._engine.interface.get(interface_id) interface._add_interface(interface_id, interfaces=interfaces) return interface.update() except InterfaceNotFound: interface = ClusterPhysicalInterface( engine=self._engine, interface_id=interface_id, interfaces=interfaces, cvi_mode=cvi_mode if macaddress else 'none', macaddress=macaddress, zone_ref=zone_ref, comment=comment, **kw) return self._engine.add_interface(interface)
[docs] def add_layer3_vlan_cluster_interface(self, interface_id, vlan_id, nodes=None, cluster_virtual=None, network_value=None, macaddress=None, cvi_mode='packetdispatch', zone_ref=None, comment=None, **kw): """ Add IP addresses to VLANs on a firewall cluster. The minimum params required are ``interface_id`` and ``vlan_id``. To create a VLAN interface with a CVI, specify ``cluster_virtual``, ``cluster_mask`` and ``macaddress``. To create a VLAN with only NDI, specify ``nodes`` parameter. Nodes data structure is expected to be in this format:: nodes=[{'address':'5.5.5.2', 'network_value':'5.5.5.0/24', 'nodeid':1}, {'address':'5.5.5.3', 'network_value':'5.5.5.0/24', 'nodeid':2}] :param str,int interface_id: interface id to assign VLAN. :param str,int vlan_id: vlan identifier :param list nodes: optional addresses for node interfaces (NDI's). For a cluster, each node will require an address specified using the nodes format. :param str cluster_virtual: cluster virtual ip address (optional). If specified, cluster_mask parameter is required :param str network_value: Specifies the network address, i.e. if cluster virtual is 1.1.1.1, cluster mask could be 1.1.1.0/24. :param str macaddress: (optional) if used will provide the mapping from node interfaces to participate in load balancing. :param str cvi_mode: cvi mode for cluster interface (default: packetdispatch) :param zone_ref: zone to assign, can be name, str href or Zone :param dict kw: keyword arguments are passed to top level of VLAN interface, not the base level physical interface. This is useful if you want to pass in a configuration that enables the DHCP server on a VLAN for example. :raises EngineCommandFailed: failure creating interface :return: None .. note:: If the ``interface_id`` specified already exists, it is still possible to add additional VLANs and interface addresses. """ interfaces = {'nodes': nodes if nodes else [], 'cluster_virtual': cluster_virtual, 'network_value': network_value} interfaces.update(**kw) _interface = {'interface_id': interface_id, 'interfaces': [interfaces], 'macaddress': macaddress, 'cvi_mode': cvi_mode if macaddress else 'none', 'zone_ref': zone_ref, 'comment': comment} try: interface = self._engine.interface.get(interface_id) vlan = interface.vlan_interface.get(vlan_id) # Interface exists, so we need to update but check if VLAN already exists if vlan is None: interfaces.update(vlan_id=vlan_id) interface._add_interface(**_interface) else: for k in ('macaddress', 'cvi_mode'): _interface.pop(k) _interface.update(interface_id='{}.{}'.format(interface_id, vlan_id)) vlan._add_interface(**_interface) return interface.update() except InterfaceNotFound: interfaces.update(vlan_id=vlan_id) interface = ClusterPhysicalInterface(**_interface) return self._engine.add_interface(interface)
[docs] def add_inline_interface(self, interface_id, second_interface_id, logical_interface_ref=None, vlan_id=None, second_vlan_id=None, zone_ref=None, second_zone_ref=None, failure_mode='normal', comment=None, **kw): """ Add an inline interface pair. This method is only for IPS or L2FW engine types. :param str interface_id: interface id of first interface :param str second_interface_id: second interface pair id :param str, href logical_interface_ref: logical interface by href or name :param str vlan_id: vlan ID for first interface in pair :param str second_vlan_id: vlan ID for second interface in pair :param str, href zone_ref: zone reference by name or href for first interface :param str, href second_zone_ref: zone reference by nae or href for second interface :param str failure_mode: normal or bypass :param str comment: optional comment :raises EngineCommandFailed: failure creating interface :return: None """ interface_spec = {'interface_id': interface_id, 'second_interface_id': second_interface_id, 'interface': kw.get('interface') if self._engine.type in ('single_fw', 'fw_cluster') else 'inline_interface'} _interface = {'logical_interface_ref': logical_interface_ref, 'failure_mode': failure_mode, 'zone_ref': zone_ref, 'second_zone_ref': second_zone_ref, 'comment': comment} vlan = {'vlan_id': vlan_id, 'second_vlan_id': second_vlan_id} try: inline_id = '{}-{}'.format(interface_id, second_interface_id) interface = self._engine.interface.get(inline_id) _interface.update(vlan) interface_spec.update(interfaces=[_interface]) interface._add_interface(**interface_spec) return interface.update() except InterfaceNotFound: _interface.update(interfaces=[vlan]) interface_spec.update(_interface) interface = Layer2PhysicalInterface(**interface_spec) return self._engine.add_interface(interface)
[docs] def add_inline_ips_interface(self, interface_id, second_interface_id, logical_interface_ref=None, vlan_id=None, failure_mode='normal', zone_ref=None, second_zone_ref=None, comment=None): """ .. versionadded:: 0.5.6 Using an inline interface on a layer 3 FW requires SMC and engine version >= 6.3. An inline IPS interface is a new interface type for Layer 3 NGFW engines version >=6.3. Traffic passing an Inline IPS interface will have a access rule default action of Allow. Inline IPS interfaces are bypass capable. When using bypass interfaces and NGFW is powered off, in an offline state or overloaded, traffic is allowed through without inspection regardless of the access rules. If the interface does not exist and a VLAN id is specified, the logical interface and zones will be applied to the top level physical interface. If adding VLANs to an existing inline ips pair, the logical and zones will be applied to the VLAN. :param str interface_id: first interface in the interface pair :param str second_interface_id: second interface in the interface pair :param str logical_interface_ref: logical interface name, href or LogicalInterface. If None, 'default_eth' logical interface will be used. :param str vlan_id: optional VLAN id for first interface pair :param str failure_mode: 'normal' or 'bypass' (default: normal). Bypass mode requires fail open interfaces. :param zone_ref: zone for first interface in pair, can be name, str href or Zone :param second_zone_ref: zone for second interface in pair, can be name, str href or Zone :param str comment: comment for this interface :raises EngineCommandFailed: failure creating interface :return: None .. note:: Only a single VLAN is supported on this inline pair type """ _interface = {'interface_id': interface_id, 'second_interface_id': second_interface_id, 'logical_interface_ref': logical_interface_ref, 'failure_mode': failure_mode, 'zone_ref': zone_ref, 'second_zone_ref': second_zone_ref, 'comment': comment, 'interface': 'inline_ips_interface', 'vlan_id': vlan_id} return self.add_inline_interface(**_interface)
[docs] def add_inline_l2fw_interface(self, interface_id, second_interface_id, logical_interface_ref=None, vlan_id=None, zone_ref=None, second_zone_ref=None, comment=None): """ .. versionadded:: 0.5.6 Requires NGFW engine >=6.3 and layer 3 FW or cluster An inline L2 FW interface is a new interface type for Layer 3 NGFW engines version >=6.3. Traffic passing an Inline Layer 2 Firewall interface will have a default action in access rules of Discard. Layer 2 Firewall interfaces are not bypass capable, so when NGFW is powered off, in an offline state or overloaded, traffic is blocked on this interface. If the interface does not exist and a VLAN id is specified, the logical interface and zones will be applied to the top level physical interface. If adding VLANs to an existing inline ips pair, the logical and zones will be applied to the VLAN. :param str interface_id: interface id; '1-2', '3-4', etc :param str logical_interface_ref: logical interface name, href or LogicalInterface. If None, 'default_eth' logical interface will be used. :param str vlan_id: optional VLAN id for first interface pair :param str vlan_id2: optional VLAN id for second interface pair :param zone_ref_intf1: zone for first interface in pair, can be name, str href or Zone :param zone_ref_intf2: zone for second interface in pair, can be name, str href or Zone :raises EngineCommandFailed: failure creating interface :return: None .. note:: Only a single VLAN is supported on this inline pair type """ _interface = {'interface_id': interface_id, 'second_interface_id': second_interface_id, 'logical_interface_ref': logical_interface_ref, 'failure_mode': 'normal', 'zone_ref': zone_ref, 'second_zone_ref': second_zone_ref, 'comment': comment, 'interface': 'inline_l2fw_interface', 'vlan_id': vlan_id} return self.add_inline_interface(**_interface)
[docs] def add_dhcp_interface(self, interface_id, dynamic_index, zone_ref=None, vlan_id=None, comment=None): """ Add a DHCP interface on a single FW :param int interface_id: interface id :param int dynamic_index: index number for dhcp interface :param bool primary_mgt: whether to make this primary mgt :param str zone_ref: zone reference, can be name, href or Zone :raises EngineCommandFailed: failure creating interface :return: None See :class:`~DHCPInterface` for more information """ _interface = {'interface_id': interface_id, 'interfaces': [{'nodes': [ {'dynamic': True, 'dynamic_index': dynamic_index}], 'vlan_id': vlan_id}], 'comment': comment, 'zone_ref': zone_ref} if 'single_fw' in self._engine.type: _interface.update(interface='single_node_interface') try: interface = self._engine.interface.get(interface_id) vlan = interface.vlan_interface.get(vlan_id) # Interface exists, so we need to update but check if VLAN already exists if vlan is None: interface._add_interface(**_interface) interface.update() except InterfaceNotFound: interface = Layer3PhysicalInterface(**_interface) return self._engine.add_interface(interface)
[docs] def add_cluster_interface_on_master_engine(self, interface_id, macaddress, nodes, zone_ref=None, vlan_id=None, comment=None): """ Add a cluster address specific to a master engine. Master engine clusters will not use "CVI" interfaces like normal layer 3 FW clusters, instead each node has a unique address and share a common macaddress. Adding multiple addresses to an interface is not supported with this method. :param str,int interface_id: interface id to use :param str macaddress: mac address to use on interface :param list nodes: interface node list :param bool is_mgmt: is this a management interface :param zone_ref: zone to use, by name, str href or Zone :param vlan_id: optional VLAN id if this should be a VLAN interface :raises EngineCommandFailed: failure creating interface :return: None """ _interface = {'interface_id': interface_id, 'macaddress': macaddress, 'interfaces': [{'nodes': nodes if nodes else [], 'vlan_id': vlan_id}], 'zone_ref': zone_ref, 'comment': comment} try: interface = self._engine.interface.get(interface_id) vlan = interface.vlan_interface.get(vlan_id) # Interface exists, so we need to update but check if VLAN already exists if vlan is None: interface._add_interface(**_interface) interface.update() except InterfaceNotFound: interface = Layer3PhysicalInterface(**_interface) return self._engine.add_interface(interface)
[docs]class VirtualPhysicalInterfaceCollection(InterfaceCollection): """ PhysicalInterface Collection provides an interface to retrieving existing interfaces and helper methods to shortcut the creation of an interface. """ def __init__(self, engine): super(VirtualPhysicalInterfaceCollection, self).__init__(engine, 'virtual_physical_interface')
[docs] def add_layer3_interface(self, interface_id, address, network_value, zone_ref=None, comment=None, **kw): """ Add a layer 3 interface on a virtual engine. :param str,int interface_id: interface identifier :param str address: ip address :param str network_value: network/cidr (12.12.12.0/24) :param str zone_ref: zone reference, can be name, href or Zone :param kw: keyword arguments are passed are any value attribute values of type :class:`smc.core.sub_interfaces.NodeInterface` :raises EngineCommandFailed: failure creating interface :return: None .. note:: If an existing ip address exists on the interface and zone_ref is provided, this value will overwrite any previous zone definition. """ interfaces = {'interface_id': interface_id, 'interfaces': [{'nodes': [{'address': address, 'network_value': network_value}]}], 'zone_ref': zone_ref, 'comment': comment} interfaces.update(kw) try: interface = self._engine.interface.get(interface_id) interface._add_interface(**interfaces) return interface.update() except InterfaceNotFound: interface = VirtualPhysicalInterface(**interfaces) return self._engine.add_interface(interface)
[docs] def add_tunnel_interface(self, interface_id, address, network_value, zone_ref=None, comment=None): """ Creates a tunnel interface for a virtual engine. :param str,int interface_id: the tunnel id for the interface, used as nicid also :param str address: ip address of interface :param str network_value: network cidr for interface; format: 1.1.1.0/24 :param str zone_ref: zone reference for interface can be name, href or Zone :raises EngineCommandFailed: failure during creation :return: None """ interfaces = [{'nodes': [{'address': address, 'network_value': network_value}]}] interface = {'interface_id': interface_id, 'interfaces': interfaces, 'zone_ref': zone_ref, 'comment': comment} tunnel_interface = TunnelInterface(**interface) self._engine.add_interface(tunnel_interface)