Skip to content

Commit

Permalink
Merge "Use proper repr/type of uuid and ctime in stale zk lock checks."
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and opencontrail-ci-admin committed Nov 9, 2015
2 parents c94dfd2 + 8f50ab9 commit a74e059
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 20 deletions.
46 changes: 46 additions & 0 deletions src/config/api-server/tests/test_crud_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,52 @@ def stub(*args, **kwargs):

self._create_test_object()
# end test_stale_fq_name_lock_removed_on_partial_delete

def test_stale_fq_name_lock_removed_coverage(self):
vn_obj = VirtualNetwork('vn-%s' %(self.id()))
vn_obj.__dict__['id_perms'] = {}
vn_UUID = uuid.uuid4()

# create zk-node
self._api_server._db_conn.set_uuid(
obj_type=vn_obj._type,
obj_dict=vn_obj.__dict__,
id=vn_UUID,
do_lock=True)

# assert we hit the zk-node on re-create
with ExpectedException(ResourceExistsError, ".*at zookeeper.*"):
self._api_server._db_conn.set_uuid(
obj_type=vn_obj._type,
obj_dict=vn_obj.__dict__,
id=vn_UUID,
do_lock=True)

# create entry in cassandra too and assert
# not a stale lock on re-create
uuid_cf = test_common.CassandraCFs.get_cf('obj_uuid_table')
with uuid_cf.patch_row(str(vn_UUID),
new_columns={'fq_name':json.dumps(vn_obj.fq_name),
'type':json.dumps(vn_obj._type)}):
with ExpectedException(ResourceExistsError, ".*at cassandra.*"):
self._api_server._db_conn.set_uuid(
obj_type=vn_obj._type,
obj_dict=vn_obj.__dict__,
id=vn_UUID,
do_lock=True)

self._api_server._db_conn._cassandra_db.cache_uuid_to_fq_name_del(
str(vn_UUID))

# sleep and re-create and now it should be fine
gevent.sleep(float(self.STALE_LOCK_SECS))
self._api_server._db_conn.set_uuid(
obj_type=vn_obj._type,
obj_dict=vn_obj.__dict__,
id=vn_UUID,
do_lock=True)
# end test_stale_fq_name_lock_removed_coverage

# end TestStaleLockRemoval

class TestIfmapHealthCheck(test_case.ApiServerTestCase):
Expand Down
12 changes: 8 additions & 4 deletions src/config/api-server/vnc_cfg_ifmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,10 @@ def get_fq_name_to_uuid_mapping(self, obj_type, fq_name):
fq_name_str = ':'.join(fq_name)
zk_path = self._fq_name_to_uuid_path+'/%s:%s' %(obj_type.replace('-', '_'),
fq_name_str)
return self._zk_client.read_node(zk_path, include_timestamp=True)
obj_uuid, znode_stat = self._zk_client.read_node(
zk_path, include_timestamp=True)

return obj_uuid, znode_stat.ctime
# end get_fq_name_to_uuid_mapping

def delete_fq_name_to_uuid_mapping(self, obj_type, fq_name):
Expand Down Expand Up @@ -1410,12 +1413,13 @@ def set_uuid(self, obj_type, obj_dict, id, do_lock=True):
str(id))
except ResourceExistsError as rexist:
# see if stale and if so delete stale
_, epoch_msecs = self._zk_db.get_fq_name_to_uuid_mapping(
_, ctime = self._zk_db.get_fq_name_to_uuid_mapping(
obj_type, fq_name)
epoch_msecs = ctime
try:
self._cassandra_db.uuid_to_fq_name(id)
self._cassandra_db.uuid_to_fq_name(str(id))
# not stale
raise
raise ResourceExistsError(fq_name, str(id), 'cassandra')
except NoIdError:
lock_msecs = float(time.time()*1000 - epoch_msecs)
stale_msecs_cfg = 1000 * float(
Expand Down
12 changes: 9 additions & 3 deletions src/config/common/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,20 @@ def __str__(self):
# end class MaxRabbitPendingError

class ResourceExistsError(VncError):
def __init__(self, eexists_fq_name, eexists_id):
def __init__(self, eexists_fq_name, eexists_id, location=None):
self._eexists_fq_name = eexists_fq_name
self._eexists_id = eexists_id
self._eexists_location = location
# end __init__

def __str__(self):
return 'FQ Name: %s exists already with ID: %s' \
% (self._eexists_fq_name, self._eexists_id)
if self._eexists_location:
return 'FQ Name: %s exists already with ID: %s at %s' \
% (self._eexists_fq_name, self._eexists_id,
self._eexists_location)
else:
return 'FQ Name: %s exists already with ID: %s' \
% (self._eexists_fq_name, self._eexists_id)
# end __str__
# end class ResourceExistsError

Expand Down
40 changes: 28 additions & 12 deletions src/config/common/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,16 +267,25 @@ def send(self):

@contextlib.contextmanager
def patch_row(self, key, new_columns=None):
orig_cols = self._rows[key]
if new_columns is None:
# simulates absence of key in cf
del self._rows[key]
else:
self._rows[key] = new_columns
if key in self._rows:
row_existed = True
orig_cols = self._rows[key]
if new_columns is None:
# simulates absence of key in cf
del self._rows[key]
else:
self._rows[key] = new_columns
else: # row didn't exist, create one
row_existed = False
self.insert(key, new_columns)

try:
yield
finally:
self._rows[key] = orig_cols
if row_existed:
self._rows[key] = orig_cols
else:
del self._rows[key]
#end patch_row
# end class FakeCF

Expand Down Expand Up @@ -1150,6 +1159,11 @@ def Fake_uuid_to_time(time_uuid_in_db):
return ts
# end of Fake_uuid_to_time

class ZnodeStat(object):
def __init__(self, ctime):
self.ctime = ctime
# end ZnodeStat

class FakeKazooClient(object):
class Election(object):
__init__ = stub
Expand All @@ -1165,8 +1179,9 @@ def __init__(self, *args, **kwargs):

def create(self, path, value='', *args, **kwargs):
if path in self._values:
raise ResourceExistsError(path, str(self._values[path]))
self._values[path] = (value, time.time()*1000)
raise ResourceExistsError(
path, str(self._values[path][0]), 'zookeeper')
self._values[path] = (value, ZnodeStat(time.time()*1000))
# end create

def get(self, path):
Expand Down Expand Up @@ -1203,7 +1218,7 @@ def alloc_from(self, path, max_id):
def alloc_from_str(self, path, value=''):
self._count = self._count + 1
zk_val = "%(#)010d" % {'#': self._count}
self._values[path + zk_val] = (value, time.time()*1000)
self._values[path + zk_val] = (value, ZnodeStat(time.time()*1000))
return zk_val
# end alloc_from_str

Expand Down Expand Up @@ -1236,8 +1251,9 @@ def read_node(self, path, include_timestamp=False):

def create_node(self, path, value=''):
if path in self._values:
raise ResourceExistsError(path, str(self._values[path]))
self._values[path] = (value, time.time()*1000)
raise ResourceExistsError(
path, str(self._values[path][0], 'zookeeper'))
self._values[path] = (value, ZnodeStat(time.time()*1000))
# end create_node

def delete_node(self, path, recursive=False):
Expand Down
2 changes: 1 addition & 1 deletion src/config/common/zkclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def create_node(self, path, value=None):
current_value = self.read_node(path)
if current_value == value:
return True;
raise ResourceExistsError(path, str(current_value))
raise ResourceExistsError(path, str(current_value), 'zookeeper')
# end create_node

def delete_node(self, path, recursive=False):
Expand Down

0 comments on commit a74e059

Please sign in to comment.