Restore ACI when aci_mod fails

aci_mod command is composed of 2 ACI commands: aci_del which
deletes the old ACI and aci_add which adds the new modified ACI.
However, if aci_add command fails then both new and the old ACI
are lost. Old ACI must be restored in this case.

https://fedorahosted.org/freeipa/ticket/2013
https://fedorahosted.org/freeipa/ticket/2014
This commit is contained in:
Martin Kosek 2012-01-06 13:58:01 +01:00
parent 86f908a0e4
commit d50618f6bd
2 changed files with 43 additions and 4 deletions

View File

@ -117,6 +117,7 @@ must include all existing attributes as well. When doing an aci-mod the
targetattr REPLACES the current attributes, it does not add to them. targetattr REPLACES the current attributes, it does not add to them.
""" """
from copy import deepcopy
from ipalib import api, crud, errors from ipalib import api, crud, errors
from ipalib import Object, Command from ipalib import Object, Command
@ -614,14 +615,18 @@ class aci_mod(crud.Update):
# The strategy here is to convert the ACI we're updating back into # The strategy here is to convert the ACI we're updating back into
# a series of keywords. Then we replace any keywords that have been # a series of keywords. Then we replace any keywords that have been
# updated and convert that back into an ACI and write it out. # updated and convert that back into an ACI and write it out.
newkw = _aci_to_kw(ldap, aci) oldkw = _aci_to_kw(ldap, aci)
newkw = deepcopy(oldkw)
if 'selfaci' in newkw and newkw['selfaci'] == True: if 'selfaci' in newkw and newkw['selfaci'] == True:
# selfaci is set in aci_to_kw to True only if the target is self # selfaci is set in aci_to_kw to True only if the target is self
kw['selfaci'] = True kw['selfaci'] = True
for k in kw.keys(): for k in kw.keys():
newkw[k] = kw[k] newkw[k] = kw[k]
if 'aciname' in newkw: for acikw in (oldkw, newkw):
del newkw['aciname'] try:
del acikw['aciname']
except KeyError:
pass
# _make_aci is what is run in aci_add and validates the input. # _make_aci is what is run in aci_add and validates the input.
# Do this before we delete the existing ACI. # Do this before we delete the existing ACI.
@ -631,7 +636,16 @@ class aci_mod(crud.Update):
self.api.Command['aci_del'](aciname, **kw) self.api.Command['aci_del'](aciname, **kw)
result = self.api.Command['aci_add'](aciname, **newkw)['result'] try:
result = self.api.Command['aci_add'](aciname, **newkw)['result']
except Exception, e:
# ACI could not be added, try to restore the old deleted ACI and
# report the ADD error back to user
try:
self.api.Command['aci_add'](aciname, **oldkw)
except:
pass
raise e
if kw.get('raw', False): if kw.get('raw', False):
result = dict(aci=unicode(newaci)) result = dict(aci=unicode(newaci))

View File

@ -172,6 +172,31 @@ class test_selfservice(Declarative):
), ),
dict(
desc='Try to update %r with empty permissions' % selfservice1,
command=(
'selfservice_mod', [selfservice1], dict(permissions=None)
),
expected=errors.RequirementError(name='permissions'),
),
dict(
desc='Retrieve %r to verify invalid update' % selfservice1,
command=('selfservice_show', [selfservice1], {}),
expected=dict(
value=selfservice1,
summary=None,
result={
'attrs': [u'street', u'c', u'l', u'st', u'postalcode'],
'permissions': [u'read'],
'selfaci': True,
'aciname': selfservice1,
},
),
),
dict( dict(
desc='Delete %r' % selfservice1, desc='Delete %r' % selfservice1,
command=('selfservice_del', [selfservice1], {}), command=('selfservice_del', [selfservice1], {}),