# Path: smc/base/util.py
# def save_to_file(filename, content):
#     """
#     Save content to file. Used by node initial contact but
#     can be used anywhere.
# 
#     :param str filename: name of file to save to
#     :param str content: content to save
#     :return: None
#     :raises IOError: permissions issue saving, invalid directory, etc
#     """
#     import os.path
#     path = os.path.abspath(filename)
#     with open(path, "w") as text_file:
#         text_file.write("{}".format(content))
# 
# def b64encode(source):
#     """
#     Base64 encoding for python 2 and 3
#     
#     :rtype: base64 content
#     """
#     if compat.PY3:
#         source = source.encode('utf-8')
#     return base64.b64encode(source).decode('utf-8')
# 
# Path: smc/base/model.py
# class SubElement(ElementBase):
#     """
#     SubElement is the base class for elements that do not
#     have direct entry points in the SMC and instead are obtained
#     through a reference. They are not 'loaded' directly as are
#     classes that inherit from :class:`Element`.
#     """
# 
#     def __init__(self, **meta):
#         super(SubElement, self).__init__(**meta)
# 
#     @property
#     def name(self):
#         return self._meta.name if self._meta else None
# 
#     @property
#     def href(self):
#         return self._meta.href if self._meta else None
# 
# Path: smc/core/sub_interfaces.py
# class LoopbackInterface(NodeInterface):
#     """
#     Loopback interface for a physical or virtual single firewall.
#     To create a loopback interface, call from the engine node::
#     
#         engine.loopback_interface.add_single(...)
#     """
#     typeof = 'loopback_node_dedicated_interface'
#     
#     def __init__(self, data, engine=None):
#         self._engine = engine
#         super(LoopbackInterface, self).__init__(data)
#         
#     @classmethod
#     def create(cls, address, rank=1, nodeid=1, ospf_area=None, **kwargs):
#         return super(LoopbackInterface, cls).create(
#             interface_id='Loopback Interface',
#             #rank=rank,
#             address=address,
#             network_value='{}/32'.format(address),
#             nodeid=nodeid,
#             ospfv2_area_ref=ospf_area,
#             **kwargs)
#     
#     def add_single(self, address, rank=1, nodeid=1, ospf_area=None, **kwargs):
#         """
#         Add a single loopback interface to this engine. This is used
#         for single or virtual FW engines.
#         
#         :param str address: ip address for loopback
#         :param int nodeid: nodeid to apply. Default to 1 for single FW
#         :param str, Element ospf_area: ospf area href or element
#         :raises UpdateElementFailed: failure to create loopback address
#         :return: None
#         """
#         lb = self.create(address, rank, nodeid, ospf_area, **kwargs)
#         self._engine.nodes[0].data[self.typeof].append(lb.data)
#         self._engine.update()
#     
#     def delete(self):
#         """
#         Delete a loopback interface from this engine. Changes to the
#         engine configuration are done immediately.
#         
#         A simple way to obtain an existing loopback is to iterate the
#         loopbacks or to get by address::
#         
#             lb = engine.loopback_interface.get('127.0.0.10')
#             lb.delete()
#         
#         .. warning:: When deleting a loopback assigned to a node on a cluster
#             all loopbacks with the same rank will also be removed.
#         
#         :raises UpdateElementFailed: failure to delete loopback interface
#         :return: None
#         """
#         nodes = []
#         for node in self._engine.nodes:
#             node.data[self.typeof] = \
#                 [lb for lb in node.loopback_node_dedicated_interface
#                  if lb.get('rank') != self.rank]
#             nodes.append({node.type: node.data})
#         
#         self._engine.data['nodes'] = nodes
#         self._engine.update()
#     
#     def change_ipaddress(self, address):
#         self.update(address=address,
#                     network_value='{}/32'.format(address))
# 
#     def __repr__(self):
#         return 'LoopbackInterface(address={}, nodeid={}, rank={})'.format(
#             self.address, self.nodeid, self.rank)   
# 
# Path: smc/api/exceptions.py
# class LicenseError(SMCException):
#     """
#     Thrown when operations to perform Node specific license related operations such as
#     bind license, fetch license or cancel license fail.
#     For node licensing specific actions, see:
#     :py:class: `smc.core.node.Node`
#     """
# 
# class NodeCommandFailed(SMCException):
#     """
#     Each engine node will have multiple commands that can be executed such as go online,
#     go offline, go standby, locking, etc. When these commands fail, this exception will
#     be thrown and wrap the SMC API response.
#     For all node specific command actions, see:
#     :py:class: `smc.core.node.Node`
#     """
# 
# Path: smc/base/structs.py
# class SerializedIterable(BaseIterable):
#     """
#     A pre-serialized list of elements. This is used when it's easier to
#     provide a pre-serialized class as long as all elements are of the
#     same type.
#     
#     :param iterable item: items for which to perform iteration. Can be
#         another class with an __iter__ method also to chain iterators.
#     :param model: optional class to serialize each iteration. 
#     """
#     def __init__(self, items, model):
#         items = [model(**r) for r in items]
#         super(SerializedIterable, self).__init__(items)


import collections
from smc.base.util import save_to_file, b64encode
from smc.base.model import SubElement
from smc.core.sub_interfaces import LoopbackInterface
from smc.api.exceptions import LicenseError, NodeCommandFailed
from smc.base.structs import SerializedIterable
"""
Node level actions for an engine. Once an engine is loaded, all methods
and resources are available to that particular engine.

For example, to load an engine and run node level commands::

    engine = Engine('myfw')
    for node in engine.nodes:
        node.reboot()
        node.bind_license()
        node.go_online()
        node.go_offline()
        ...
        ...
"""
        


# Path: smc/base/util.py
# def save_to_file(filename, content):
#     """
#     Save content to file. Used by node initial contact but
#     can be used anywhere.
# 
#     :param str filename: name of file to save to
#     :param str content: content to save
#     :return: None
#     :raises IOError: permissions issue saving, invalid directory, etc
#     """
#     import os.path
#     path = os.path.abspath(filename)
#     with open(path, "w") as text_file:
#         text_file.write("{}".format(content))
# 
# def b64encode(source):
#     """
#     Base64 encoding for python 2 and 3
#     
#     :rtype: base64 content
#     """
#     if compat.PY3:
#         source = source.encode('utf-8')
#     return base64.b64encode(source).decode('utf-8')
# 
# Path: smc/base/model.py
# class SubElement(ElementBase):
#     """
#     SubElement is the base class for elements that do not
#     have direct entry points in the SMC and instead are obtained
#     through a reference. They are not 'loaded' directly as are
#     classes that inherit from :class:`Element`.
#     """
# 
#     def __init__(self, **meta):
#         super(SubElement, self).__init__(**meta)
# 
#     @property
#     def name(self):
#         return self._meta.name if self._meta else None
# 
#     @property
#     def href(self):
#         return self._meta.href if self._meta else None
# 
# Path: smc/core/sub_interfaces.py
# class LoopbackInterface(NodeInterface):
#     """
#     Loopback interface for a physical or virtual single firewall.
#     To create a loopback interface, call from the engine node::
#     
#         engine.loopback_interface.add_single(...)
#     """
#     typeof = 'loopback_node_dedicated_interface'
#     
#     def __init__(self, data, engine=None):
#         self._engine = engine
#         super(LoopbackInterface, self).__init__(data)
#         
#     @classmethod
#     def create(cls, address, rank=1, nodeid=1, ospf_area=None, **kwargs):
#         return super(LoopbackInterface, cls).create(
#             interface_id='Loopback Interface',
#             #rank=rank,
#             address=address,
#             network_value='{}/32'.format(address),
#             nodeid=nodeid,
#             ospfv2_area_ref=ospf_area,
#             **kwargs)
#     
#     def add_single(self, address, rank=1, nodeid=1, ospf_area=None, **kwargs):
#         """
#         Add a single loopback interface to this engine. This is used
#         for single or virtual FW engines.
#         
#         :param str address: ip address for loopback
#         :param int nodeid: nodeid to apply. Default to 1 for single FW
#         :param str, Element ospf_area: ospf area href or element
#         :raises UpdateElementFailed: failure to create loopback address
#         :return: None
#         """
#         lb = self.create(address, rank, nodeid, ospf_area, **kwargs)
#         self._engine.nodes[0].data[self.typeof].append(lb.data)
#         self._engine.update()
#     
#     def delete(self):
#         """
#         Delete a loopback interface from this engine. Changes to the
#         engine configuration are done immediately.
#         
#         A simple way to obtain an existing loopback is to iterate the
#         loopbacks or to get by address::
#         
#             lb = engine.loopback_interface.get('127.0.0.10')
#             lb.delete()
#         
#         .. warning:: When deleting a loopback assigned to a node on a cluster
#             all loopbacks with the same rank will also be removed.
#         
#         :raises UpdateElementFailed: failure to delete loopback interface
#         :return: None
#         """
#         nodes = []
#         for node in self._engine.nodes:
#             node.data[self.typeof] = \
#                 [lb for lb in node.loopback_node_dedicated_interface
#                  if lb.get('rank') != self.rank]
#             nodes.append({node.type: node.data})
#         
#         self._engine.data['nodes'] = nodes
#         self._engine.update()
#     
#     def change_ipaddress(self, address):
#         self.update(address=address,
#                     network_value='{}/32'.format(address))
# 
#     def __repr__(self):
#         return 'LoopbackInterface(address={}, nodeid={}, rank={})'.format(
#             self.address, self.nodeid, self.rank)   
# 
# Path: smc/api/exceptions.py
# class LicenseError(SMCException):
#     """
#     Thrown when operations to perform Node specific license related operations such as
#     bind license, fetch license or cancel license fail.
#     For node licensing specific actions, see:
#     :py:class: `smc.core.node.Node`
#     """
# 
# class NodeCommandFailed(SMCException):
#     """
#     Each engine node will have multiple commands that can be executed such as go online,
#     go offline, go standby, locking, etc. When these commands fail, this exception will
#     be thrown and wrap the SMC API response.
#     For all node specific command actions, see:
#     :py:class: `smc.core.node.Node`
#     """
# 
# Path: smc/base/structs.py
# class SerializedIterable(BaseIterable):
#     """
#     A pre-serialized list of elements. This is used when it's easier to
#     provide a pre-serialized class as long as all elements are of the
#     same type.
#     
#     :param iterable item: items for which to perform iteration. Can be
#         another class with an __iter__ method also to chain iterators.
#     :param model: optional class to serialize each iteration. 
#     """
#     def __init__(self, items, model):
#         items = [model(**r) for r in items]
#         super(SerializedIterable, self).__init__(items)


# Path: smc/core/node.py
import collections
from smc.base.util import save_to_file, b64encode
from smc.base.model import SubElement
from smc.core.sub_interfaces import LoopbackInterface
from smc.api.exceptions import LicenseError, NodeCommandFailed
from smc.base.structs import SerializedIterable

"""
Node level actions for an engine. Once an engine is loaded, all methods
and resources are available to that particular engine.

For example, to load an engine and run node level commands::

    engine = Engine('myfw')
    for node in engine.nodes:
        node.reboot()
        node.bind_license()
        node.go_online()
        node.go_offline()
        ...
        ...
"""
        


class Node(SubElement):