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  from io import StringIO
     19
     20  import dns.rdataset
     21  import dns.rdatatype
     22  import dns.renderer
     23
     24
     25 -class Node(object):
     26
     27      """A DNS node.
     28
     29      A node is a set of rdatasets
     30
     31      @ivar rdatasets: the node's rdatasets
     32      @type rdatasets: list of dns.rdataset.Rdataset objects"""
     33
     34      __slots__ = ['rdatasets']
     35
     36 -    def __init__(self):
     37          """Initialize a DNS node.
     38          """
     39
     40          self.rdatasets = []
     41
     42 -    def to_text(self, name, **kw):
     43          """Convert a node to text format.
     44
     45          Each rdataset at the node is printed.  Any keyword arguments
     46          to this method are passed on to the rdataset's to_text() method.
     47          @param name: the owner name of the rdatasets
     48          @type name: dns.name.Name object
     49          @rtype: string
     50          """
     51
     52          s = StringIO()
     53          for rds in self.rdatasets:
     54              if len(rds) > 0:
     55                  s.write(rds.to_text(name, **kw))
     56                  s.write(u'\n')
     57          return s.getvalue()[:-1]
     58
     59 -    def __repr__(self):
     60          return '<DNS node ' + str(id(self)) + '>'
     61
     62 -    def __eq__(self, other):
     63          """Two nodes are equal if they have the same rdatasets.
     64
     65          @rtype: bool
     66          """
     67          #
     68          # This is inefficient.  Good thing we don't need to do it much.
     69          #
     70          for rd in self.rdatasets:
     71              if rd not in other.rdatasets:
     72                  return False
     73          for rd in other.rdatasets:
     74              if rd not in self.rdatasets:
     75                  return False
     76          return True
     77
     78 -    def __ne__(self, other):
     79          return not self.__eq__(other)
     80
     81 -    def __len__(self):
     82          return len(self.rdatasets)
     83
     84 -    def __iter__(self):
     85          return iter(self.rdatasets)
     86
     87 -    def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
     88                        create=False):
     89          """Find an rdataset matching the specified properties in the
     90          current node.
     91
     92          @param rdclass: The class of the rdataset
     93          @type rdclass: int
     94          @param rdtype: The type of the rdataset
     95          @type rdtype: int
     96          @param covers: The covered type.  Usually this value is
     97          dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or
     98          dns.rdatatype.RRSIG, then the covers value will be the rdata
     99          type the SIG/RRSIG covers.  The library treats the SIG and RRSIG
    100          types as if they were a family of
    101          types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).  This makes RRSIGs much
    102          easier to work with than if RRSIGs covering different rdata
    103          types were aggregated into a single RRSIG rdataset.
    104          @type covers: int
    105          @param create: If True, create the rdataset if it is not found.
    106          @type create: bool
    107          @raises KeyError: An rdataset of the desired type and class does
    108          not exist and I{create} is not True.
    109          @rtype: dns.rdataset.Rdataset object
    110          """
    111
    112          for rds in self.rdatasets:
    113              if rds.match(rdclass, rdtype, covers):
    114                  return rds
    115          if not create:
    116              raise KeyError
    117          rds = dns.rdataset.Rdataset(rdclass, rdtype)
    118          self.rdatasets.append(rds)
    119          return rds
    120
    121 -    def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
    122                       create=False):
    123          """Get an rdataset matching the specified properties in the
    124          current node.
    125
    126          None is returned if an rdataset of the specified type and
    127          class does not exist and I{create} is not True.
    128
    129          @param rdclass: The class of the rdataset
    130          @type rdclass: int
    131          @param rdtype: The type of the rdataset
    132          @type rdtype: int
    133          @param covers: The covered type.
    134          @type covers: int
    135          @param create: If True, create the rdataset if it is not found.
    136          @type create: bool
    137          @rtype: dns.rdataset.Rdataset object or None
    138          """
    139
    140          try:
    141              rds = self.find_rdataset(rdclass, rdtype, covers, create)
    142          except KeyError:
    143              rds = None
    144          return rds
    145
    146 -    def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE):
    147          """Delete the rdataset matching the specified properties in the
    148          current node.
    149
    150          If a matching rdataset does not exist, it is not an error.
    151
    152          @param rdclass: The class of the rdataset
    153          @type rdclass: int
    154          @param rdtype: The type of the rdataset
    155          @type rdtype: int
    156          @param covers: The covered type.
    157          @type covers: int
    158          """
    159
    160          rds = self.get_rdataset(rdclass, rdtype, covers)
    161          if rds is not None:
    162              self.rdatasets.remove(rds)
    163
    164 -    def replace_rdataset(self, replacement):
    165          """Replace an rdataset.
    166
    167          It is not an error if there is no rdataset matching I{replacement}.
    168
    169          Ownership of the I{replacement} object is transferred to the node;
    170          in other words, this method does not store a copy of I{replacement}
    171          at the node, it stores I{replacement} itself.
    172          """
    173
    174          if not isinstance(replacement, dns.rdataset.Rdataset):
    175              raise ValueError('replacement is not an rdataset')
    176          self.delete_rdataset(replacement.rdclass, replacement.rdtype,
    177                               replacement.covers)
    178          self.rdatasets.append(replacement)
    179