Commit 91880668 authored by Antonio Gines Buendia Lopez's avatar Antonio Gines Buendia Lopez
Browse files

Implement handling of gRPC errors and timeouts on NBI

Fixed returning generic error 500 on response when gRPC was failing. Implemented a timeout on the gRPC calls from NBI to PCE
parent 46cef737
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -40,7 +40,7 @@ spec:
            - name: ENABLE_HRAT
            - name: ENABLE_HRAT
              value: "TRUE"
              value: "TRUE"
            - name: HRAT_HOST
            - name: HRAT_HOST
              value: "192.168.1.168"
              value: "192.168.1.135"
            - name: HRAT_PORT
            - name: HRAT_PORT
              value: "9090"
              value: "9090"
            - name: HRAT_SCHEME
            - name: HRAT_SCHEME
+75 −0
Original line number Original line Diff line number Diff line
@@ -13,10 +13,16 @@
# limitations under the License.
# limitations under the License.
import json
import json
import logging
import logging

import grpc
from flask_restful import Resource, request
from flask_restful import Resource, request
from pathcompextended.client.PathCompExtendedClient import PathCompExtendedClient
from pathcompextended.client.PathCompExtendedClient import PathCompExtendedClient


from common.proto.context_pb2 import Empty
from common.proto.context_pb2 import Empty
from nbi.service._tools.HttpStatusCodes import HTTP_BADREQUEST, HTTP_GATEWAYTIMEOUT

# Local constants (NBI shared constants cannot be modified)
HTTP_SERVICE_UNAVAILABLE = 503
from common.proto.pathcompextended_pb2 import (
from common.proto.pathcompextended_pb2 import (
    IetfNetworkSlice, LivenessProbe, NetworkContext as NetworkContextProto,
    IetfNetworkSlice, LivenessProbe, NetworkContext as NetworkContextProto,
    NetworkTopology, TransportNetworkSliceL3, TransportOpticalSlice, UUID,
    NetworkTopology, TransportNetworkSliceL3, TransportOpticalSlice, UUID,
@@ -26,6 +32,27 @@ from common.tools.grpc.Tools import grpc_message_to_json_string


LOGGER = logging.getLogger(__name__)
LOGGER = logging.getLogger(__name__)


# Generic gRPC error parsing: details + HTTP status. Each endpoint adds its own error message.
def _parse_grpc_error(e: grpc.RpcError):
    """Extract details and HTTP status from gRPC error. Returns (details_str, status_code)."""
    details = str(e.details()) if e.details() else str(e)
    code = e.code()
    if code == grpc.StatusCode.DEADLINE_EXCEEDED:
        return details, HTTP_GATEWAYTIMEOUT
    if code == grpc.StatusCode.UNAVAILABLE:
        return details, HTTP_SERVICE_UNAVAILABLE
    if code == grpc.StatusCode.UNREACHABLE:
        return details, HTTP_SERVICE_UNAVAILABLE
    if code in (grpc.StatusCode.FAILED_PRECONDITION, grpc.StatusCode.UNIMPLEMENTED):
        return details, HTTP_BADREQUEST
    return details, HTTP_SERVICE_UNAVAILABLE


def _grpc_error_response(e: grpc.RpcError, error_message: str):
    """Build JSON error response from gRPC error with endpoint-specific message."""
    details, status = _parse_grpc_error(e)
    return {"error": error_message, "details": details}, status



class _Resource(Resource):
class _Resource(Resource):
    def __init__(self) -> None:
    def __init__(self) -> None:
@@ -51,6 +78,9 @@ class Health(_Resource):
            LOGGER.debug(grpc_message_to_json_string(probe))
            LOGGER.debug(grpc_message_to_json_string(probe))
            output = json.loads(grpc_message_to_json_string(probe))
            output = json.loads(grpc_message_to_json_string(probe))
            return output
            return output
        except grpc.RpcError as e:
            LOGGER.error("Error checking health (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error checking health: %s", e, exc_info=True)
            LOGGER.error("Error checking health: %s", e, exc_info=True)
            return {"error": str(e), "status": "unhealthy"}, 500
            return {"error": str(e), "status": "unhealthy"}, 500
@@ -66,6 +96,9 @@ class Reset(_Resource):
            else:
            else:
                output = {"message": result.message}
                output = {"message": result.message}
            return output, 200
            return output, 200
        except grpc.RpcError as e:
            LOGGER.error("Error resetting (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error resetting: %s", e, exc_info=True)
            LOGGER.error("Error resetting: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -96,6 +129,9 @@ class NetworkContext(_Resource):
                "total": len(net_context.topologies),
                "total": len(net_context.topologies),
            }
            }
            return output
            return output
        except grpc.RpcError as e:
            LOGGER.error("Error getting network context (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error getting network context: %s", e, exc_info=True)
            LOGGER.error("Error getting network context: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -135,6 +171,9 @@ class NetworkContext(_Resource):
                output = {"message": result.message}
                output = {"message": result.message}


            return output, 201
            return output, 201
        except grpc.RpcError as e:
            LOGGER.error("Error creating network context (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error creating network context: %s", e, exc_info=True)
            LOGGER.error("Error creating network context: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -155,6 +194,9 @@ class NetworkContextDetails(_Resource):
                "raw-json-topology": topology.raw_json_topology,
                "raw-json-topology": topology.raw_json_topology,
            }
            }
            return output
            return output
        except grpc.RpcError as e:
            LOGGER.error("Error getting network context %s (gRPC): %s", id, e, exc_info=True)
            return _grpc_error_response(e, "PCE unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error getting network context %s: %s", id, e, exc_info=True)
            LOGGER.error("Error getting network context %s: %s", id, e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -171,6 +213,9 @@ class NetworkContextDetails(_Resource):
            else:
            else:
                output = {"message": result.message}
                output = {"message": result.message}
            return output, 200
            return output, 200
        except grpc.RpcError as e:
            LOGGER.error("Error deleting network context %s (gRPC): %s", id, e, exc_info=True)
            return _grpc_error_response(e, "PCE unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error deleting network context %s: %s", id, e, exc_info=True)
            LOGGER.error("Error deleting network context %s: %s", id, e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -211,6 +256,9 @@ class TransportOpticalSlice(_Resource):
                "data": data,
                "data": data,
                "message": response.message,
                "message": response.message,
            }
            }
        except grpc.RpcError as e:
            LOGGER.error("Error getting transport optical slices (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error getting transport optical slices: %s", e, exc_info=True)
            LOGGER.error("Error getting transport optical slices: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -225,6 +273,9 @@ class TransportOpticalSlice(_Resource):
            else:
            else:
                output = {"message": result.message}
                output = {"message": result.message}
            return output, 200
            return output, 200
        except grpc.RpcError as e:
            LOGGER.error("Error deleting all transport optical slices (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error deleting all transport optical slices: %s", e, exc_info=True)
            LOGGER.error("Error deleting all transport optical slices: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -246,6 +297,9 @@ class TransportOpticalSlice(_Resource):
            LOGGER.debug(grpc_message_to_json_string(result))
            LOGGER.debug(grpc_message_to_json_string(result))
            output = _transport_optical_slice_to_hrat(result)
            output = _transport_optical_slice_to_hrat(result)
            return output, 201
            return output, 201
        except grpc.RpcError as e:
            LOGGER.error("Error creating transport optical slice (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error creating transport optical slice: %s", e, exc_info=True)
            LOGGER.error("Error creating transport optical slice: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -262,6 +316,9 @@ class TransportOpticalSliceDetails(_Resource):
            LOGGER.debug(grpc_message_to_json_string(slice_msg))
            LOGGER.debug(grpc_message_to_json_string(slice_msg))
            output = _transport_optical_slice_to_hrat(slice_msg)
            output = _transport_optical_slice_to_hrat(slice_msg)
            return output
            return output
        except grpc.RpcError as e:
            LOGGER.error("Error getting transport optical slice %s (gRPC): %s", id, e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error getting transport optical slice %s: %s", id, e, exc_info=True)
            LOGGER.error("Error getting transport optical slice %s: %s", id, e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -278,6 +335,9 @@ class TransportOpticalSliceDetails(_Resource):
            else:
            else:
                output = {"message": result.message}
                output = {"message": result.message}
            return output, 200
            return output, 200
        except grpc.RpcError as e:
            LOGGER.error("Error deleting transport optical slice %s (gRPC): %s", id, e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error deleting transport optical slice %s: %s", id, e, exc_info=True)
            LOGGER.error("Error deleting transport optical slice %s: %s", id, e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -299,6 +359,9 @@ class TransportNetworkSliceL3(_Resource):
                "data": data,
                "data": data,
                "message": response.message,
                "message": response.message,
            }
            }
        except grpc.RpcError as e:
            LOGGER.error("Error getting transport network slices L3 (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error getting transport network slices L3: %s", e, exc_info=True)
            LOGGER.error("Error getting transport network slices L3: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -313,6 +376,9 @@ class TransportNetworkSliceL3(_Resource):
            else:
            else:
                output = {"message": result.message}
                output = {"message": result.message}
            return output, 200
            return output, 200
        except grpc.RpcError as e:
            LOGGER.error("Error deleting all transport network slices L3 (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error deleting all transport network slices L3: %s", e, exc_info=True)
            LOGGER.error("Error deleting all transport network slices L3: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -334,6 +400,9 @@ class TransportNetworkSliceL3(_Resource):
            LOGGER.debug(grpc_message_to_json_string(result))
            LOGGER.debug(grpc_message_to_json_string(result))
            output = _transport_network_slice_l3_to_hrat(result)
            output = _transport_network_slice_l3_to_hrat(result)
            return output, 201
            return output, 201
        except grpc.RpcError as e:
            LOGGER.error("Error creating transport network slice L3 (gRPC): %s", e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error creating transport network slice L3: %s", e, exc_info=True)
            LOGGER.error("Error creating transport network slice L3: %s", e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -350,6 +419,9 @@ class TransportNetworkSliceL3Details(_Resource):
            LOGGER.debug(grpc_message_to_json_string(slice_msg))
            LOGGER.debug(grpc_message_to_json_string(slice_msg))
            output = _transport_network_slice_l3_to_hrat(slice_msg)
            output = _transport_network_slice_l3_to_hrat(slice_msg)
            return output
            return output
        except grpc.RpcError as e:
            LOGGER.error("Error getting transport network slice L3 %s (gRPC): %s", id, e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error getting transport network slice L3 %s: %s", id, e, exc_info=True)
            LOGGER.error("Error getting transport network slice L3 %s: %s", id, e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
@@ -366,6 +438,9 @@ class TransportNetworkSliceL3Details(_Resource):
            else:
            else:
                output = {"message": result.message}
                output = {"message": result.message}
            return output, 200
            return output, 200
        except grpc.RpcError as e:
            LOGGER.error("Error deleting transport network slice L3 %s (gRPC): %s", id, e, exc_info=True)
            return _grpc_error_response(e, "PCE or H-RAT unavailable")
        except Exception as e:
        except Exception as e:
            LOGGER.error("Error deleting transport network slice L3 %s: %s", id, e, exc_info=True)
            LOGGER.error("Error deleting transport network slice L3 %s: %s", id, e, exc_info=True)
            return {"error": str(e)}, 500
            return {"error": str(e)}, 500
+17 −16
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ from common.tools.grpc.Tools import grpc_message_to_json_string


LOGGER = logging.getLogger(__name__)
LOGGER = logging.getLogger(__name__)
MAX_RETRIES = 15
MAX_RETRIES = 15
GRPC_TIMEOUT_SECONDS = 10
DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0)
DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0)
RETRY_DECORATOR = retry(max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')
RETRY_DECORATOR = retry(max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')


@@ -60,7 +61,7 @@ class PathCompExtendedClient:
        if request is None:
        if request is None:
            request = Empty()
            request = Empty()
        LOGGER.debug('HealthCheck request')
        LOGGER.debug('HealthCheck request')
        response = self.stub.HealthCheck(request)
        response = self.stub.HealthCheck(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('HealthCheck result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('HealthCheck result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -69,7 +70,7 @@ class PathCompExtendedClient:
        if request is None:
        if request is None:
            request = Empty()
            request = Empty()
        LOGGER.debug('Reset request')
        LOGGER.debug('Reset request')
        response = self.stub.Reset(request)
        response = self.stub.Reset(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('Reset result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('Reset result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -80,14 +81,14 @@ class PathCompExtendedClient:
    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def CreateNetworkContext(self, request: NetworkContext) -> GenericMessage:
    def CreateNetworkContext(self, request: NetworkContext) -> GenericMessage:
        LOGGER.debug('CreateNetworkContext request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('CreateNetworkContext request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.CreateNetworkContext(request)
        response = self.stub.CreateNetworkContext(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('CreateNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('CreateNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def DeleteNetworkContext(self, request: UUID) -> GenericMessage:
    def DeleteNetworkContext(self, request: UUID) -> GenericMessage:
        LOGGER.debug('DeleteNetworkContext request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('DeleteNetworkContext request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.DeleteNetworkContext(request)
        response = self.stub.DeleteNetworkContext(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('DeleteNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('DeleteNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -96,14 +97,14 @@ class PathCompExtendedClient:
        if request is None:
        if request is None:
            request = Empty()
            request = Empty()
        LOGGER.debug('GetNetworkContext request')
        LOGGER.debug('GetNetworkContext request')
        response = self.stub.GetNetworkContext(request)
        response = self.stub.GetNetworkContext(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('GetNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('GetNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def GetSpecificNetworkContext(self, request: UUID) -> NetworkTopology:
    def GetSpecificNetworkContext(self, request: UUID) -> NetworkTopology:
        LOGGER.debug('GetSpecificNetworkContext request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('GetSpecificNetworkContext request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.GetSpecificNetworkContext(request)
        response = self.stub.GetSpecificNetworkContext(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('GetSpecificNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('GetSpecificNetworkContext result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -114,14 +115,14 @@ class PathCompExtendedClient:
    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def CreateTransportOpticalSlice(self, request: IetfNetworkSlice) -> TransportOpticalSlice:
    def CreateTransportOpticalSlice(self, request: IetfNetworkSlice) -> TransportOpticalSlice:
        LOGGER.debug('CreateTransportOpticalSlice request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('CreateTransportOpticalSlice request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.CreateTransportOpticalSlice(request)
        response = self.stub.CreateTransportOpticalSlice(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('CreateTransportOpticalSlice result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('CreateTransportOpticalSlice result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def DeleteTransportOpticalSlice(self, request: UUID) -> GenericMessage:
    def DeleteTransportOpticalSlice(self, request: UUID) -> GenericMessage:
        LOGGER.debug('DeleteTransportOpticalSlice request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('DeleteTransportOpticalSlice request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.DeleteTransportOpticalSlice(request)
        response = self.stub.DeleteTransportOpticalSlice(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('DeleteTransportOpticalSlice result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('DeleteTransportOpticalSlice result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -130,7 +131,7 @@ class PathCompExtendedClient:
        if request is None:
        if request is None:
            request = Empty()
            request = Empty()
        LOGGER.debug('DeleteAllTransportOpticalSlices request')
        LOGGER.debug('DeleteAllTransportOpticalSlices request')
        response = self.stub.DeleteAllTransportOpticalSlices(request)
        response = self.stub.DeleteAllTransportOpticalSlices(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('DeleteAllTransportOpticalSlices result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('DeleteAllTransportOpticalSlices result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -139,14 +140,14 @@ class PathCompExtendedClient:
        if request is None:
        if request is None:
            request = Empty()
            request = Empty()
        LOGGER.debug('GetTransportOpticalSlices request')
        LOGGER.debug('GetTransportOpticalSlices request')
        response = self.stub.GetTransportOpticalSlices(request)
        response = self.stub.GetTransportOpticalSlices(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('GetTransportOpticalSlices result: {:d} items'.format(len(response.data)))
        LOGGER.debug('GetTransportOpticalSlices result: {:d} items'.format(len(response.data)))
        return response
        return response


    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def GetTransportOpticalSlice(self, request: UUID) -> TransportOpticalSlice:
    def GetTransportOpticalSlice(self, request: UUID) -> TransportOpticalSlice:
        LOGGER.debug('GetTransportOpticalSlice request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('GetTransportOpticalSlice request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.GetTransportOpticalSlice(request)
        response = self.stub.GetTransportOpticalSlice(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('GetTransportOpticalSlice result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('GetTransportOpticalSlice result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -157,14 +158,14 @@ class PathCompExtendedClient:
    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def CreateTransportNetworkSliceL3(self, request: IetfNetworkSlice) -> TransportNetworkSliceL3:
    def CreateTransportNetworkSliceL3(self, request: IetfNetworkSlice) -> TransportNetworkSliceL3:
        LOGGER.debug('CreateTransportNetworkSliceL3 request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('CreateTransportNetworkSliceL3 request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.CreateTransportNetworkSliceL3(request)
        response = self.stub.CreateTransportNetworkSliceL3(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('CreateTransportNetworkSliceL3 result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('CreateTransportNetworkSliceL3 result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def DeleteTransportNetworkSliceL3(self, request: UUID) -> GenericMessage:
    def DeleteTransportNetworkSliceL3(self, request: UUID) -> GenericMessage:
        LOGGER.debug('DeleteTransportNetworkSliceL3 request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('DeleteTransportNetworkSliceL3 request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.DeleteTransportNetworkSliceL3(request)
        response = self.stub.DeleteTransportNetworkSliceL3(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('DeleteTransportNetworkSliceL3 result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('DeleteTransportNetworkSliceL3 result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -173,7 +174,7 @@ class PathCompExtendedClient:
        if request is None:
        if request is None:
            request = Empty()
            request = Empty()
        LOGGER.debug('DeleteAllTransportNetworkSlicesL3 request')
        LOGGER.debug('DeleteAllTransportNetworkSlicesL3 request')
        response = self.stub.DeleteAllTransportNetworkSlicesL3(request)
        response = self.stub.DeleteAllTransportNetworkSlicesL3(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('DeleteAllTransportNetworkSlicesL3 result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('DeleteAllTransportNetworkSlicesL3 result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response


@@ -182,14 +183,14 @@ class PathCompExtendedClient:
        if request is None:
        if request is None:
            request = Empty()
            request = Empty()
        LOGGER.debug('GetTransportNetworkSlicesL3 request')
        LOGGER.debug('GetTransportNetworkSlicesL3 request')
        response = self.stub.GetTransportNetworkSlicesL3(request)
        response = self.stub.GetTransportNetworkSlicesL3(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('GetTransportNetworkSlicesL3 result: {:d} items'.format(len(response.data)))
        LOGGER.debug('GetTransportNetworkSlicesL3 result: {:d} items'.format(len(response.data)))
        return response
        return response


    @RETRY_DECORATOR
    @RETRY_DECORATOR
    def GetTransportNetworkSliceL3(self, request: UUID) -> TransportNetworkSliceL3:
    def GetTransportNetworkSliceL3(self, request: UUID) -> TransportNetworkSliceL3:
        LOGGER.debug('GetTransportNetworkSliceL3 request: {:s}'.format(grpc_message_to_json_string(request)))
        LOGGER.debug('GetTransportNetworkSliceL3 request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.GetTransportNetworkSliceL3(request)
        response = self.stub.GetTransportNetworkSliceL3(request, timeout=GRPC_TIMEOUT_SECONDS)
        LOGGER.debug('GetTransportNetworkSliceL3 result: {:s}'.format(grpc_message_to_json_string(response)))
        LOGGER.debug('GetTransportNetworkSliceL3 result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
        return response