Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions dim-testsuite/tests/dns_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,16 @@ def test_create_cname(self):
with raises(InvalidParameterError):
self.r.rr_create(name='d.test.com.', type='MX', preference=10, exchange='a.test.com.')

def test_rr_list_exact(self):
self.r.zone_create('test.com')
self.r.rr_create(name='*.test.com.', type='A', ip='12.0.0.1')
self.r.rr_create(name='a.test.com.', type='A', ip='12.0.0.2')
wildcard = rrs(self.r.rr_list(pattern='*.test.com.'))
assert ('*', 'test.com', 'A', '12.0.0.1') in wildcard
assert ('a', 'test.com', 'A', '12.0.0.2') in wildcard
assert rrs(self.r.rr_list(pattern='*.test.com.', exact=True)) == rrs([
('*', 'test.com', 'A', '12.0.0.1')])

def test_create_cname_2(self):
# ND-100
self.r.zone_create('test.com')
Expand Down
2 changes: 1 addition & 1 deletion dim/CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* fix missing check if pool is already in target layer3domain (#232)
* fix missing check to avoid creating A or AAAA records in zone profiles (#238)
* update dependencies (#248)
* add exact match option to :func:`rr_list`/``rr_list2`` to allow listing literal wildcard records (#298)

5.0.1
-----
Expand Down Expand Up @@ -428,4 +429,3 @@ API Changes:
* *vlan* option for :func:`ippool_create`, :func:`ippool_set_vlan`
* *priority* parameter for :func:`subnet_set_priority`
* *prefix*, *maxsplit* parameters for :func:`ippool_get_delegation`

67 changes: 43 additions & 24 deletions dim/dim/rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2286,7 +2286,8 @@ def rr_set_ttl(self, ttl=None, view=None, **kwargs):

@readonly
def rr_list(self, pattern=None, type=None, zone=None, view=None, profile=False, limit=None, offset=0,
value_as_object=False, fields=False, created_by=None, modified_by=None, layer3domain=None):
value_as_object=False, fields=False, created_by=None, modified_by=None, layer3domain=None,
exact=False):
qfields = [RR.name, Zone.name.label('zone'), ZoneView.name.label('view'), RR.ttl, RR.type, RR.value,
Layer3Domain.name.label('layer3domain')]
if fields:
Expand Down Expand Up @@ -2320,22 +2321,31 @@ def rr_list(self, pattern=None, type=None, zone=None, view=None, profile=False,
rr_query = rr_query.filter(RR.modified_by == modified_by)
if soa_query:
soa_query = soa_query.filter(ZoneView.modified_by == modified_by)
try:
ip = IP(pattern)
except:
ip = None
ip = None
if pattern is not None and not exact:
try:
ip = IP(pattern)
except:
ip = None
if ip:
rr_query = rr_query.filter(inside(Ipblock.address, ip))
soa_query = None
elif pattern is not None:
if len(pattern) > 0 and pattern[-1] not in ['*', '?', '.']:
pattern += '.'
wildcard = make_wildcard(pattern)
columns = [RR.name, RR.target]
rr_query = rr_query.filter(or_(*[col.like(wildcard) for col in columns]))
if soa_query is not None:
soa_query = soa_query.filter(or_((Zone.name + '.').like(wildcard),
ZoneView.primary.like(wildcard)))
search_value = pattern
if len(search_value) > 0 and search_value[-1] not in ['*', '?', '.']:
search_value += '.'
if exact:
rr_query = rr_query.filter(or_(*[col == search_value for col in columns]))
if soa_query is not None:
soa_query = soa_query.filter(or_((Zone.name + '.') == search_value,
ZoneView.primary == search_value))
else:
wildcard = make_wildcard(search_value)
rr_query = rr_query.filter(or_(*[col.like(wildcard) for col in columns]))
if soa_query is not None:
soa_query = soa_query.filter(or_((Zone.name + '.').like(wildcard),
ZoneView.primary.like(wildcard)))
# We can't limit reverse zones records because we can't do the same sorting in the query
if limit is not None and not reverse_zone_sorting:
limit = int(limit)
Expand Down Expand Up @@ -2430,7 +2440,7 @@ def split_by_ip(dict_list):
@readonly
def rr_list2(self, pattern=None, type=None, zone=None, view=None, profile=False, limit=None, offset=0,
value_as_object=False, fields=False, created_by=None, modified_by=None, layer3domain=None,
type_sort='asc', sort_by='record', order='asc'):
type_sort='asc', sort_by='record', order='asc', exact=False):
qfields = [RR.name, Zone.name.label('zone'), ZoneView.name.label('view'), RR.ttl, RR.type, RR.value,
Layer3Domain.name.label('layer3domain')]
if fields:
Expand Down Expand Up @@ -2464,22 +2474,31 @@ def rr_list2(self, pattern=None, type=None, zone=None, view=None, profile=False,
rr_query = rr_query.filter(RR.modified_by == modified_by)
if soa_query:
soa_query = soa_query.filter(ZoneView.modified_by == modified_by)
try:
ip = IP(pattern)
except:
ip = None
ip = None
if pattern is not None and not exact:
try:
ip = IP(pattern)
except:
ip = None
if ip:
rr_query = rr_query.filter(inside(Ipblock.address, ip))
soa_query = None
elif pattern is not None:
if len(pattern) > 0 and pattern[-1] not in ['*', '?', '.']:
pattern += '.'
wildcard = make_wildcard(pattern)
columns = [RR.name, RR.target]
rr_query = rr_query.filter(or_(*[col.like(wildcard) for col in columns]))
if soa_query is not None:
soa_query = soa_query.filter(or_((Zone.name + '.').like(wildcard),
ZoneView.primary.like(wildcard)))
search_value = pattern
if len(search_value) > 0 and search_value[-1] not in ['*', '?', '.']:
search_value += '.'
if exact:
rr_query = rr_query.filter(or_(*[col == search_value for col in columns]))
if soa_query is not None:
soa_query = soa_query.filter(or_((Zone.name + '.') == search_value,
ZoneView.primary == search_value))
else:
wildcard = make_wildcard(search_value)
rr_query = rr_query.filter(or_(*[col.like(wildcard) for col in columns]))
if soa_query is not None:
soa_query = soa_query.filter(or_((Zone.name + '.').like(wildcard),
ZoneView.primary.like(wildcard)))

rr_count = fast_count(rr_query)
soa_count = 0
Expand Down
1 change: 1 addition & 0 deletions dim/doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,7 @@ RR Functions
- *limit*: limit the amount of results
- *offset*: skip the first *offset* results
- *pattern* (string): pattern to match against the RR name or IP address. A relative pattern will be converted into an absolute one.
- *exact* (boolean): if true, the *pattern* is treated as a literal RR name instead of a wildcard/glob
- *type* (string): filter by RR type
- *zone* (string): filter by RR zone
- *view* (string): :ref:`view_option`
Expand Down
1 change: 1 addition & 0 deletions ndcli/CHANGES
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
5.0.4
-----
* fix TXT records when importing zone (#292)
* add ``--exact`` switch to ``list rrs`` for literal wildcard records (#298)

5.0.3
-----
Expand Down
4 changes: 3 additions & 1 deletion ndcli/dimcli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2541,6 +2541,7 @@ def list_zoneprofiles(self, args):
Argument('wildcard'),
rr_type_arg,
layer3domain_group,
Option(None, 'exact', action='store_true', help='match only exact record names'),
script_option)
def list_rrs(self, args):
'''
Expand All @@ -2549,7 +2550,8 @@ def list_rrs(self, args):
options = OptionDict(pattern=args.wildcard)
# do not use get_layer3domain() as CNAMEs etc. do not have a layer3domain
options.set_if(type=args.type,
layer3domain=args.get('layer3domain'))
layer3domain=args.get('layer3domain'),
exact=args.exact)
logger.info("Result for list rrs %s" % args.wildcard)
rrs = self.client.rr_list(**options)
_print_table(['record', {},
Expand Down
12 changes: 12 additions & 0 deletions ndcli/tests/dimcli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,18 @@ def test_create_rr_cname():
assert ndcli('delete zone test.com --cleanup').ok


def test_list_rrs_exact():
assert ndcli('create zone test.com').ok
assert ndcli('create rr *.test.com. a 12.0.0.1').ok
assert ndcli('create rr a.test.com. a 12.0.0.2').ok
wildcard = nosoa(ndcli('list rrs *.test.com. -H').table)
assert ['*', 'test.com', 'default', '', 'A', '12.0.0.1'] in wildcard
assert ['a', 'test.com', 'default', '', 'A', '12.0.0.2'] in wildcard
assert nosoa(ndcli('list rrs *.test.com. --exact -H').table) == [
['*', 'test.com', 'default', '', 'A', '12.0.0.1']]
assert ndcli('delete zone test.com --cleanup').ok


def test_show_rr():
# ND-92
assert ndcli('create zone test.com').ok
Expand Down