summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Misnyovszki <amisnyov@redhat.com>2014-03-25 14:47:03 +0100
committerPetr Viktorin <pviktori@redhat.com>2014-04-09 13:45:32 +0200
commit8b91d9a6e87412c36d4f1191abf15fcda0815c60 (patch)
treee6af0204d22bd2c79ca8108434a14e5ea06a65b2
parentc58d6b2689acbfa36aec362b7de1ec7512d5f82a (diff)
downloadfreeipa-8b91d9a6e87412c36d4f1191abf15fcda0815c60.tar.gz
freeipa-8b91d9a6e87412c36d4f1191abf15fcda0815c60.tar.xz
freeipa-8b91d9a6e87412c36d4f1191abf15fcda0815c60.zip
automember rebuild nowait feature added
automember-rebuild uses asynchronous 389 task, and returned success even if the task didn't run. this patch fixes this issue adding a --nowait parameter to 'ipa automember-rebuild', defaulting to False, thus when the script runs without it, it waits for the 'nstaskexitcode' attribute, which means the task has finished. Old usage can be enabled using --nowait, and returns the DN of the task for further polling. New tests added also. https://fedorahosted.org/freeipa/ticket/4239 Reviewed-By: Petr Viktorin <pviktori@redhat.com>
-rw-r--r--API.txt7
-rw-r--r--VERSION4
-rw-r--r--ipalib/errors.py16
-rw-r--r--ipalib/plugins/automember.py70
-rw-r--r--ipatests/test_xmlrpc/test_automember_plugin.py67
-rw-r--r--ipatests/test_xmlrpc/xmlrpc_test.py10
6 files changed, 149 insertions, 25 deletions
diff --git a/API.txt b/API.txt
index 14dde5683..a0285d494 100644
--- a/API.txt
+++ b/API.txt
@@ -201,12 +201,15 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Output('value', <type 'unicode'>, None)
command: automember_rebuild
-args: 0,4,3
+args: 0,7,3
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Str('hosts*')
+option: Flag('no_wait?', autofill=True, default=False)
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: StrEnum('type', cli_name='type', multivalue=False, required=False, values=(u'group', u'hostgroup'))
option: Str('users*')
option: Str('version?', exclude='webui')
-output: Output('result', <type 'bool'>, None)
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Output('value', <type 'unicode'>, None)
command: automember_remove_condition
diff --git a/VERSION b/VERSION
index 7c6722965..e787e3713 100644
--- a/VERSION
+++ b/VERSION
@@ -89,5 +89,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=81
-# Last change: amisnyov - user plugin extend
+IPA_API_VERSION_MINOR=82
+# Last change: amisnyov - automember nowait add
diff --git a/ipalib/errors.py b/ipalib/errors.py
index 311127f62..8ef35f590 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -1530,6 +1530,22 @@ class DNSDataMismatch(ExecutionError):
format = _('DNS check failed: Expected {%(expected)s} got {%(got)s}')
+class TaskTimeout(DatabaseError):
+ """
+ **4213** Raised when an LDAP task times out
+
+ For example:
+
+ >>> raise TaskTimeout()
+ Traceback (most recent call last):
+ ...
+ TaskTimeout: Automember LDAP task timeout, Task DN: ''
+ """
+
+ errno = 4213
+ format = _("%(task)s LDAP task timeout, Task DN: '%(task_dn)s'")
+
+
class CertificateError(ExecutionError):
"""
**4300** Base class for Certificate execution errors (*4300 - 4399*).
diff --git a/ipalib/plugins/automember.py b/ipalib/plugins/automember.py
index a12bfb525..ac6f66a7f 100644
--- a/ipalib/plugins/automember.py
+++ b/ipalib/plugins/automember.py
@@ -17,8 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import uuid
+import time
+
import ldap as _ldap
-from ipalib import api, errors, Str, StrEnum, _, ngettext
+
+from ipalib import api, errors, Str, StrEnum, DNParam, _, ngettext
from ipalib.plugins.baseldap import *
from ipalib.request import context
from ipapython.dn import DN
@@ -623,9 +626,21 @@ class automember_rebuild(Command):
label=_('Hosts'),
doc=_('Rebuild membership for specified hosts'),
),
+ Flag(
+ 'no_wait?',
+ default=False,
+ label=_('No wait'),
+ doc=_("Don't wait for rebuilding membership"),
+ ),
+ )
+ has_output = output.standard_entry
+ has_output_params = (
+ DNParam(
+ 'dn',
+ label=_('Task DN'),
+ doc=_('DN of the started task'),
+ ),
)
- has_output = output.standard_value
- msg_summary = _('Automember rebuild membership task completed')
def validate(self, **kw):
"""
@@ -693,20 +708,51 @@ class automember_rebuild(Command):
else:
search_filter = '(%s=*)' % obj.primary_key.name
+ task_dn = DN(
+ ('cn', cn),
+ ('cn', 'automember rebuild membership'),
+ ('cn', 'tasks'),
+ ('cn', 'config'))
+
entry = ldap.make_entry(
- DN(
- ('cn', cn),
- ('cn', 'automember rebuild membership'),
- ('cn', 'tasks'),
- ('cn', 'config'),
- ),
+ task_dn,
objectclass=['top', 'extensibleObject'],
cn=[cn],
basedn=[basedn],
filter=[search_filter],
- scope=['sub']
- )
+ scope=['sub'],
+ ttl=[3600])
ldap.add_entry(entry)
- return dict(result=True, value=u'')
+
+ summary = _('Automember rebuild membership task started')
+ result = {'dn': task_dn}
+
+ if not options.get('no_wait'):
+ summary = _('Automember rebuild membership task completed')
+ result = {}
+ start_time = time.time()
+
+ while True:
+ try:
+ task = ldap.get_entry(task_dn)
+ except errors.NotFound:
+ break
+
+ if 'nstaskexitcode' in task:
+ if str(task.single_value['nstaskexitcode']) == '0':
+ summary=task.single_value['nstaskstatus']
+ break
+ else:
+ raise errors.DatabaseError(
+ desc=task.single_value['nstaskstatus'],
+ info=_("Task DN = '%s'" % task_dn))
+ time.sleep(1)
+ if time.time() > (start_time + 60):
+ raise errors.TaskTimeout(task=_('Automember'), task_dn=task_dn)
+
+ return dict(
+ result=result,
+ summary=unicode(summary),
+ value=u'')
api.register(automember_rebuild)
diff --git a/ipatests/test_xmlrpc/test_automember_plugin.py b/ipatests/test_xmlrpc/test_automember_plugin.py
index 9453ebb5a..600d54890 100644
--- a/ipatests/test_xmlrpc/test_automember_plugin.py
+++ b/ipatests/test_xmlrpc/test_automember_plugin.py
@@ -24,7 +24,8 @@ Test the `ipalib/plugins/automember.py` module.
from ipalib import api, errors
from ipapython.dn import DN
from ipatests.test_xmlrpc import objectclasses
-from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
+from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid, \
+ fuzzy_automember_dn, fuzzy_automember_message
from ipatests.test_xmlrpc.test_user_plugin import get_user_result
@@ -242,8 +243,20 @@ class test_automember(Declarative):
command=('automember_rebuild', [], dict(type=u'hostgroup')),
expected=dict(
value=u'',
- summary=u'Automember rebuild membership task completed',
- result=True
+ summary=fuzzy_automember_message,
+ result=dict()
+ ),
+ ),
+
+ dict(
+ desc='Rebuild membership for hostgroups asynchronously',
+ command=('automember_rebuild', [], dict(type=u'hostgroup',no_wait=True)),
+ expected=dict(
+ value=u'',
+ summary=u'Automember rebuild membership task started',
+ result=dict(
+ dn=fuzzy_automember_dn
+ ),
),
),
@@ -349,8 +362,20 @@ class test_automember(Declarative):
command=('automember_rebuild', [], dict(hosts=fqdn1)),
expected=dict(
value=u'',
- summary=u'Automember rebuild membership task completed',
- result=True
+ summary=fuzzy_automember_message,
+ result=dict()
+ ),
+ ),
+
+ dict(
+ desc='Rebuild membership for host: %s asynchronously' % fqdn1,
+ command=('automember_rebuild', [], dict(hosts=fqdn1, no_wait=True)),
+ expected=dict(
+ value=u'',
+ summary=u'Automember rebuild membership task started',
+ result=dict(
+ dn=fuzzy_automember_dn
+ ),
),
),
@@ -519,8 +544,20 @@ class test_automember(Declarative):
command=('automember_rebuild', [], dict(type=u'group')),
expected=dict(
value=u'',
- summary=u'Automember rebuild membership task completed',
- result=True
+ summary=fuzzy_automember_message,
+ result=dict()
+ ),
+ ),
+
+ dict(
+ desc='Rebuild membership for groups asynchronously',
+ command=('automember_rebuild', [], dict(type=u'group', no_wait=True)),
+ expected=dict(
+ value=u'',
+ summary=u'Automember rebuild membership task started',
+ result=dict(
+ dn=fuzzy_automember_dn
+ ),
),
),
@@ -584,8 +621,20 @@ class test_automember(Declarative):
command=('automember_rebuild', [], dict(users=user1)),
expected=dict(
value=u'',
- summary=u'Automember rebuild membership task completed',
- result=True
+ summary=fuzzy_automember_message,
+ result=dict()
+ ),
+ ),
+
+ dict(
+ desc='Rebuild membership for user: %s asynchronously' % user1,
+ command=('automember_rebuild', [], dict(users=user1, no_wait=True)),
+ expected=dict(
+ value=u'',
+ summary=u'Automember rebuild membership task started',
+ result=dict(
+ dn=fuzzy_automember_dn
+ ),
),
),
diff --git a/ipatests/test_xmlrpc/xmlrpc_test.py b/ipatests/test_xmlrpc/xmlrpc_test.py
index 8f31a1ec0..a596cd69c 100644
--- a/ipatests/test_xmlrpc/xmlrpc_test.py
+++ b/ipatests/test_xmlrpc/xmlrpc_test.py
@@ -38,6 +38,16 @@ uuid_re = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
# Matches an ipauniqueid like u'784d85fd-eae7-11de-9d01-54520012478b'
fuzzy_uuid = Fuzzy('^%s$' % uuid_re)
+# Matches an automember task DN
+fuzzy_automember_dn = Fuzzy(
+ '^cn=%s,cn=automember rebuild membership,cn=tasks,cn=config$' % uuid_re
+)
+
+# Matches an automember task finish message
+fuzzy_automember_message = Fuzzy(
+ '^Automember rebuild task finished\. Processed \(\d+\) entries\.$'
+)
+
# Matches trusted domain GUID, like u'463bf2be-3456-4a57-979e-120304f2a0eb'
fuzzy_guid = fuzzy_uuid