From 15abfcf0f77664f426ba50ebf20e0f6c2a6f8275 Mon Sep 17 00:00:00 2001 From: Martin Basti Date: Jun 03 2016 13:58:21 +0000 Subject: DNS Locations: extend server-* command with locations Server find, server show, server mod should work with IPA locations. https://fedorahosted.org/freeipa/ticket/2008 Reviewed-By: Petr Spacek Reviewed-By: Jan Cholasta --- diff --git a/API.txt b/API.txt index bfdb904..9912750 100644 --- a/API.txt +++ b/API.txt @@ -4006,14 +4006,16 @@ output: Output('result', type=[]) output: Output('summary', type=[, ]) output: ListOfPrimaryKeys('value') command: server_find -args: 1,12,4 +args: 1,14,4 arg: Str('criteria?') option: Flag('all', autofill=True, cli_name='all', default=False) option: Str('cn?', autofill=False, cli_name='name') +option: DNSNameParam('in_location*', cli_name='in_locations') option: Int('ipamaxdomainlevel?', autofill=False, cli_name='maxlevel') option: Int('ipamindomainlevel?', autofill=False, cli_name='minlevel') option: Flag('no_members', autofill=True, default=True) option: Str('no_topologysuffix*', cli_name='no_topologysuffixes') +option: DNSNameParam('not_in_location*', cli_name='not_in_locations') option: Flag('pkey_only?', autofill=True, default=False) option: Flag('raw', autofill=True, cli_name='raw', default=False) option: Int('sizelimit?', autofill=False) @@ -4024,6 +4026,22 @@ output: Output('count', type=[]) output: ListOfEntries('result') output: Output('summary', type=[, ]) output: Output('truncated', type=[]) +command: server_mod +args: 1,10,3 +arg: Str('cn', cli_name='name') +option: Str('addattr*', cli_name='addattr') +option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('delattr*', cli_name='delattr') +option: DNSNameParam('ipalocation_location?', autofill=False, cli_name='location') +option: Int('ipalocationweight?', autofill=False, cli_name='location_weight') +option: Flag('no_members', autofill=True, default=False) +option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Flag('rights', autofill=True, default=False) +option: Str('setattr*', cli_name='setattr') +option: Str('version?') +output: Entry('result') +output: Output('summary', type=[, ]) +output: PrimaryKey('value') command: server_show args: 1,5,3 arg: Str('cn', cli_name='name') diff --git a/VERSION b/VERSION index de7ad35..70bd7c9 100644 --- a/VERSION +++ b/VERSION @@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=174 -# Last change: mbasti - location-* commands +IPA_API_VERSION_MINOR=175 +# Last change: mbasti - server-mod: locations added diff --git a/ipaserver/plugins/location.py b/ipaserver/plugins/location.py index 7c0aab1..35435f4 100644 --- a/ipaserver/plugins/location.py +++ b/ipaserver/plugins/location.py @@ -106,7 +106,7 @@ class location(LDAPObject): ) def get_dn(self, *keys, **options): - loc = keys[-1] + loc = keys[0] assert isinstance(loc, DNSName) loc_a = loc.ToASCII() diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py index 6faaf8e..3192a58 100644 --- a/ipaserver/plugins/server.py +++ b/ipaserver/plugins/server.py @@ -6,16 +6,21 @@ import dbus import dbus.mainloop.glib from ipalib import api, crud, errors, messages -from ipalib import Int, Str +from ipalib import Int, Str, DNSNameParam from ipalib.plugable import Registry from .baseldap import ( LDAPSearch, LDAPRetrieve, LDAPDelete, - LDAPObject) + LDAPObject, + LDAPUpdate, +) from ipalib.request import context from ipalib import _, ngettext from ipalib import output +from ipapython.dn import DN +from ipapython.dnsutil import DNSName + __doc__ = _(""" IPA servers @@ -43,18 +48,21 @@ class server(LDAPObject): object_name = _('server') object_name_plural = _('servers') object_class = ['top'] + possible_objectclasses = ['ipaLocationMember'] search_attributes = ['cn'] default_attributes = [ 'cn', 'iparepltopomanagedsuffix', 'ipamindomainlevel', - 'ipamaxdomainlevel' + 'ipamaxdomainlevel', 'ipalocation', 'ipalocationweight' ] label = _('IPA Servers') label_singular = _('IPA Server') attribute_members = { 'iparepltopomanagedsuffix': ['topologysuffix'], + 'ipalocation': ['location'], } relationships = { 'iparepltopomanagedsuffix': ('Managed', '', 'no_'), + 'ipalocation': ('IPA', 'in_', 'not_in_'), } takes_params = ( Str( @@ -87,6 +95,23 @@ class server(LDAPObject): doc=_('Maximum domain level'), flags={'no_create', 'no_update'}, ), + DNSNameParam( + 'ipalocation_location?', + cli_name='location', + label=_('Location'), + doc=_('Server location'), + only_relative=True, + flags={'no_search'}, + ), + Int( + 'ipalocationweight?', + cli_name='location_weight', + label=_('Location weight'), + doc=_('Location weight for server'), + minvalue=0, + maxvalue=65535, + flags={'no_search'}, + ) ) def _get_suffixes(self): @@ -105,6 +130,67 @@ class server(LDAPObject): suffixes.get(m, m) for m in entry['iparepltopomanagedsuffix'] ] + def normalize_location(self, kw, **options): + """ + Return the DN of location + """ + if 'ipalocation_location' in kw: + location = kw.pop('ipalocation_location') + kw['ipalocation'] = ( + [self.api.Object.location.get_dn(location)] + if location is not None else location + ) + + def convert_location(self, entry_attrs, **options): + """ + Return a location name from DN + """ + if options.get('raw'): + return + + converted_locations = [ + DNSName(location_dn['idnsname']) for + location_dn in entry_attrs.pop('ipalocation', []) + ] + + if converted_locations: + entry_attrs['ipalocation_location'] = converted_locations + + +@register() +class server_mod(LDAPUpdate): + __doc__ = _('Modify information about an IPA server.') + + msg_summary = _('Modified IPA server "%(value)s"') + + def args_options_2_entry(self, *args, **options): + kw = super(server_mod, self).args_options_2_entry( + *args, **options) + self.obj.normalize_location(kw, **options) + return kw + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + assert isinstance(dn, DN) + + if entry_attrs.get('ipalocation'): + if not ldap.entry_exists(entry_attrs['ipalocation'][0]): + self.api.Object.location.handle_not_found( + options['ipalocation_location']) + + if 'ipalocation' or 'ipalocationweight' in entry_attrs: + server_entry = ldap.get_entry(dn, ['objectclass']) + + # we need to extend object with ipaLocationMember objectclass + entry_attrs['objectclass'] = ( + server_entry['objectclass'] + ['ipalocationmember'] + ) + + return dn + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + assert isinstance(dn, DN) + self.obj.convert_location(entry_attrs, **options) + return dn @register() class server_find(LDAPSearch): @@ -114,7 +200,13 @@ class server_find(LDAPSearch): '%(count)d IPA server matched', '%(count)d IPA servers matched', 0 ) - member_attributes = ['iparepltopomanagedsuffix'] + member_attributes = ['iparepltopomanagedsuffix', 'ipalocation'] + + def args_options_2_entry(self, *args, **options): + kw = super(server_find, self).args_options_2_entry( + *args, **options) + self.obj.normalize_location(kw, **options) + return kw def get_options(self): for option in super(server_find, self).get_options(): @@ -173,6 +265,8 @@ class server_find(LDAPSearch): for entry in entries: self.obj._apply_suffixes(entry, suffixes) + for entry in entries: + self.obj.convert_location(entry, **options) return truncated @@ -184,7 +278,7 @@ class server_show(LDAPRetrieve): if not options.get('raw', False): suffixes = self.obj._get_suffixes() self.obj._apply_suffixes(entry, suffixes) - + self.obj.convert_location(entry, **options) return dn