Source code for smc.core.contact_address
"""
A ContactAddress is used by elements to provide an alternate
address for communication between engine and management/log server.
This is typically used when the SMC sits behind a NAT address and
the SMC needs to contact the engine directly (this is a default behavior).
In this case, you would add the public IP in front of the engine as a
contact address to the engine interface.
Obtain all eligible interfaces for contact addressess::
>>> engine = Engine('dingo')
>>> for ca in engine.contact_addresses:
... ca
...
ContactAddressNode(interface_id=11, interface_ip=10.10.10.20)
ContactAddressNode(interface_id=120, interface_ip=120.120.120.100)
ContactAddressNode(interface_id=0, interface_ip=1.1.1.1)
ContactAddressNode(interface_id=12, interface_ip=3.3.3.3)
ContactAddressNode(interface_id=12, interface_ip=17.17.17.17)
Retrieve a specific contact address interface for modification::
>>> ca = engine.contact_addresses.get(interface_id=12, interface_ip='3.3.3.3')
>>> ca
ContactAddressNode(interface_id=12, interface_ip=3.3.3.3)
>>> list(ca)
[InterfaceContactAddress(location=Default,address=4.4.4.4), InterfaceContactAddress(location=Foo,address=3.4.5.6)]
Add a new contact address to the fetched interface::
>>> ca.add_contact_address('23.23.23.23', location='mynewlocation')
>>> list(ca)
[InterfaceContactAddress(location=Default,address=4.4.4.4), InterfaceContactAddress(location=Foo,address=3.4.5.6),
InterfaceContactAddress(location=mynewlocation,address=23.23.23.23)]
Remove a contact address::
>>> ca.remove_contact_address('23.23.23.23')
>>> list(ca)
[InterfaceContactAddress(location=Default,address=4.4.4.4), InterfaceContactAddress(location=Foo,address=3.4.5.6)]
.. note:: Contact Addresses for servers (Management/Log Server) do not use
this same object definition
"""
from smc.base.model import SubElement
from smc.elements.helpers import location_helper
from smc.elements.other import ContactAddress
from smc.base.collection import SubElementCollection
[docs]class InterfaceContactAddress(ContactAddress):
"""
An interface contact address is used on engine interfaces
to provide an alternative location to address mapping. This
is frequently used when the engine sits behind a NAT and
you need a public NAT mapping, as might be the case with
site to site VPN.
"""
@property
def addresses(self):
return self.get('address')
@property
def dynamic(self):
return self.get('dynamic', 'false') == 'true'
[docs]class ContactAddressNode(SubElement):
"""
A mapping of contact address to interface. This is specific to
assigning the contact address on the engine.
"""
def __init__(self, **meta):
meta.update(type='contact_addresses')
super(ContactAddressNode, self).__init__(**meta)
self._name, self._address = self.name.split('_')
@property
def _cas(self):
return self.data.get('contact_addresses', [])
def __iter__(self):
for addr in self._cas:
yield InterfaceContactAddress(addr)
def __contains__(self, location_href):
for location in self._cas:
if location.get('location_ref') == location_href:
return True
return False
[docs] def delete(self, location_name):
"""
Remove a given location by location name. This operation is
performed only if the given location is valid, and if so,
`update` is called automatically.
:param str location: location name or location ref
:raises UpdateElementFailed: failed to update element with reason
:rtype: bool
"""
updated = False
location_ref = location_helper(location_name, search_only=True)
if location_ref in self:
self._cas[:] = [loc for loc in self
if loc.location_ref != location_ref]
self.update()
updated = True
return updated
[docs] def update_or_create(self, location, contact_address, with_status=False, **kw):
"""
Update an existing contact address or create if the location does
not exist.
:param str location: name of the location, the location will be added
if it doesn't exist
:param str contact_address: contact address IP. Can be the string 'dynamic'
if this should be a dynamic contact address (i.e. on DHCP interface)
: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 UpdateElementFailed: failed to update element with reason
:rtype: ContactAddressNode
"""
updated, created = False, False
location_ref = location_helper(location)
if location_ref in self:
for ca in self:
if ca.location_ref == location_ref:
ca.update(
address=contact_address if 'dynamic' not in contact_address\
else 'First DHCP Interface ip',
dynamic='true' if 'dynamic' in contact_address else 'false')
updated = True
else:
self.data.setdefault('contact_addresses', []).append(
dict(address=contact_address if 'dynamic' not in contact_address\
else 'First DHCP Interface ip',
dynamic='true' if 'dynamic' in contact_address else 'false',
location_ref=location_ref))
created = True
if updated or created:
self.update()
if with_status:
return self, updated, created
return self
[docs] def add_contact_address(self, contact_address, location='Default'):
"""
Add a contact address to this specified interface. A
contact address is an alternative address which is
typically applied when NAT is used between the NGFW
and another component (such as management server). Adding a
contact address operation is committed immediately.
:param str contact_address: IP address for this contact address.
:raises EngineCommandFailed: invalid contact address
:return: ContactAddressNode
"""
return self.update_or_create(location, contact_address)
[docs] def remove_contact_address(self, location):
"""
Remove a contact address from an interface by the location
name. There is a one to one relationship between a
contact address and
:param str contact_address: ip for contact address
:raises EngineCommandFailed: problem removing address
:return: status of delete as boolean
:rtype: bool
"""
return self.delete(location)
@property
def interface_id(self):
"""
The interface ID for this contact address interface
:rtype: str
"""
return self._name.split(' ')[-1]
@property
def interface_ip(self):
"""
The IP address for this contact address interface
:rtype: str
"""
return self._address
def __str__(self):
return '{}(interface_id={}, interface_ip={})'.format(
self.__class__.__name__, self.interface_id, self.interface_ip)
[docs]class ContactAddressCollection(SubElementCollection):
"""
A contact address collection provides all available interfaces that
can be used to configure a contact address. An eligible interface is
one that is a layer 3 interface with an address assigned (including
VLANs)::
for ca in engine.contact_addresses:
...
.. note:: All eligible interfaces are returned, regardless of whether
a contact address is assigned or not.
"""
def __init__(self, resource):
super(ContactAddressCollection, self).__init__(
resource, ContactAddressNode)
[docs] def get(self, interface_id, interface_ip=None):
"""
Get will return a list of interface references based on the
specified interface id. Multiple references can be returned if
a single interface has multiple IP addresses assigned.
:return: If interface_ip is provided, a single ContactAddressNode
element is returned if found. Otherwise a list will be
returned with all contact address nodes for the given
interface_id.
"""
interfaces = []
for interface in iter(self):
if interface.interface_id == str(interface_id):
if interface_ip:
if interface.interface_ip == interface_ip:
return interface
else:
interfaces.append(interface)
return interfaces