diff --git a/src/vnsw/contrail-vrouter-api/contrail_vrouter_api/vrouter_api.py b/src/vnsw/contrail-vrouter-api/contrail_vrouter_api/vrouter_api.py index 5580f04d3e1..f5c891a4d62 100644 --- a/src/vnsw/contrail-vrouter-api/contrail_vrouter_api/vrouter_api.py +++ b/src/vnsw/contrail-vrouter-api/contrail_vrouter_api/vrouter_api.py @@ -9,7 +9,7 @@ class ContrailVRouterApi(object): - def __init__(self, server_port=9090, doconnect=False): + def __init__(self, server_port=9090, doconnect=False, semaphore=None): """ local variables: _client: current transport connection @@ -19,6 +19,7 @@ def __init__(self, server_port=9090, doconnect=False): self._client = None self._ports = {} self._connect = doconnect + self._semaphore = semaphore def _rpc_client_instance(self): """ Return an RPC client connection """ @@ -72,87 +73,98 @@ def add_port(self, vm_uuid_str, vif_uuid_str, interface_name, mac_address, dictionary since the vrouter agent may not be running at the moment or the RPC may fail. """ + try: + if self._semaphore: + self._semaphore.acquire() + vif_uuid = self._uuid_from_string(vif_uuid_str) + # ip_address and network_uuid are optional to this API but must + # be present in the message. For instance, when running in + # CloudStack/XenServer/XAPI these arguments are not known. + if 'ip_address' in kwargs: + ip_address = kwargs['ip_address'] + else: + ip_address = '0.0.0.0' + + if 'vn_id' in kwargs: + network_uuid = self._uuid_string_to_hex(kwargs['vn_id']) + else: + network_uuid = [0] * 16 + + # create port with mandatory arguments + data = ttypes.Port( + self._uuid_to_hex(vif_uuid), + self._uuid_string_to_hex(vm_uuid_str), + interface_name, + ip_address, + network_uuid, + mac_address) + + if 'display_name' in kwargs: + data.display_name = kwargs['display_name'] + if 'hostname' in kwargs: + data.hostname = kwargs['hostname'] + if 'vm_project_id' in kwargs: + data.vm_project_id = self._uuid_string_to_hex( + kwargs['vm_project_id']) + if ('port_type' in kwargs and + kwargs['port_type'] in ttypes.PortTypes._NAMES_TO_VALUES.keys()): + data.port_type = \ + ttypes.PortTypes._NAMES_TO_VALUES[kwargs['port_type']] + else: + data.port_type = ttypes.PortTypes.NameSpacePort + if 'ip6_address' in kwargs: + data.ip6_address = kwargs['ip6_address'] + + if 'vlan' in kwargs: + data.vlan_id = kwargs['vlan'] + + data.validate() - vif_uuid = self._uuid_from_string(vif_uuid_str) - # ip_address and network_uuid are optional to this API but must - # be present in the message. For instance, when running in - # CloudStack/XenServer/XAPI these arguments are not known. - if 'ip_address' in kwargs: - ip_address = kwargs['ip_address'] - else: - ip_address = '0.0.0.0' - - if 'vn_id' in kwargs: - network_uuid = self._uuid_string_to_hex(kwargs['vn_id']) - else: - network_uuid = [0] * 16 - - # create port with mandatory arguments - data = ttypes.Port( - self._uuid_to_hex(vif_uuid), - self._uuid_string_to_hex(vm_uuid_str), - interface_name, - ip_address, - network_uuid, - mac_address) - - if 'display_name' in kwargs: - data.display_name = kwargs['display_name'] - if 'hostname' in kwargs: - data.hostname = kwargs['hostname'] - if 'vm_project_id' in kwargs: - data.vm_project_id = self._uuid_string_to_hex( - kwargs['vm_project_id']) - if ('port_type' in kwargs and - kwargs['port_type'] in ttypes.PortTypes._NAMES_TO_VALUES.keys()): - data.port_type = \ - ttypes.PortTypes._NAMES_TO_VALUES[kwargs['port_type']] - else: - data.port_type = ttypes.PortTypes.NameSpacePort - if 'ip6_address' in kwargs: - data.ip6_address = kwargs['ip6_address'] - - if 'vlan' in kwargs: - data.vlan_id = kwargs['vlan'] - - data.validate() - - if self._client is None: - self._client = self._rpc_client_instance() + if self._client is None: + self._client = self._rpc_client_instance() - if self._client is None: - self._ports[vif_uuid] = data - return False + if self._client is None: + self._ports[vif_uuid] = data + return False - self._resynchronize() + self._resynchronize() - self._ports[vif_uuid] = data + self._ports[vif_uuid] = data - try: - result = self._client.AddPort([data]) - except: - self._client = None - raise - return result + try: + result = self._client.AddPort([data]) + except: + self._client = None + raise + return result + finally: + if self._semaphore: + self._semaphore.release() def delete_port(self, vif_uuid_str): """ Delete a port form the agent. The port is first removed from the internal _ports dictionary. """ - vif_uuid = self._uuid_from_string(vif_uuid_str) - self._ports.pop(vif_uuid, None) + try: + if self._semaphore: + self._semaphore.acquire() + vif_uuid = self._uuid_from_string(vif_uuid_str) + self._ports.pop(vif_uuid, None) - if self._client is None: - self._client = self._rpc_client_instance() if self._client is None: - return - self._resynchronize() - - try: - self._client.DeletePort(self._uuid_to_hex(vif_uuid)) - except: - self._client = None + self._client = self._rpc_client_instance() + if self._client is None: + return + self._resynchronize() + + try: + self._client.DeletePort(self._uuid_to_hex(vif_uuid)) + except: + self._client = None + finally: + if self._semaphore: + self._semaphore.release() def periodic_connection_check(self): """ @@ -160,15 +172,21 @@ def periodic_connection_check(self): It is the API client's resposibility to periodically invoke this method. """ - if self._client is None: - self._client = self._rpc_client_instance() - if self._client is None: - return - self._resynchronize() - try: - if self._client: - self._client.KeepAliveCheck() - except Exception as ex: - self._client = None - logging.exception(ex) + if self._semaphore: + self._semaphore.acquire() + if self._client is None: + self._client = self._rpc_client_instance() + if self._client is None: + return + self._resynchronize() + + try: + if self._client: + self._client.KeepAliveCheck() + except Exception as ex: + self._client = None + logging.exception(ex) + finally: + if self._semaphore: + self._semaphore.release()