Search code examples
objectpythonintrospection

Efficiently introspecting Python object IP address instance ownership


In the code below, I am trying to find a way to eliminate self.owner from the L3Address() class... the idea is that I want to know who owns the IP address on a given Vlan or Interface without having to explicitly call it out.

Is there a better way to derive the IPv4 addresses' owner (perhaps through introspection)?

import ipaddr

class SomethingOwned(object):
    def __init__(self, owner=None):
        self._owner = owner
        # Build self.owner (the object instance that owns the subclass object)
        self._create_owner()

    def _create_owner(self):
        """
        create self.owner and ensure the subclass was called correctly
        """
        if not (self._owner is None):
            self.owner = self._owner
        else:
            raise ValueError, "%s() must be called with an 'owner' arg, which cannot be None" % self.__class__.__name__

class L3Address(SomethingOwned):
    """
    A Layer3 IP PDU address that has an owning object
    """
    def __init__(self, version=None, owner=None, addr=None, masklen=None):
        # Call SomethingOwned.__init__(owner=owner) to add an owner attribute
        super(L3Address, self).__init__(owner=owner)
        self._addr = addr
        self._masklen = masklen
        self._version = version

        # Build self._obj
        self._create_ip_object()

        self.addr = self._obj.ip
        self.netmask = self._obj.netmask
        self.masklen = self._obj.prefixlen

    def __repr__(self):
        return "<IPv%i %s/%s>" % (self._version, self.addr, self.masklen)


    def _create_ip_object(self):
        """
        create self._obj and ensure the subclass was called with the correct version
        """
        if self._version==4:
            if (self._masklen is None):
                self._obj = ipaddr.IPv4Network(self._addr)
            else:
                self._obj = ipaddr.IPv4Network("%s/%s" % (self._addr, self._masklen))
        elif self._version==6:
            if (self._masklen is None):
                self._obj = ipaddr.IPv6Network(self._addr)
            else:
                self._obj = ipaddr.IPv6Network("%s/%s" % (self._addr, self._masklen))
        else:
            raise ValueError, "Version must be 4 or 6"


class IPv4(L3Address):
    def __init__(self, **kwargs):
        ## Initialize the IPv4 network object instance
        super(IPv4, self).__init__(version=4, **kwargs)

class IPv6(L3Address):
    def __init__(self, **kwargs):
        ## Initialize the IPv6 network object instance
        super(IPv6, self).__init__(version=6, **kwargs)

class Vlan(object):
    def __init__(self, name=None, id=None, ipv4=None):
        self.id = id
        self.name = name
        if not (ipv4 is None):
            ### NOTE: I am trying to eliminate the need for the owner arg here
            self.ipv4 = IPv4(owner=self, addr=ipv4)
    def __repr__(self):
        return "Vlan %s (name: %s)" % (self.id, self.name)

class Interface(object):
    def __init__(self, id=None, ipv4=None):
        self.id = id
        self.ipv4 = None
        if not (ipv4 is None):
            ### NOTE: I am trying to eliminate the need for the owner arg here
            self.ipv4 = IPv4(owner=self, addr=ipv4)
    def __repr__(self):
        return "Interface %s" % self.id



if __name__=='__main__':
    def find_owner(ip_instance):
        print "Owner of '%s' is '%s'" % (ip_instance, ip_instance.owner)

    find_owner(Interface(id='ge-0/0/0', ipv4='1.1.1.1').ipv4)
    find_owner(Vlan(id='25', name='accounting', ipv4='1.1.1.2/25').ipv4)

Execution Results:

[mpenning@hotcoffee ~]$ python cisco.py 
Owner of <IPv4 1.1.1.1/32> is 'Interface ge-0/0/0'
Owner of <IPv4 1.1.1.2/25> is 'Vlan 25 (name: accounting)'
[mpenning@hotcoffee ~]$

Solution

  • Your current approach using owner is the probably the cleanest solution.

    That being said, if you need to find out who owns an IP address, then gc.get_referrers() may be of help.