From 719bf0ce45a34de6b67bc073d9bac345770e6c2a Mon Sep 17 00:00:00 2001 From: Tomas Babej Date: Thu, 31 Jul 2014 14:09:05 +0200 Subject: idviews: Add ipa idview-apply and idview-unapply commands Part of: https://fedorahosted.org/freeipa/ticket/3979 --- API.txt | 19 +++++ ipalib/plugins/idviews.py | 179 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 195 insertions(+), 3 deletions(-) diff --git a/API.txt b/API.txt index 29f7faefe..08af899bd 100644 --- a/API.txt +++ b/API.txt @@ -2199,6 +2199,16 @@ option: Str('version?', exclude='webui') output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) output: Output('summary', (, ), None) output: PrimaryKey('value', None, None) +command: idview_apply +args: 1,3,4 +arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True) +option: Str('host*', cli_name='hosts') +option: Str('hostgroup*', cli_name='hostgroups') +option: Str('version?', exclude='webui') +output: Output('completed', , None) +output: Output('failed', , None) +output: Output('succeeded', , None) +output: Output('summary', (, ), None) command: idview_del args: 1,2,3 arg: Str('cn', attribute=True, cli_name='name', multivalue=True, primary_key=True, query=True, required=True) @@ -2247,6 +2257,15 @@ option: Str('version?', exclude='webui') output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) output: Output('summary', (, ), None) output: PrimaryKey('value', None, None) +command: idview_unapply +args: 0,3,4 +option: Str('host*', cli_name='hosts') +option: Str('hostgroup*', cli_name='hostgroups') +option: Str('version?', exclude='webui') +output: Output('completed', , None) +output: Output('failed', , None) +output: Output('succeeded', , None) +output: Output('summary', (, ), None) command: json_metadata args: 2,4,3 arg: Str('objname?') diff --git a/ipalib/plugins/idviews.py b/ipalib/plugins/idviews.py index e7a26dea2..c27a014cb 100644 --- a/ipalib/plugins/idviews.py +++ b/ipalib/plugins/idviews.py @@ -18,12 +18,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from ipalib.plugins.baseldap import (LDAPObject, LDAPCreate, +from ipalib.plugins.baseldap import (LDAPQuery, LDAPObject, LDAPCreate, LDAPDelete, LDAPUpdate, LDAPSearch, - LDAPRetrieve) -from ipalib import api, Str, Int, _, ngettext + LDAPRetrieve, global_output_params) +from ipalib.plugins.hostgroup import get_complete_hostgroup_member_list +from ipalib import api, Str, Int, _, ngettext, errors, output from ipalib.plugable import Registry +from ipapython.dn import DN __doc__ = _(""" ID views @@ -106,6 +108,177 @@ class idview_show(LDAPRetrieve): __doc__ = _('Display information about an ID view.') +@register() +class idview_apply(LDAPQuery): + __doc__ = _('Applies ID view to specified hosts or current members of ' + 'specified hostgroups. If any other ID view is applied to ' + 'the host, it is overriden.') + + member_count_out = (_('ID view applied to %i host.'), + _('ID view applied to %i hosts.')) + + msg_summary = 'Applied ID view "%(value)s"' + + takes_options = ( + Str('host*', + cli_name='hosts', + doc=_('Hosts to apply the ID view to'), + label=_('hosts'), + ), + Str('hostgroup*', + cli_name='hostgroups', + doc=_('Hostgroups to whose hosts apply the ID view to. Please note ' + 'that view is not applied automatically to any hosts added ' + 'to the hostgroup after running the idview-apply command.'), + label=_('hostgroups'), + ), + ) + + has_output = ( + output.summary, + output.Output('succeeded', + type=dict, + doc=_('Hosts that this ID view was applied to.'), + ), + output.Output('failed', + type=dict, + doc=_('Hosts or hostgroups that this ID view could not be ' + 'applied to.'), + ), + output.Output('completed', + type=int, + doc=_('Number of hosts the ID view was applied to:'), + ), + ) + + has_output_params = global_output_params + + def execute(self, *keys, **options): + view = keys[-1] if keys else None + ldap = self.obj.backend + + # Test if idview actually exists, if it does not, NotFound is raised + if not options.get('clear_view', False): + view_dn = self.api.Object['idview'].get_dn_if_exists(view) + assert isinstance(view_dn, DN) + else: + # In case we are removing assigned view, we modify the host setting + # the ipaAssignedIDView to None + view_dn = None + + completed = 0 + succeeded = {'host': []} + failed = { + 'host': [], + 'hostgroup': [], + } + + # Generate a list of all hosts to apply the view to + hosts_to_apply = list(options.get('host', [])) + + for hostgroup in options.get('hostgroup', ()): + try: + hosts_to_apply += get_complete_hostgroup_member_list(hostgroup) + except errors.NotFound: + failed['hostgroup'].append((hostgroup, "not found")) + except errors.PublicError as e: + failed['hostgroup'].append((hostgroup, "%s : %s" % ( + e.__class__.__name__, str(e)))) + + for host in hosts_to_apply: + try: + host_dn = api.Object['host'].get_dn_if_exists(host) + + host_entry = ldap.get_entry(host_dn, + attrs_list=['ipaassignedidview']) + host_entry['ipaassignedidview'] = view_dn + + ldap.update_entry(host_entry) + + # If no exception was raised, view assigment went well + completed = completed + 1 + succeeded['host'].append(host) + except errors.EmptyModlist: + # If view was already applied, do not complain + pass + except errors.NotFound: + failed['host'].append((host, "not found")) + except errors.PublicError as e: + failed['host'].append((host, str(e))) + + # Wrap dictionary containing failures in another dictionary under key + # 'memberhost', since that is output parameter in global_output_params + # and thus we get nice output in the CLI + failed = {'memberhost': failed} + + # Sort the list of affected hosts + succeeded['host'].sort() + + # Note that we're returning the list of affected hosts even if they + # were passed via referencing a hostgroup. This is desired, since we + # want to stress the fact that view is applied on all the current + # member hosts of the hostgroup and not tied with the hostgroup itself. + + return dict( + summary=unicode(_(self.msg_summary % {'value': view})), + succeeded=succeeded, + completed=completed, + failed=failed, + ) + + +@register() +class idview_unapply(idview_apply): + __doc__ = _('Clears ID view from specified hosts or current members of ' + 'specified hostgroups.') + + member_count_out = (_('ID view cleared from %i host.'), + _('ID view cleared from %i hosts.')) + + msg_summary = 'Cleared ID views' + + takes_options = ( + Str('host*', + cli_name='hosts', + doc=_('Hosts to clear (any) ID view from.'), + label=_('hosts'), + ), + Str('hostgroup*', + cli_name='hostgroups', + doc=_('Hostgroups whose hosts should have ID views cleared. Note ' + 'that view is not cleared automatically from any host added ' + 'to the hostgroup after running idview-unapply command.'), + label=_('hostgroups'), + ), + ) + + has_output = ( + output.summary, + output.Output('succeeded', + type=dict, + doc=_('Hosts that ID view was cleared from.'), + ), + output.Output('failed', + type=dict, + doc=_('Hosts or hostgroups that ID view could not be cleared ' + 'from.'), + ), + output.Output('completed', + type=int, + doc=_('Number of hosts that had a ID view was unset:'), + ), + ) + + # Take no arguments, since ID View reference is not needed to clear + # the hosts + def get_args(self): + return () + + def execute(self, *keys, **options): + options['clear_view'] = True + return super(idview_unapply, self).execute(*keys, **options) + + @register() class idoverride(LDAPObject): """ -- cgit