1 # Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc.
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.
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.
16 """DNS nodes. A node is a set of rdatasets."""
27 A node is a set of rdatasets
29 @ivar rdatasets: the node's rdatasets
30 @type rdatasets: list of dns.rdataset.Rdataset objects"""
32 __slots__ = ['rdatasets']
35 """Initialize a DNS node.
40 def to_text(self, name, **kw):
41 """Convert a node to text format.
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
50 s = StringIO.StringIO()
51 for rds in self.rdatasets:
52 print >> s, rds.to_text(name, **kw)
53 return s.getvalue()[:-1]
56 return '<DNS node ' + str(id(self)) + '>'
58 def __eq__(self, other):
59 """Two nodes are equal if they have the same rdatasets.
64 # This is inefficient. Good thing we don't need to do it much.
66 for rd in self.rdatasets:
67 if rd not in other.rdatasets:
69 for rd in other.rdatasets:
70 if rd not in self.rdatasets:
74 def __ne__(self, other):
75 return not self.__eq__(other)
78 return len(self.rdatasets)
81 return iter(self.rdatasets)
83 def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
85 """Find an rdataset matching the specified properties in the
88 @param rdclass: The class of the rdataset
90 @param rdtype: The type of the rdataset
92 @param covers: The covered type. Usually this value is
93 dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or
94 dns.rdatatype.RRSIG, then the covers value will be the rdata
95 type the SIG/RRSIG covers. The library treats the SIG and RRSIG
96 types as if they were a family of
97 types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much
98 easier to work with than if RRSIGs covering different rdata
99 types were aggregated into a single RRSIG rdataset.
101 @param create: If True, create the rdataset if it is not found.
103 @raises KeyError: An rdataset of the desired type and class does
104 not exist and I{create} is not True.
105 @rtype: dns.rdataset.Rdataset object
108 for rds in self.rdatasets:
109 if rds.match(rdclass, rdtype, covers):
113 rds = dns.rdataset.Rdataset(rdclass, rdtype)
114 self.rdatasets.append(rds)
117 def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
119 """Get an rdataset matching the specified properties in the
122 None is returned if an rdataset of the specified type and
123 class does not exist and I{create} is not True.
125 @param rdclass: The class of the rdataset
127 @param rdtype: The type of the rdataset
129 @param covers: The covered type.
131 @param create: If True, create the rdataset if it is not found.
133 @rtype: dns.rdataset.Rdataset object or None
137 rds = self.find_rdataset(rdclass, rdtype, covers, create)
142 def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE):
143 """Delete the rdataset matching the specified properties in the
146 If a matching rdataset does not exist, it is not an error.
148 @param rdclass: The class of the rdataset
150 @param rdtype: The type of the rdataset
152 @param covers: The covered type.
156 rds = self.get_rdataset(rdclass, rdtype, covers)
158 self.rdatasets.remove(rds)
160 def replace_rdataset(self, replacement):
161 """Replace an rdataset.
163 It is not an error if there is no rdataset matching I{replacement}.
165 Ownership of the I{replacement} object is transferred to the node;
166 in other words, this method does not store a copy of I{replacement}
167 at the node, it stores I{replacement} itself.
170 self.delete_rdataset(replacement.rdclass, replacement.rdtype,
172 self.rdatasets.append(replacement)