mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Add DNS management plugin port to the new ldap backend.
This commit is contained in:
committed by
Rob Crittenden
parent
8eabf068fb
commit
36c239cda4
797
ipalib/plugins/dns2.py
Normal file
797
ipalib/plugins/dns2.py
Normal file
@@ -0,0 +1,797 @@
|
||||
# Authors:
|
||||
# Pavel Zuna <pzuna@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2009 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; version 2 only
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
Domain Name System (DNS) Plugin
|
||||
|
||||
Implements a set of commands useful for manipulating DNS records used by
|
||||
the BIND LDAP plugin.
|
||||
|
||||
EXAMPLES:
|
||||
|
||||
Add new zone;
|
||||
ipa dns2-create example.com nameserver.example.com admin@example.com
|
||||
|
||||
Add second nameserver for example.com:
|
||||
ipa dns2-add-rr example.com @ NS nameserver2.example.com
|
||||
|
||||
Delete previously added nameserver from example.com:
|
||||
ipa dns2-del-rr example.com @ NS nameserver2.example.com
|
||||
|
||||
Add new A record for www.example.com: (random IP)
|
||||
ipa dns2-add-rr example.com www A 80.142.15.2
|
||||
|
||||
Show zone example.com:
|
||||
ipa dns2-show example.com
|
||||
|
||||
Find zone with 'example' in it's domain name:
|
||||
ipa dns2-find example
|
||||
|
||||
Find records for resources with 'www' in their name in zone example.com:
|
||||
ipa dns2-find-rr example.com www
|
||||
|
||||
Find A records for resource www in zone example.com
|
||||
ipa dns2-find-rr example.com --resource www --type A
|
||||
|
||||
Show records for resource www in zone example.com
|
||||
ipa dns2-show-rr example.com www
|
||||
|
||||
Delete zone example.com with all resource records:
|
||||
ipa dns2-delete example.com
|
||||
"""
|
||||
|
||||
# A few notes about the LDAP schema to make this plugin more understandable:
|
||||
# - idnsRecord object is a HOSTNAME with one or more resource records
|
||||
# - idnsZone object is a idnsRecord object with mandatory SOA record
|
||||
# it basically makes the assumption that ZONE == DOMAINNAME + SOA record
|
||||
# resource records can be stored in both idnsZone and idnsRecord objects
|
||||
|
||||
import time
|
||||
|
||||
from ipalib import api, crud, errors
|
||||
from ipalib import Object, Command
|
||||
from ipalib import Flag, Int, Str, StrEnum
|
||||
|
||||
# parent DN
|
||||
_zone_container_dn = api.env.container_dns
|
||||
|
||||
# supported resource record types
|
||||
_record_types = (
|
||||
u'A', u'AAAA', u'A6', u'AFSDB', u'CERT', u'CNAME', u'DNAME',
|
||||
u'DS', u'HINFO', u'KEY', u'KX', u'LOC', u'MD', u'MINFO', u'MX',
|
||||
u'NAPTR', u'NS', u'NSEC', u'NXT', u'PTR', u'RRSIG', u'SSHFP',
|
||||
u'SRV', u'TXT',
|
||||
)
|
||||
|
||||
# supported DNS classes, IN = internet, rest is almost never used
|
||||
_record_classes = (u'IN', u'CS', u'CH', u'HS')
|
||||
|
||||
# attributes displayed by default for resource records
|
||||
_record_default_attributes = ['%srecord' % r for r in _record_types]
|
||||
_record_default_attributes.append('idnsname')
|
||||
|
||||
# attributes displayed by default for zones
|
||||
_zone_default_attributes = [
|
||||
'idnsname', 'idnszoneactive', 'idnssoamname', 'idnssoarname',
|
||||
'idnssoaserial', 'idnssoarefresh', 'idnssoaretry', 'idnssoaexpire',
|
||||
'idnssoaminimum'
|
||||
]
|
||||
|
||||
|
||||
# build zone dn
|
||||
def _get_zone_dn(ldap, idnsname):
|
||||
rdn = ldap.make_rdn_from_attr('idnsName', idnsname)
|
||||
return ldap.make_dn_from_rdn(rdn, _zone_container_dn)
|
||||
|
||||
# build dn for entry with record
|
||||
def _get_record_dn(ldap, zone, idnsname):
|
||||
parent_dn = _get_zone_dn(ldap, zone)
|
||||
if idnsname == '@' or idnsname == zone:
|
||||
return parent_dn
|
||||
rdn = ldap.make_rdn_from_attr('idnsName', idnsname)
|
||||
return ldap.make_dn_from_rdn(rdn, parent_dn)
|
||||
|
||||
|
||||
class dns2(Object):
|
||||
"""DNS zone/SOA record object."""
|
||||
|
||||
takes_params = (
|
||||
Str('idnsname',
|
||||
cli_name='name',
|
||||
doc='zone name (FQDN)',
|
||||
normalizer=lambda value: value.lower(),
|
||||
primary_key=True,
|
||||
),
|
||||
Str('idnssoamname',
|
||||
cli_name='name_server',
|
||||
doc='authoritative name server',
|
||||
),
|
||||
Str('idnssoarname',
|
||||
cli_name='admin_email',
|
||||
doc='administrator e-mail address',
|
||||
default_from=lambda idnsname: 'root.%s' % idnsname,
|
||||
normalizer=lambda value: value.replace('@', '.'),
|
||||
),
|
||||
Int('idnssoaserial?',
|
||||
cli_name='serial',
|
||||
doc='SOA serial',
|
||||
),
|
||||
Int('idnssoarefresh?',
|
||||
cli_name='refresh',
|
||||
doc='SOA refresh',
|
||||
),
|
||||
Int('idnssoaretry?',
|
||||
cli_name='retry',
|
||||
doc='SOA retry',
|
||||
),
|
||||
Int('idnssoaexpire?',
|
||||
cli_name='expire',
|
||||
doc='SOA expire',
|
||||
),
|
||||
Int('idnssoaminimum?',
|
||||
cli_name='minimum',
|
||||
doc='SOA minimum',
|
||||
),
|
||||
Int('dnsttl?',
|
||||
cli_name='ttl',
|
||||
doc='SOA time to live',
|
||||
),
|
||||
StrEnum('dnsclass?',
|
||||
cli_name='class',
|
||||
doc='SOA class',
|
||||
values=_record_classes,
|
||||
),
|
||||
Flag('idnsallowdynupdate',
|
||||
cli_name='allow_dynupdate',
|
||||
doc='allow dynamic update?',
|
||||
),
|
||||
)
|
||||
|
||||
api.register(dns2)
|
||||
|
||||
|
||||
class dns2_create(crud.Create):
|
||||
"""
|
||||
Create new DNS zone/SOA record.
|
||||
"""
|
||||
|
||||
def execute(self, *args, **options):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.Backend.ldap2
|
||||
idnsname = args[0]
|
||||
|
||||
# build entry attributes
|
||||
entry_attrs = self.args_options_2_entry(*args, **options)
|
||||
|
||||
# build entry DN
|
||||
dn = _get_zone_dn(ldap, idnsname)
|
||||
|
||||
# fill in required attributes
|
||||
entry_attrs['objectclass'] = ['top', 'idnsRecord', 'idnsZone']
|
||||
entry_attrs['idnszoneactive'] = True
|
||||
|
||||
# fill default values, build SOA serial from current date
|
||||
soa_serial = int('%s01' % time.strftime('%Y%d%m'))
|
||||
entry_attrs.setdefault('idnssoaserial', soa_serial)
|
||||
entry_attrs.setdefault('idnssoarefresh', 3600)
|
||||
entry_attrs.setdefault('idnssoaretry', 900)
|
||||
entry_attrs.setdefault('idnssoaexpire', 1209600)
|
||||
entry_attrs.setdefault('idnssoaminimum', 3600)
|
||||
|
||||
# create zone entry
|
||||
ldap.add_entry(dn, entry_attrs)
|
||||
|
||||
# get zone entry with created attributes for output
|
||||
return ldap.get_entry(dn, entry_attrs.keys())
|
||||
|
||||
def output_for_cli(self, textui, result, *args, **options):
|
||||
(dn, entry_attrs) = result
|
||||
idnsname = args[0]
|
||||
|
||||
textui.print_name(self.name)
|
||||
textui.print_attribute('dn', dn)
|
||||
textui.print_entry(entry_attrs)
|
||||
textui.print_dashed('Created DNS zone "%s".' % idnsname)
|
||||
|
||||
api.register(dns2_create)
|
||||
|
||||
|
||||
class dns2_delete(crud.Delete):
|
||||
"""
|
||||
Delete existing DNS zone/SOA record.
|
||||
"""
|
||||
|
||||
def execute(self, *args, **options):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
idnsname = args[0]
|
||||
|
||||
# build zone entry DN
|
||||
dn = _get_zone_dn(ldap, idnsname)
|
||||
# just check if zone exists for now
|
||||
ldap.get_entry(dn, [''])
|
||||
|
||||
# retrieve all subentries of zone - records
|
||||
try:
|
||||
entries = ldap.find_entries(None, [''], dn, ldap.SCOPE_ONELEVEL)
|
||||
except errors.NotFound:
|
||||
entries = tuple()
|
||||
|
||||
# kill'em all, records first
|
||||
for e in entries:
|
||||
ldap.delete_entry(e[0])
|
||||
ldap.delete_entry(dn)
|
||||
|
||||
# return something positive
|
||||
return True
|
||||
|
||||
def output_for_cli(self, textui, result, *args, **options):
|
||||
textui.print_name(self.name)
|
||||
textui.print_dashed('Deleted DNS zone "%s".' % args[0])
|
||||
|
||||
api.register(dns2_delete)
|
||||
|
||||
|
||||
class dns2_mod(crud.Update):
|
||||
"""
|
||||
Modify DNS zone/SOA record.
|
||||
"""
|
||||
|
||||
def execute(self, *args, **options):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
idnsname = args[0]
|
||||
|
||||
# build entry attributes, don't include idnsname!
|
||||
entry_attrs = self.args_options_2_entry(*tuple(), **options)
|
||||
|
||||
# build entry DN
|
||||
dn = _get_zone_dn(ldap, idnsname)
|
||||
|
||||
# update zone entry
|
||||
ldap.update_entry(dn, entry_attrs)
|
||||
|
||||
# get zone entry with modified + default attributes for output
|
||||
return ldap.get_entry(
|
||||
dn, (entry_attrs.keys() + _zone_default_attributes)
|
||||
)
|
||||
|
||||
def output_for_cli(self, textui, result, *args, **options):
|
||||
(dn, entry_attrs) = result
|
||||
idnsname = args[0]
|
||||
|
||||
textui.print_name(self.name)
|
||||
textui.print_attribute('dn', dn)
|
||||
textui.print_entry(entry_attrs)
|
||||
textui.print_dashed('Modified DNS zone "%s".' % idnsname)
|
||||
|
||||
api.register(dns2_mod)
|
||||
|
||||
|
||||
class dns2_find(crud.Search):
|
||||
"""
|
||||
Search for DNS zones/SOA records.
|
||||
"""
|
||||
|
||||
takes_options = (
|
||||
Flag('all',
|
||||
doc='retrieve all attributes',
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, term, **options):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
# build search filter
|
||||
filter = ldap.make_filter_from_attr('idnsName', term, exact=False)
|
||||
|
||||
# select attributes we want to retrieve
|
||||
if options['all']:
|
||||
attrs_list = ['*']
|
||||
else:
|
||||
attrs_list = _zone_default_attributes
|
||||
|
||||
# get matching entries
|
||||
try:
|
||||
entries = ldap.find_entries(
|
||||
filter, attrs_list, _zone_container_dn, ldap.SCOPE_ONELEVEL
|
||||
)
|
||||
except errors.NotFound:
|
||||
entries = tuple()
|
||||
|
||||
return entries
|
||||
|
||||
def output_for_cli(self, textui, result, term, **options):
|
||||
textui.print_name(self.name)
|
||||
for e in result:
|
||||
(dn, entry_attrs) = e
|
||||
textui.print_attribute('dn', dn)
|
||||
textui.print_entry(entry_attrs)
|
||||
textui.print_plain('')
|
||||
textui.print_count(
|
||||
len(result), '%i DNS zone matched.', '%i DNS zones matched.'
|
||||
)
|
||||
|
||||
api.register(dns2_find)
|
||||
|
||||
|
||||
class dns2_show(crud.Retrieve):
|
||||
"""
|
||||
Display DNS zone/SOA record.
|
||||
"""
|
||||
|
||||
takes_options = (
|
||||
Flag('all',
|
||||
doc='retrieve all attributes',
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, idnsname, **options):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
# build entry DN
|
||||
dn = _get_zone_dn(ldap, idnsname)
|
||||
|
||||
# select attributes we want to retrieve
|
||||
if options['all']:
|
||||
attrs_list = ['*']
|
||||
else:
|
||||
attrs_list = _zone_default_attributes
|
||||
|
||||
return ldap.get_entry(dn, attrs_list)
|
||||
|
||||
def output_for_cli(self, textui, result, *args, **options):
|
||||
(dn, entry_attrs) = result
|
||||
|
||||
textui.print_name(self.name)
|
||||
textui.print_attribute('dn', dn)
|
||||
textui.print_entry(entry_attrs)
|
||||
|
||||
api.register(dns2_show)
|
||||
|
||||
|
||||
class dns2_enable(Command):
|
||||
"""
|
||||
Activate DNS zone.
|
||||
"""
|
||||
|
||||
takes_args = (
|
||||
Str('zone',
|
||||
cli_name='zone',
|
||||
doc='zone name',
|
||||
normalizer=lambda value: value.lower(),
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, zone):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
# build entry DN
|
||||
dn = _get_zone_dn(ldap, zone)
|
||||
|
||||
# activate!
|
||||
try:
|
||||
ldap.update_entry(dn, {'idnszoneactive': True})
|
||||
except errors.EmptyModlist:
|
||||
pass
|
||||
|
||||
# return something positive
|
||||
return True
|
||||
|
||||
def output_for_cli(self, textui, result, zone):
|
||||
textui.print_name(self.name)
|
||||
textui.print_dashed('Activated DNS zone "%s".' % zone)
|
||||
|
||||
api.register(dns2_enable)
|
||||
|
||||
|
||||
class dns2_disable(Command):
|
||||
"""
|
||||
Deactivate DNS zone.
|
||||
"""
|
||||
|
||||
takes_args = (
|
||||
Str('zone',
|
||||
cli_name='zone',
|
||||
doc='zone name',
|
||||
normalizer=lambda value: value.lower(),
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, zone):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
# build entry DN
|
||||
dn = _get_zone_dn(ldap, zone)
|
||||
|
||||
# deactivate!
|
||||
try:
|
||||
ldap.update_entry(dn, {'idnszoneactive': False})
|
||||
except errors.EmptyModlist:
|
||||
pass
|
||||
|
||||
# return something positive
|
||||
return True
|
||||
|
||||
def output_for_cli(self, textui, result, zone):
|
||||
textui.print_name(self.name)
|
||||
textui.print_dashed('Deactivated DNS zone "%s".' % zone)
|
||||
|
||||
api.register(dns2_disable)
|
||||
|
||||
|
||||
class dns2_add_rr(Command):
|
||||
"""
|
||||
Add new DNS resource record.
|
||||
"""
|
||||
|
||||
takes_args = (
|
||||
Str('zone',
|
||||
cli_name='zone',
|
||||
doc='zone name',
|
||||
normalizer=lambda value: value.lower(),
|
||||
),
|
||||
Str('idnsname',
|
||||
cli_name='resource',
|
||||
doc='resource name',
|
||||
default_from=lambda zone: zone.lower(),
|
||||
attribute=True,
|
||||
),
|
||||
StrEnum('type',
|
||||
cli_name='type',
|
||||
doc='record type',
|
||||
values=_record_types,
|
||||
),
|
||||
Str('data',
|
||||
cli_name='data',
|
||||
doc='type-specific data',
|
||||
),
|
||||
)
|
||||
|
||||
takes_options = (
|
||||
Int('dnsttl?',
|
||||
cli_name='ttl',
|
||||
doc='time to live',
|
||||
attribute=True,
|
||||
),
|
||||
StrEnum('dnsclass?',
|
||||
cli_name='class',
|
||||
doc='class',
|
||||
values=_record_classes,
|
||||
attribute=True,
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, zone, idnsname, type, data, **options):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
attr = '%srecord' % type
|
||||
|
||||
# build entry DN
|
||||
dn = _get_record_dn(ldap, zone, idnsname)
|
||||
|
||||
# get resource entry where to store the new record
|
||||
try:
|
||||
(dn, entry_attrs) = ldap.get_entry(dn, [attr])
|
||||
except errors.NotFound:
|
||||
if idnsname != '@' and idnsname != zone:
|
||||
# resource entry doesn't exist, check if zone exists
|
||||
zone_dn = _get_zone_dn(ldap, zone)
|
||||
ldap.get_entry(zone_dn, [''])
|
||||
# it does, create new resource entry
|
||||
|
||||
# build entry attributes
|
||||
entry_attrs = self.args_options_2_entry(
|
||||
(idnsname, ), **options
|
||||
)
|
||||
|
||||
# fill in required attributes
|
||||
entry_attrs['objectclass'] = ['top', 'idnsRecord']
|
||||
|
||||
# fill in the record
|
||||
entry_attrs[attr] = data
|
||||
|
||||
# create the entry
|
||||
ldap.add_entry(dn, entry_attrs)
|
||||
|
||||
# get entry with created attributes for output
|
||||
return ldap.get_entry(dn, entry_attrs.keys())
|
||||
|
||||
# zone doesn't exist
|
||||
raise
|
||||
# resource entry already exists, create a modlist for the new record
|
||||
|
||||
# convert entry_attrs keys to lowercase
|
||||
#entry_attrs = dict(
|
||||
# (k.lower(), v) for (k, v) in entry_attrs.iteritems()
|
||||
#)
|
||||
|
||||
# get new value for record attribute
|
||||
attr_value = entry_attrs.get(attr, [])
|
||||
attr_value.append(data)
|
||||
|
||||
ldap.update_entry(dn, {attr: attr_value})
|
||||
# get entry with updated attribute for output
|
||||
return ldap.get_entry(dn, ['idnsname', attr])
|
||||
|
||||
def output_for_cli(self, textui, result, zone, idnsname, type, data,
|
||||
**options):
|
||||
(dn, entry_attrs) = result
|
||||
output = '"%s %s %s" to zone "%s"' % (
|
||||
idnsname, type, data, zone,
|
||||
)
|
||||
|
||||
textui.print_name(self.name)
|
||||
textui.print_attribute('dn', dn)
|
||||
textui.print_entry(entry_attrs)
|
||||
textui.print_dashed('Added DNS resource record %s.' % output)
|
||||
|
||||
api.register(dns2_add_rr)
|
||||
|
||||
|
||||
class dns2_del_rr(Command):
|
||||
"""
|
||||
Delete DNS resource record.
|
||||
"""
|
||||
|
||||
takes_args = (
|
||||
Str('zone',
|
||||
cli_name='zone',
|
||||
doc='zone name',
|
||||
normalizer=lambda value: value.lower(),
|
||||
),
|
||||
Str('idnsname',
|
||||
cli_name='resource',
|
||||
doc='resource name',
|
||||
default_from=lambda zone: zone.lower(),
|
||||
attribute=True,
|
||||
),
|
||||
StrEnum('type',
|
||||
cli_name='type',
|
||||
doc='record type',
|
||||
values=_record_types,
|
||||
),
|
||||
Str('data',
|
||||
cli_name='data',
|
||||
doc='type-specific data',
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, zone, idnsname, type, data):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
attr = '%srecord' % type
|
||||
|
||||
# build entry DN
|
||||
dn = _get_record_dn(ldap, zone, idnsname)
|
||||
|
||||
# get resource entry with the record we're trying to delete
|
||||
(dn, entry_attrs) = ldap.get_entry(dn)
|
||||
|
||||
# convert entry_attrs keys to lowercase
|
||||
entry_attrs = dict(
|
||||
(k.lower(), v) for (k, v) in entry_attrs.iteritems()
|
||||
)
|
||||
|
||||
# get new value for record attribute
|
||||
attr_value = entry_attrs.get(attr.lower(), [])
|
||||
try:
|
||||
attr_value.remove(data)
|
||||
except ValueError:
|
||||
raise errors.NotFound(message=u'resource record not found')
|
||||
|
||||
# check if it's worth to keep this entry in LDAP
|
||||
if 'idnsZone' not in entry_attrs['objectclass']:
|
||||
# get a list of all meaningful record attributes
|
||||
record_attrs = []
|
||||
for (k, v) in entry_attrs.iteritems():
|
||||
if k.endswith('record') and v:
|
||||
record_attrs.append(k)
|
||||
# check if the list is empty
|
||||
if not record_attrs:
|
||||
# it's not
|
||||
ldap.delete_entry(dn)
|
||||
return True
|
||||
|
||||
ldap.update_entry(dn, {attr: attr_value})
|
||||
# get entry with updated attribute for output
|
||||
return ldap.get_entry(dn, ['idnsname', attr])
|
||||
|
||||
def output_for_cli(self, textui, result, zone, idnsname, type, data):
|
||||
output = '"%s %s %s" from zone "%s"' % (
|
||||
idnsname, type, data, zone,
|
||||
)
|
||||
|
||||
textui.print_name(self.name)
|
||||
if not isinstance(result, bool):
|
||||
(dn, entry_attrs) = result
|
||||
textui.print_attribute('dn', dn)
|
||||
textui.print_entry(entry_attrs)
|
||||
textui.print_dashed('Deleted DNS resource record %s' % output)
|
||||
|
||||
api.register(dns2_del_rr)
|
||||
|
||||
|
||||
class dns2_find_rr(Command):
|
||||
"""
|
||||
Search for DNS resource records.
|
||||
"""
|
||||
|
||||
takes_args = (
|
||||
Str('zone',
|
||||
cli_name='zone',
|
||||
doc='zone name',
|
||||
normalizer=lambda value: value.lower(),
|
||||
),
|
||||
Str('criteria?',
|
||||
cli_name='criteria',
|
||||
doc='search criteria',
|
||||
),
|
||||
)
|
||||
|
||||
takes_options = (
|
||||
Str('idnsname?',
|
||||
cli_name='resource',
|
||||
doc='resource name',
|
||||
default_from=lambda zone: zone.lower(),
|
||||
),
|
||||
StrEnum('type?',
|
||||
cli_name='type',
|
||||
doc='record type',
|
||||
values=_record_types,
|
||||
),
|
||||
Str('data?',
|
||||
cli_name='data',
|
||||
doc='type-specific data',
|
||||
),
|
||||
Flag('all',
|
||||
doc='retrieve all attributes',
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, zone, term, **options):
|
||||
assert self.api.env.use_ldap2, 'use_ldap2 is False'
|
||||
ldap = self.api.Backend.ldap2
|
||||
if 'type' in options:
|
||||
attr = '%srecord' % options['type']
|
||||
else:
|
||||
attr = None
|
||||
|
||||
# build base dn for search
|
||||
base_dn = _get_zone_dn(ldap, zone)
|
||||
|
||||
# build search keywords
|
||||
search_kw = {}
|
||||
if 'data' in options:
|
||||
if attr is not None:
|
||||
# user is looking for a certain record type
|
||||
search_kw[attr] = options['data']
|
||||
else:
|
||||
# search in all record types
|
||||
for a in _record_default_attributes:
|
||||
search_kw[a] = term
|
||||
if 'idnsname' in options:
|
||||
idnsname = options['idnsname']
|
||||
if idnsname == '@':
|
||||
search_kw['idnsname'] = zone
|
||||
else:
|
||||
search_kw['idnsname'] = idnsname
|
||||
|
||||
# build search filter
|
||||
filter = ldap.make_filter(search_kw, rules=ldap.MATCH_ALL)
|
||||
if term:
|
||||
search_kw = {}
|
||||
for a in _record_default_attributes:
|
||||
search_kw[a] = term
|
||||
term_filter = ldap.make_filter(search_kw, exact=False)
|
||||
filter = ldap.combine_filters((filter, term_filter), ldap.MATCH_ALL)
|
||||
self.log.info(filter)
|
||||
|
||||
# select attributes we want to retrieve
|
||||
if options['all']:
|
||||
attrs_list = ['*']
|
||||
elif attr is not None:
|
||||
attrs_list = [attr]
|
||||
else:
|
||||
attrs_list = _record_default_attributes
|
||||
|
||||
# get matching entries
|
||||
try:
|
||||
entries = ldap.find_entries(filter, attrs_list, base_dn)
|
||||
except errors.NotFound:
|
||||
entries = tuple()
|
||||
|
||||
# if the user is looking for a certain record type, don't display
|
||||
# entries that do not contain it
|
||||
if attr is not None:
|
||||
related_entries = []
|
||||
for e in entries:
|
||||
entry_attrs = e[1]
|
||||
if attr in entry_attrs:
|
||||
related_entries.append(e)
|
||||
entries = related_entries
|
||||
|
||||
return entries
|
||||
|
||||
def output_for_cli(self, textui, result, zone, term, **options):
|
||||
textui.print_name(self.name)
|
||||
for e in result:
|
||||
(dn, entry_attrs) = e
|
||||
textui.print_attribute('dn', dn)
|
||||
textui.print_entry(entry_attrs)
|
||||
textui.print_plain('')
|
||||
textui.print_count(
|
||||
len(result), '%i DNS resource record matched.',
|
||||
'%i DNS resource records matched.'
|
||||
)
|
||||
|
||||
api.register(dns2_find_rr)
|
||||
|
||||
|
||||
class dns2_show_rr(Command):
|
||||
"""
|
||||
Show existing DNS resource records.
|
||||
"""
|
||||
|
||||
takes_args = (
|
||||
Str('zone',
|
||||
cli_name='zone',
|
||||
doc='zone name',
|
||||
normalizer=lambda value: value.lower(),
|
||||
),
|
||||
Str('idnsname',
|
||||
cli_name='resource',
|
||||
doc='resource name',
|
||||
normalizer=lambda value: value.lower(),
|
||||
),
|
||||
)
|
||||
|
||||
takes_options = (
|
||||
Flag('all',
|
||||
doc='retrieve all attributes',
|
||||
),
|
||||
)
|
||||
|
||||
def execute(self, zone, idnsname, **options):
|
||||
# shows all records associated with resource
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
# build entry DN
|
||||
dn = _get_record_dn(ldap, zone, idnsname)
|
||||
|
||||
# select attributes we want to retrieve
|
||||
if options['all']:
|
||||
attrs_list = ['*']
|
||||
else:
|
||||
attrs_list = _record_default_attributes
|
||||
|
||||
return ldap.get_entry(dn, attrs_list)
|
||||
|
||||
def output_for_cli(self, textui, result, zone, idnsname, **options):
|
||||
(dn, entry_attrs) = result
|
||||
|
||||
textui.print_name(self.name)
|
||||
textui.print_attribute('dn', dn)
|
||||
textui.print_entry(entry_attrs)
|
||||
|
||||
api.register(dns2_show_rr)
|
||||
|
Reference in New Issue
Block a user