Package dns :: Module node |
[hide private]
[frames] | no frames]

# Source Code for Module dns.node

      1  # Copyright (C) 2001-2007, 2009-2011 Nominum, Inc.
      2  #
      3  # Permission to use, copy, modify, and distribute this software and its
      4  # documentation for any purpose with or without fee is hereby granted,
      5  # provided that the above copyright notice and this permission notice
      6  # appear in all copies.
      7  #
      8  # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
      9  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
     11  # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     14  # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15
     16  """DNS nodes.  A node is a set of rdatasets."""
     17
     18  import StringIO
     19
     20  import dns.rdataset
     21  import dns.rdatatype
     22  import dns.renderer
     23
     24 -class Node(object):
     25      """A DNS node.
     26
     27      A node is a set of rdatasets
     28
     29      @ivar rdatasets: the node's rdatasets
     30      @type rdatasets: list of dns.rdataset.Rdataset objects"""
     31
     32      __slots__ = ['rdatasets']
     33
     34 -    def __init__(self):
     35          """Initialize a DNS node.
     36          """
     37
     38          self.rdatasets = [];
     39
     40 -    def to_text(self, name, **kw):
     41          """Convert a node to text format.
     42
     43          Each rdataset at the node is printed.  Any keyword arguments
     44          to this method are passed on to the rdataset's to_text() method.
     45          @param name: the owner name of the rdatasets
     46          @type name: dns.name.Name object
     47          @rtype: string
     48          """
     49
     50          s = StringIO.StringIO()
     51          for rds in self.rdatasets:
     52              if len(rds) > 0:
     53                  print >> s, rds.to_text(name, **kw)
     54          return s.getvalue()[:-1]
     55
     56 -    def __repr__(self):
     57          return '<DNS node ' + str(id(self)) + '>'
     58
     59 -    def __eq__(self, other):
     60          """Two nodes are equal if they have the same rdatasets.
     61
     62          @rtype: bool
     63          """
     64          #
     65          # This is inefficient.  Good thing we don't need to do it much.
     66          #
     67          for rd in self.rdatasets:
     68              if rd not in other.rdatasets:
     69                  return False
     70          for rd in other.rdatasets:
     71              if rd not in self.rdatasets:
     72                  return False
     73          return True
     74
     75 -    def __ne__(self, other):
     76          return not self.__eq__(other)
     77
     78 -    def __len__(self):
     79          return len(self.rdatasets)
     80
     81 -    def __iter__(self):
     82          return iter(self.rdatasets)
     83
     84 -    def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
     85                        create=False):
     86          """Find an rdataset matching the specified properties in the
     87          current node.
     88
     89          @param rdclass: The class of the rdataset
     90          @type rdclass: int
     91          @param rdtype: The type of the rdataset
     92          @type rdtype: int
     93          @param covers: The covered type.  Usually this value is
     94          dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or
     95          dns.rdatatype.RRSIG, then the covers value will be the rdata
     96          type the SIG/RRSIG covers.  The library treats the SIG and RRSIG
     97          types as if they were a family of
     98          types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).  This makes RRSIGs much
     99          easier to work with than if RRSIGs covering different rdata
    100          types were aggregated into a single RRSIG rdataset.
    101          @type covers: int
    102          @param create: If True, create the rdataset if it is not found.
    103          @type create: bool
    104          @raises KeyError: An rdataset of the desired type and class does
    105          not exist and I{create} is not True.
    106          @rtype: dns.rdataset.Rdataset object
    107          """
    108
    109          for rds in self.rdatasets:
    110              if rds.match(rdclass, rdtype, covers):
    111                  return rds
    112          if not create:
    113              raise KeyError
    114          rds = dns.rdataset.Rdataset(rdclass, rdtype)
    115          self.rdatasets.append(rds)
    116          return rds
    117
    118 -    def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
    119                       create=False):
    120          """Get an rdataset matching the specified properties in the
    121          current node.
    122
    123          None is returned if an rdataset of the specified type and
    124          class does not exist and I{create} is not True.
    125
    126          @param rdclass: The class of the rdataset
    127          @type rdclass: int
    128          @param rdtype: The type of the rdataset
    129          @type rdtype: int
    130          @param covers: The covered type.
    131          @type covers: int
    132          @param create: If True, create the rdataset if it is not found.
    133          @type create: bool
    134          @rtype: dns.rdataset.Rdataset object or None
    135          """
    136
    137          try:
    138              rds = self.find_rdataset(rdclass, rdtype, covers, create)
    139          except KeyError:
    140              rds = None
    141          return rds
    142
    143 -    def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE):
    144          """Delete the rdataset matching the specified properties in the
    145          current node.
    146
    147          If a matching rdataset does not exist, it is not an error.
    148
    149          @param rdclass: The class of the rdataset
    150          @type rdclass: int
    151          @param rdtype: The type of the rdataset
    152          @type rdtype: int
    153          @param covers: The covered type.
    154          @type covers: int
    155          """
    156
    157          rds = self.get_rdataset(rdclass, rdtype, covers)
    158          if not rds is None:
    159              self.rdatasets.remove(rds)
    160
    161 -    def replace_rdataset(self, replacement):
    162          """Replace an rdataset.
    163
    164          It is not an error if there is no rdataset matching I{replacement}.
    165
    166          Ownership of the I{replacement} object is transferred to the node;
    167          in other words, this method does not store a copy of I{replacement}
    168          at the node, it stores I{replacement} itself.
    169          """
    170
    171          if not isinstance(replacement, dns.rdataset.Rdataset):
    172              raise ValueError, 'replacement is not an rdataset'
    173          self.delete_rdataset(replacement.rdclass, replacement.rdtype,
    174                               replacement.covers)
    175          self.rdatasets.append(replacement)
    176