Exemple #1
0
 def _load(cls, engine):
     nodes = []
     for node in engine.data.get('nodes', []):
         for typeof, data in node.items():
             cache = ElementCache(data)
             node = Node(name=cache.get('name'),
                         href=cache.get_link('self'),
                         type=typeof)
             node.data = cache
             node._engine = engine
             nodes.append(node)
     return nodes
Exemple #2
0
class MultilinkMember(object):
    """
    A multilink member represents an netlink member used on a multilink
    configuration. Multilink uses netlinks to specify settings specific
    to a connection, network, whether it should be active or standby and
    optionally QoS.
    Use this class to create mutlilink members that are required for
    creating a Multilink element.
    """
    def __init__(self, kwargs):
        self.data = ElementCache(kwargs)
    
    @property
    def ip_range(self):
        """
        Specifies the IP address range for dynamic source address
        translation (NAT) for the internal source IP addresses on the
        NetLink. Can also be set.

        :rtype: str
        """
        return self.data.get('ip_range')
    
    @ip_range.setter
    def ip_range(self, value):
        if '-' in value:
            self.data.update(ip_range=value)
    
    @property
    def netlink_role(self):
        """
        Shows whether the Netlink is active or standby.
        Active - traffic is routed through the NetLink according to the
        method you specify in the Outbound Multi-Link element properties.
        Standby - traffic is only routed through the netlink if all primary
        (active) netlinks are unavailable.
        
        :rtype: str
        """
        return self.data.get('netlink_role')
    
    @netlink_role.setter
    def netlink_role(self, value):
        if value in ('standby', 'active'):
            self.data.update(netlink_role=value)
    
    @property
    def network(self):
        """
        Specifies the Network element that represents the IP address
        space in the directly connected external network of the network
        link. Can also be set.
        
        :rtype: Network
        """
        return Element.from_href(self.data.get('network_ref'))
    
    @network.setter
    def network(self, value):
        self.data.update(network_ref=element_resolver(value))
    
    @property
    def netlink(self):
        """
        The static netlink referenced in this multilink member
        
        :rtype: StaticNetlink
        """
        return Element.from_href(self.data.get('netlink_ref'))

    @classmethod
    def create(cls, netlink, ip_range=None, netlink_role='active'):
        """
        Create a multilink member. Multilink members are added to an
        Outbound Multilink configuration and define the ip range, static
        netlink to use, and the role. This element can be passed to the
        Multilink constructor to simplify creation of the outbound multilink.
        
        :param StaticNetlink,DynamicNetlink netlink: static netlink element to
            use as member
        :param str ip_range: the IP range for source NAT for this member. The
            IP range should be part of the defined network range used by this
            netlink. Not required for dynamic netlink
        :param str netlink_role: role of this netlink, 'active' or 'standby'
        :raises ElementNotFound: Specified netlink could not be found
        :rtype: MultilinkMember
        """
        member_def = dict(
            netlink_ref=netlink.href,
            netlink_role=netlink_role,
            ip_range=ip_range if netlink.typeof == 'netlink' else '0.0.0.0')
        if netlink.typeof == 'netlink': # static netlink vs dynamic netlink
            member_def.update(network_ref=netlink.network[0].href)
            
        return cls(member_def)
    
    def __repr__(self):
        return 'MultilinkMember(netlink={},netlink_role={},ip_range={})'.format(
            self.netlink, self.netlink_role, self.ip_range)  
Exemple #3
0
class MultilinkMember(object):
    """
    A multilink member represents an netlink member used on a multilink
    configuration. Multilink uses netlinks to specify settings specific
    to a connection, network, whether it should be active or standby and
    optionally QoS.
    Use this class to create mutlilink members that are required for
    creating a Multilink element.
    
    :ivar Network network: network element reference specifying netlink subnet
    :ivar StaticNetlink,DynamicNetlink netlink: netlink element reference
    """
    network = ElementRef('network_ref')
    netlink = ElementRef('netlink_ref')
    
    def __init__(self, kwargs):
        self.data = ElementCache(kwargs)
    
    def __eq__(self, other):
        return all([
            self.ip_range == other.ip_range,
            self.netlink_role == other.netlink_role,
            self.data.get('network_ref') == other.data.get('network_ref'),
            self.data.get('netlink_ref') == other.data.get('netlink_ref')
            ])
    
    def __ne__(self, other):
        return not self == other

    def __hash__(self):
        return hash((self.ip_range, self.netlink_role,
            self.data.get('network_ref'), self.data.get('netlink_ref')))
    
    @property
    def ip_range(self):
        """
        Specifies the IP address range for dynamic source address
        translation (NAT) for the internal source IP addresses on the
        NetLink. Can also be set.

        :rtype: str
        """
        return self.data.get('ip_range')
    
    @ip_range.setter
    def ip_range(self, value):
        if '-' in value:
            self.data.update(ip_range=value)
    
    @property
    def netlink_role(self):
        """
        Shows whether the Netlink is active or standby.
        Active - traffic is routed through the NetLink according to the
        method you specify in the Outbound Multi-Link element properties.
        Standby - traffic is only routed through the netlink if all primary
        (active) netlinks are unavailable.
        
        :rtype: str
        """
        return self.data.get('netlink_role')
    
    @netlink_role.setter
    def netlink_role(self, value):
        if value in ('standby', 'active'):
            self.data.update(netlink_role=value)

    @classmethod
    def create(cls, netlink, ip_range=None, netlink_role='active'):
        """
        Create a multilink member. Multilink members are added to an
        Outbound Multilink configuration and define the ip range, static
        netlink to use, and the role. This element can be passed to the
        Multilink constructor to simplify creation of the outbound multilink.
        
        :param StaticNetlink,DynamicNetlink netlink: static netlink element to
            use as member
        :param str ip_range: the IP range for source NAT for this member. The
            IP range should be part of the defined network range used by this
            netlink. Not required for dynamic netlink
        :param str netlink_role: role of this netlink, 'active' or 'standby'
        :raises ElementNotFound: Specified netlink could not be found
        :rtype: MultilinkMember
        """
        member_def = dict(
            netlink_ref=netlink.href,
            netlink_role=netlink_role,
            ip_range=ip_range if netlink.typeof == 'netlink' else '0.0.0.0')
        if netlink.typeof == 'netlink': # static netlink vs dynamic netlink
            member_def.update(network_ref=netlink.network[0].href)
            
        return cls(member_def)
    
    def __repr__(self):
        return 'MultilinkMember(netlink={},netlink_role={},ip_range={})'.format(
            self.netlink, self.netlink_role, self.ip_range)  
Exemple #4
0
class Task(SubElement):
    """
    Task representation. This is generic and the format is used for
    any calls to SMC that return an asynchronous follower link to
    check the status of the task.

    :param str last_message: Last message received on this task
    :param bool in_progress: Whether the task is in progress or finished
    :param bool success: Whether the task succeeded or not
    :param str follower: Fully qualified path to the follower link to track
        this task.
    """
    def __init__(self, task):
        super(Task, self).__init__(href=task.get("follower", None),
                                   name=task.get("type", None))
        self.data = ElementCache(task)

    @property
    def resource(self):
        """
        The resource/s associated with this task

        :rtype: list(Element)
        """
        return [
            Element.from_href(resource)
            for resource in self.data.get("resource", [])
        ]

    @property
    def progress(self):
        """
        Percentage of completion

        :rtype: int
        """
        return self.data.get("progress", 0)

    @property
    def success(self):
        """
        the task has succeed

        :rtype: boolean
        """
        return self.data.get("success", 0)

    @property
    def last_message(self):
        """
        the last message returned by the task

        :rtype: string
        """
        return self.data.get("last_message", 0)

    @property
    def start_time(self):
        """
        Task start time in UTC datetime format

        :rtype: datetime
        """
        start_time = self.data.get("start_time")
        if start_time:
            return millis_to_utc(start_time)

    @property
    def end_time(self):
        """
        Task end time in UTC datetime format

        :rtype: datetime
        """
        end_time = self.data.get("end_time")
        if end_time:
            return millis_to_utc(end_time)

    def abort(self):
        """
        Abort existing task.

        :raises ActionCommandFailed: aborting task failed with reason
        :return: None
        """
        try:
            self.make_request(method="delete", resource="abort")

        except ResourceNotFound:
            pass
        except ActionCommandFailed:
            pass

    @property
    def result_url(self):
        """
        Link to result (this task)

        :rtype: str
        """
        return self.get_relation("result")

    def update_status(self):
        """
        Gets the current status of this task and returns a
        new task object.

        :raises TaskRunFailed: fail to update task status
        """
        task = self.make_request(TaskRunFailed, href=self.href)

        return Task(task)

    def __getattr__(self, key):
        return self.data.get(key)

    @staticmethod
    def execute(self, resource, **kw):
        """
        Execute the task and return a TaskOperationPoller.

        :rtype: TaskOperationPoller
        """
        params = kw.pop("params", {})
        json = kw.pop("json", None)
        task = self.make_request(TaskRunFailed,
                                 method="create",
                                 params=params,
                                 json=json,
                                 resource=resource)

        timeout = kw.pop("timeout", 5)
        wait_for_finish = kw.pop("wait_for_finish", True)

        return TaskOperationPoller(task=task,
                                   timeout=timeout,
                                   wait_for_finish=wait_for_finish,
                                   **kw)

    @staticmethod
    def download(self, resource, filename, timeout=5, max_tries=36, **kw):
        """
        Start and return a Download Task

        :rtype: DownloadTask(TaskOperationPoller)
        """
        params = kw.pop("params", {})
        task = self.make_request(TaskRunFailed,
                                 method="create",
                                 resource=resource,
                                 params=params)

        return DownloadTask(timeout=timeout,
                            max_tries=max_tries,
                            filename=filename,
                            task=task)
Exemple #5
0
class RoutingTree(SubElement):
    """
    RoutingTree is the base class for both Routing and Antispoofing nodes.
    This provides a commmon API for operations that affect how routing table
    and antispoofing operate.
    """
    def __init__(self, data=None, **meta):
        super(RoutingTree, self).__init__(**meta)
        if data is not None:
            self.data = ElementCache(data)

    def __iter__(self):
        for node in self.data[self.typeof]:
            data = ElementCache(node)
            yield (self.__class__(href=data.get_link('self'),
                                  type=self.__class__.__name__,
                                  data=node,
                                  parent=self))

    @property
    def name(self):
        """
        Interface name / ID for routing level

        :return: name of routing node
        :rtype: str
        """
        return self.data.get('name')

    @property
    def nicid(self):
        """
        NIC id for this interface

        :return: nic identifier
        :rtype: str
        """
        return self.data.get('nic_id')

    @property
    def dynamic_nicid(self):
        """
        NIC id for this dynamic interface
        
        :return: nic identifier, if this is a DHCP interface
        :rtype: str or None
        """
        return self.data.get('dynamic_nicid')

    @property
    def ip(self):
        """
        IP network / host for this route

        :return: IP address of this routing level
        :rtype: str
        """
        return self.data.get('ip')

    @property
    def level(self):
        """
        Routing nodes have multiple 'levels' where routes can
        be nested. Most routes are placed at the interface level.
        This setting can mostly be ignored, but provides an
        informative view of how the route is nested.

        :return: routing node level (interface,network,gateway,any)
        :rtype: str
        """
        return self.data.get('level')

    @property
    def related_element_type(self):
        """
        .. versionadded:: 0.6.0
            Requires SMC version >= 6.4
            
        Related element type defines the 'type' of element at this
        routing or antispoofing node level.
        
        :rtype: str
        """
        return self.data.get('related_element_type')

    def as_tree(self, level=0):
        """
        Display the routing tree representation in string
        format
        
        :rtype: str
        """
        ret = '--' * level + repr(self) + '\n'
        for routing_node in self:
            ret += routing_node.as_tree(level + 1)
        return ret

    def get(self, interface_id):
        """
        Obtain routing configuration for a specific interface by
        ID.

        .. note::
            If interface is a VLAN, you must use a str to specify the
            interface id, such as '3.13' (interface 3, VLAN 13)

        :param str,int interface_id: interface identifier
        :raises InterfaceNotFound: invalid interface for engine
        :return: Routing element, or None if not found
        :rtype: Routing
        """
        for interface in self:
            if interface.nicid == str(interface_id) or \
                interface.dynamic_nicid == str(interface_id):
                return interface
        raise InterfaceNotFound('Specified interface {} does not exist on '
                                'this engine.'.format(interface_id))

    def delete(self):
        super(RoutingTree, self).delete()
        flush_parent_cache(self._parent)

    def update(self):
        super(RoutingTree, self).update()
        flush_parent_cache(self._parent)

    def all(self):
        """
        Return all routes for this engine.

        :return: current route entries as :class:`.Routing` element
        :rtype: list
        """
        return [node for node in self]

    def __str__(self):
        return '{}(name={},level={},type={})'.format(self.__class__.__name__,
                                                     self.name, self.level,
                                                     self.related_element_type)

    def __repr__(self):
        return str(self)
Exemple #6
0
class Routing(SubElement):
    """
    Routing represents the Engine routing configuration and provides the
    ability to view and add features to routing nodes such as OSPF.
    """
    def __init__(self, data=None, **meta):
        super(Routing, self).__init__(**meta)
        if data is not None:
            self.data = ElementCache(**data)

    def __iter__(self):
        for node in self.data['routing_node']:
            data = ElementCache(**node)
            yield (Routing(href=data.get_link('self'), data=node))

    @property
    def name(self):
        """
        Interface name / ID for routing level

        :return: name of routing node
        :rtype: str
        """
        return self.data.get('name')

    @property
    def nicid(self):
        """
        NIC id for this interface

        :return str nic identifier
        """
        return self.data.get('nic_id')

    @property
    def dynamic_nicid(self):
        """
        NIC id for this dynamic interface
        
        :return str nic identifier
        """
        return self.data.get('dynamic_nicid')

    @property
    def ip(self):
        """
        IP network / host for this route

        :return: IP address of this routing level
        :rtype: str
        """
        return self.data.get('ip')

    @property
    def level(self):
        """
        Routing nodes have multiple 'levels' where routes can
        be nested. Most routes are placed at the interface level.
        This setting can mostly be ignored, but provides an
        informative view of how the route is nested.

        :return: routing node level (interface,network,gateway,any)
        :rtype: str
        """
        return self.data.get('level')

    def get(self, interface_id):
        """
        Obtain routing configuration for a specific interface by
        ID.

        .. note::
            If interface is a VLAN, you must use a str to specify the
            interface id, such as '3.13' (interface 3, VLAN 13)

        :param str,int interface_id: interface identifier
        :return: Routing element, or None if not found
        :rtype: Routing
        """
        for interface in iter(self):
            if interface.nicid == str(interface_id) or \
                interface.dynamic_nicid == str(interface_id):
                return interface

    def add_traffic_handler(self, netlink, netlink_gw=None, network=None):
        """
        Add a traffic handler to a routing node. A traffic handler can be
        either a static netlink or a multilink traffic handler. If ``network``
        is not specified and the interface has multiple IP addresses, the 
        traffic handler will be added to all ipv4 addresses.
        
        Add a pre-defined netlink to the route table of interface 0::
        
            engine = Engine('vm')
            rnode = engine.routing.get(0)
            rnode.add_traffic_handler(StaticNetlink('mynetlink'))
        
        Add a pre-defined netlink only to a specific network on an interface
        with multiple addresses. Specify a netlink_gw for the netlink::
        
            rnode = engine.routing.get(0)
            rnode.add_traffic_handler(
                StaticNetlink('mynetlink'),
                netlink_gw=Router('myrtr'),
                network='172.18.1.0/24')
            
        :param StaticNetlink,Multilink netlink: netlink element
        :param Element netlink_gw: gateway for the netlink element. Can be
            None if no gateway is needed. Element type is typically of type
            :class:`smc.elements.network.Router`.
        :param str network: if network specified, only add OSPF to this network on interface
        :raises EngineCommandFailed: failure updating routing
        :raises ElementNotFound: ospf area not found
        :return: None
        """
        netlink = {
            'href': netlink.href,
            'level': 'gateway',
            'routing_node': [],
            'name': netlink.name
        }

        if netlink_gw:
            netlink_gateway = {
                'level': 'any',
                'href': netlink_gw.href,
                'name': netlink_gw.name
            }

            netlink['routing_node'].append(netlink_gateway)

        self._bind_to_ipv4_network(network, netlink)
        self.update()

    def add_ospf_area(self,
                      ospf_area,
                      communication_mode='NOT_FORCED',
                      unicast_ref=None,
                      network=None):
        """
        Add OSPF Area to this routing node.

        Communication mode specifies how the interface will interact with the
        adjacent OSPF environment. Please see SMC API documentation for more
        in depth information on each option.

        If the interface has multiple networks nested below, all networks
        will receive the OSPF area by default unless the ``network`` parameter
        is specified. OSPF cannot be applied to IPv6 networks.

        Example of adding an area to interface routing node::

            area = OSPFArea('area0') #obtain area resource

            #Set on routing interface 0
            interface = engine.routing.get(0)
            interface.add_ospf_area(area)

        .. note:: If UNICAST is specified, you must also provide a unicast_ref
                  to identify the remote host

        :param OSPFArea ospf_area: OSPF area instance or href
        :param str communication_mode: NOT_FORCED|POINT_TO_POINT|PASSIVE|UNICAST
        :param Element unicast_ref: Element used as unicast gw (required for UNICAST)
        :param str network: if network specified, only add OSPF to this network
            on interface
        :raises EngineCommandFailed: failure updating routing
        :raises ElementNotFound: ospf area not found
        :return: None
        """
        communication_mode = communication_mode.upper()
        node = {
            'href': ospf_area.href,
            'communication_mode': communication_mode,
            'level': 'gateway',
            'routing_node': [],
            'name': ospf_area.name
        }

        if communication_mode == 'UNICAST':
            # Need a destination ref, add to sub routing_node
            node['routing_node'].append({
                'href': unicast_ref.href,
                'level': 'any',
                'name': unicast_ref.name
            })

        self._bind_to_ipv4_network(network, node)
        self.update()

    def add_bgp_peering(self, bgp_peering, external_bgp_peer, network=None):
        """
        Add a BGP configuration to this routing interface. 
        If the interface has multiple ipaddresses, all networks will receive
        the BGP peering by default unless the ``network`` parameter is
        specified.
        
        Example of adding BGP to an interface by ID::

            interface = engine.routing.get(0)
            interface.add_bgp_peering(
                BGPPeering('mypeer'),
                ExternalBGPPeer('neighbor'))

        :param BGPPeering bgp_peering: BGP Peer element
        :param ExternalBGPPeer external_bgp_peer: peer element or href
        :param str network: if network specified, only add OSPF to this network
            on interface
        :raises UpdateElementFailed: failed to add BGP
        :return: None
        """
        bgp = {
            'href': bgp_peering.href,
            'level': 'gateway',
            'routing_node': [],
            'name': bgp_peering.name
        }

        external_peer = {
            'href': external_bgp_peer.href,
            'level': 'any',
            'name': external_bgp_peer.name
        }

        bgp['routing_node'].append(external_peer)

        self._bind_to_ipv4_network(network, bgp)
        self.update()

    def add_static_route(self, gateway, destination, network=None):
        """
        Add a static route to this route table. Destination can be any element
        type supported in the routing table such as a Group of network members.
        ::

            >>> engine = Engine('ve-1')
            >>> itf = engine.routing.get(0)
            >>> itf.add_static_route(
                    gateway=Router('tmprouter'),
                    destination=[Group('routegroup')])
        
        :param Element gateway: gateway for this route (Router, Host)
        :param Element destination: destination network/s for this route.
        :type destination: list(Host, Router, ..)
        :raises UpdateElementFailed: failure to update routing table
        :return: None
        """
        route = {
            'href': gateway.href,
            'level': 'gateway',
            'routing_node': [],
            'name': gateway.name
        }

        for dest in destination:
            route['routing_node'].append({
                'href': dest.href,
                'level': 'any',
                'name': dest.name
            })

        self._bind_to_ipv4_network(network, route)
        self.update()

    def add_dynamic_gateway(self, networks):
        """
        A dynamic gateway object is a router that is attached to
        a DHCP interface. You can associate networks with this gateway
        address to identify networks on this interface.
        ::
        
            route = engine.routing.get(0)
            route.add_dynamic_gateway([Network('mynetwork')])
        
        :param list Network: list of network elements to add to
            this gateway
        :return: None
        """
        route = {
            'dynamic_classid': 'gateway',
            'level': 'gateway',
            'routing_node': []
        }

        for network in networks:
            route['routing_node'].append({
                'href': network.href,
                'level': 'any',
                'name': network.name
            })

        for networks in iter(self):
            networks.data['routing_node'].append(route)

        self.update()

    def _bind_to_ipv4_network(self, network, element):
        for networks in iter(self):
            if len(networks.ip.split(':')) == 1:  # Skip IPv6
                if network is not None:  # Only place on specific network
                    if networks.ip == network:
                        networks.data['routing_node'].append(element)
                else:
                    networks.data['routing_node'].append(element)

    def remove_route_element(self, element, network=None):
        """
        Remove a route element by href or Element. Use this if you want to
        remove a netlink or a routing element such as BGP or OSPF. Removing
        is done from within the routing interface context.
        ::
        
            rnode = engine.routing.get(0)
            rnode.remove_route_element(StaticNetlink('mynetlink'))
            
        Only from a specific network on a multi-address interface::
        
            rnode.remove_route_element(
                StaticNetlink('mynetlink'),
                network='172.18.1.0/24')
        
        :param str,Element element: element to remove from this routing node
        :param str network: if network specified, only add OSPF to this
            network on interface
        :raises UpdateElementFailed: failed to remove route element
        :return: None
        """
        element = element_resolver(element)
        routing_node = []
        for networks in iter(self):
            if network is not None:
                if networks.ip != network:
                    routing_node.append(networks.data)
                else:
                    rnode = [
                        gw for gw in networks.data['routing_node']
                        if gw.get('href') != element
                    ]
                    networks.data['routing_node'] = rnode
                    routing_node.append(networks.data)
            else:
                rnode = [
                    gw for gw in networks.data['routing_node']
                    if gw.get('href') != element
                ]
                networks.data['routing_node'] = rnode
                routing_node.append(networks.data)

        self.data['routing_node'] = routing_node
        self.update()

    def all(self):
        """
        Return all routes for this engine.

        :return: current route entries as :class:`.Routing` element
        :rtype: list
        """
        return [node for node in iter(self)]

    def __str__(self):
        return '{0}(name={1},level={2})'.format(self.__class__.__name__,
                                                self.name, self.level)

    def __repr__(self):
        return str(self)
Exemple #7
0
class Antispoofing(SubElement):
    """
    Anti-spoofing is configured by default based on
    interface networks directly attached. It is possible
    to override these settings by adding additional
    networks as valid source networks on a given
    interface.

    Antispoofing is nested similar to routes. Iterate the
    antispoofing configuration::

        for entry in engine.antispoofing.all():
            print(entry)
    """
    def __init__(self, data=None, **meta):
        super(Antispoofing, self).__init__(**meta)
        if data is not None:
            self.data = ElementCache(**data)

    def __iter__(self):
        for node in self.data['antispoofing_node']:
            data = ElementCache(**node)
            yield (Antispoofing(href=data.get_link('self'), data=node))

    @property
    def name(self):
        """
        Name on this node level
        """
        return self.data.get('name')

    @property
    def ip(self):
        """
        IP network / address / host of this antispoofing entry

        :return: IP Address of this antispoofing node
        :rtype: str
        """
        return self.data.get('ip')

    @property
    def level(self):
        """
        Routing nodes have multiple 'levels' where routes can
        be nested. Most routes are placed at the interface level.
        This setting can mostly be ignored, but provides an
        informative view of how the route is nested.

        :return: routing node level (interface,network,gateway,any)
        :rtype: str
        """
        return self.data.get('level')

    @property
    def validity(self):
        """
        Enabled or disabled antispoofing entry

        :return: validity of this entry (enable,disable,absolute)
        :rtype: str
        """
        return self.data.get('validity')

    @property
    def nicid(self):
        """
        NIC id for this interface

        :return str nic identifier
        """
        return self.data.get('nic_id')

    def add(self, entry):
        """
        Add an entry to this antispoofing node level.
        Entry can be either href or network elements specified
        in :py:class:`smc.elements.network`
        ::

            for entry in engine.antispoofing.all():
                if entry.name == 'Interface 0':
                    entry.add(Network('network-10.1.2.0/24'))

        :param Element entry: entry to add, i.e. Network('mynetwork'), Host(..)
        :return: None
        :raises CreateElementFailed: failed adding entry
        :raises ElementNotFound: element entry specified not in SMC
        """
        node = {
            'antispoofing_node': [],
            'auto_generated': 'false',
            'href': entry.href,
            'level': self.level,
            'validity': 'enable',
            'name': entry.name
        }

        self.data['antispoofing_node'].append(node)
        self.update()

    def all(self):
        return [node for node in iter(self)]

    def __str__(self):
        return '{0}(name={1},level={2})'.format(self.__class__.__name__,
                                                self.name, self.level)

    def __repr__(self):
        return str(self)
Exemple #8
0
class RoutingTree(SubElement):
    """
    RoutingTree is the base class for both Routing and Antispoofing nodes.
    This provides a commmon API for operations that affect how routing table
    and antispoofing operate.
    """
    def __init__(self, data=None, **meta):
        super(RoutingTree, self).__init__(**meta)
        if data is not None:
            self.data = ElementCache(data)
    
    def __iter__(self):
        for node in self.data[self.typeof]:
            data = ElementCache(node)
            yield(self.__class__(
                    href=data.get_link('self'),
                    type=self.__class__.__name__,
                    data=node,
                    parent=self))
    
    @property
    def name(self):
        """
        Interface name / ID for routing level

        :return: name of routing node
        :rtype: str
        """
        return self.data.get('name')

    @property
    def nicid(self):
        """
        NIC id for this interface

        :return: nic identifier
        :rtype: str
        """
        return self.data.get('nic_id')

    @property
    def dynamic_nicid(self):
        """
        NIC id for this dynamic interface
        
        :return: nic identifier, if this is a DHCP interface
        :rtype: str or None
        """
        return self.data.get('dynamic_nicid')
    
    @property
    def ip(self):
        """
        IP network / host for this route

        :return: IP address of this routing level
        :rtype: str
        """
        return self.data.get('ip')

    @property
    def level(self):
        """
        Routing nodes have multiple 'levels' where routes can
        be nested. Most routes are placed at the interface level.
        This setting can mostly be ignored, but provides an
        informative view of how the route is nested.

        :return: routing node level (interface,network,gateway,any)
        :rtype: str
        """
        return self.data.get('level')
    
    @property
    def related_element_type(self):
        """
        .. versionadded:: 0.6.0
            Requires SMC version >= 6.4
            
        Related element type defines the 'type' of element at this
        routing or antispoofing node level.
        
        :rtype: str
        """
        if 'related_element_type' in self.data:
            return self.data.get('related_element_type')
        return None if self.dynamic_nicid or (self.nicid and '.' in self.nicid) else \
            Element.from_href(self.data.get('href')).typeof # pre-6.4
        
    def as_tree(self, level=0):
        """
        Display the routing tree representation in string
        format
        
        :rtype: str
        """
        ret = '--' * level + repr(self) + '\n'
        for routing_node in self:
            ret += routing_node.as_tree(level+1)
        return ret
    
    def get(self, interface_id):
        """
        Obtain routing configuration for a specific interface by
        ID.

        .. note::
            If interface is a VLAN, you must use a str to specify the
            interface id, such as '3.13' (interface 3, VLAN 13)

        :param str,int interface_id: interface identifier
        :raises InterfaceNotFound: invalid interface for engine
        :return: Routing element, or None if not found
        :rtype: Routing
        """
        for interface in self:
            if interface.nicid == str(interface_id) or \
                interface.dynamic_nicid == str(interface_id):
                return interface
        raise InterfaceNotFound('Specified interface {} does not exist on '
            'this engine.'.format(interface_id))
    
    def delete(self):
        super(RoutingTree, self).delete()
        flush_parent_cache(self._parent)
        
    def update(self):
        super(RoutingTree, self).update()
        flush_parent_cache(self._parent)
    
    def all(self):
        """
        Return all routes for this engine.

        :return: current route entries as :class:`.Routing` element
        :rtype: list
        """
        return [node for node in self]

    def __str__(self):
        return '{}(name={},level={},type={})'.format(
            self.__class__.__name__, self.name, self.level, self.related_element_type)

    def __repr__(self):
        return str(self)
Exemple #9
0
class MultilinkMember(object):
    """
    A multilink member represents an netlink member used on a multilink
    configuration. Multilink uses netlinks to specify settings specific
    to a connection, network, whether it should be active or standby and
    optionally QoS.
    Use this class to create mutlilink members that are required for
    creating a Multilink element.

    :ivar Network network: network element reference specifying netlink subnet
    :ivar StaticNetlink,DynamicNetlink netlink: netlink element reference
    """

    network = ElementRef("network_ref")
    netlink = ElementRef("netlink_ref")

    def __init__(self, kwargs):
        self.data = ElementCache(kwargs)

    def __eq__(self, other):
        return all([
            self.ip_range == other.ip_range,
            self.netlink_role == other.netlink_role,
            self.data.get("network_ref") == other.data.get("network_ref"),
            self.data.get("netlink_ref") == other.data.get("netlink_ref"),
        ])

    def __ne__(self, other):
        return not self == other

    def __hash__(self):
        return hash((
            self.ip_range,
            self.netlink_role,
            self.data.get("network_ref"),
            self.data.get("netlink_ref"),
        ))

    @property
    def ip_range(self):
        """
        Specifies the IP address range for dynamic source address
        translation (NAT) for the internal source IP addresses on the
        NetLink. Can also be set.

        :rtype: str
        """
        return self.data.get("ip_range")

    @ip_range.setter
    def ip_range(self, value):
        if "-" in value:
            self.data.update(ip_range=value)

    @property
    def netlink_role(self):
        """
        Shows whether the Netlink is active or standby.
        Active - traffic is routed through the NetLink according to the
        method you specify in the Outbound Multi-Link element properties.
        Standby - traffic is only routed through the netlink if all primary
        (active) netlinks are unavailable.

        :rtype: str
        """
        return self.data.get("netlink_role")

    @netlink_role.setter
    def netlink_role(self, value):
        if value in ("standby", "active"):
            self.data.update(netlink_role=value)

    @classmethod
    def create(cls, netlink, ip_range=None, netlink_role="active"):
        """
        Create a multilink member. Multilink members are added to an
        Outbound Multilink configuration and define the ip range, static
        netlink to use, and the role. This element can be passed to the
        Multilink constructor to simplify creation of the outbound multilink.

        :param StaticNetlink,DynamicNetlink netlink: static netlink element to
            use as member
        :param str ip_range: the IP range for source NAT for this member. The
            IP range should be part of the defined network range used by this
            netlink. Not required for dynamic netlink
        :param str netlink_role: role of this netlink, 'active' or 'standby'
        :raises ElementNotFound: Specified netlink could not be found
        :rtype: MultilinkMember
        """
        member_def = dict(
            netlink_ref=netlink.href,
            netlink_role=netlink_role,
            ip_range=ip_range if netlink.typeof == "netlink" else "0.0.0.0",
        )
        if netlink.typeof == "netlink":  # static netlink vs dynamic netlink
            member_def.update(network_ref=netlink.network[0].href)

        return cls(member_def)

    def __repr__(self):
        return "MultilinkMember(netlink={},netlink_role={},ip_range={})".format(
            self.netlink, self.netlink_role, self.ip_range)