tacker/tacker/sol_refactored/common/coordinate.py

103 lines
3.5 KiB
Python

# Copyright (C) 2021 Nippon Telegraph and Telephone Corporation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import functools
import inspect
from oslo_log import log as logging
from tacker.common import coordination
from tacker.sol_refactored.common import exceptions as sol_ex
LOG = logging.getLogger(__name__)
# NOTE: It is used to prevent operation for the same vnf instance
# from being processed at the same time. It can be applied between
# threads of a process and different processes (e.g. tacker-server
# and tacker-conductor) on a same host.
# Note that race condition of very short time is not considered.
def lock_vnf_instance(inst_arg, delay=False):
# NOTE: tacker-server issues RPC call to tacker-conductor
# (just) before the lock released. 'delay' is for tacker-conductor
# to be able to wait if it receives RPC call before tacker-server
# releases the lock.
def operation_lock(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
coord = coordination.COORDINATOR
# ensure coordination start
# NOTE: it is noop if already started.
coord.start()
sig = inspect.signature(func)
call_args = sig.bind(*args, **kwargs).arguments
inst_id = inst_arg.format(**call_args)
lock = coord.get_lock(inst_id)
blocking = False if not delay else 10
# NOTE: 'with lock' is not used since it can't handle
# lock failed exception well.
if not lock.acquire(blocking=blocking):
LOG.error("Locking vnfInstance %s failed.", inst_id)
raise sol_ex.OtherOperationInProgress(inst_id=inst_id)
try:
LOG.debug("vnfInstance %s locked.", inst_id)
return func(*args, **kwargs)
finally:
lock.release()
return wrapper
return operation_lock
def lock_resources(res_arg, delay=False):
def operation_lock(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
coord = coordination.COORDINATOR
# ensure coordination start
# NOTE: it is noop if already started.
coord.start()
sig = inspect.signature(func)
call_args = sig.bind(*args, **kwargs).arguments
res_id = res_arg.format(**call_args)
lock = coord.get_lock(res_id)
blocking = False if not delay else 10
# NOTE: 'with lock' is not used since it can't handle
# lock failed exception well.
if not lock.acquire(blocking=blocking):
LOG.debug("Locking resources %s failed.", res_id)
raise sol_ex.ResourcesOtherOperationInProgress(inst_id=res_id)
try:
LOG.debug("resources %s locked.", res_id)
return func(*args, **kwargs)
finally:
lock.release()
return wrapper
return operation_lock