|
|
@ -12,6 +12,7 @@ |
|
|
|
# See the License for the specific language governing permissions and |
|
|
|
# See the License for the specific language governing permissions and |
|
|
|
# limitations under the License. |
|
|
|
# limitations under the License. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import abc |
|
|
|
import dataclasses |
|
|
|
import dataclasses |
|
|
|
import logging |
|
|
|
import logging |
|
|
|
from typing import Any, Dict, List, Optional, Tuple |
|
|
|
from typing import Any, Dict, List, Optional, Tuple |
|
|
@ -23,8 +24,8 @@ from framework.infrastructure import gcp |
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
|
|
|
_ComputeV1 = gcp.compute.ComputeV1 |
|
|
|
# Type aliases |
|
|
|
GcpResource = _ComputeV1.GcpResource |
|
|
|
GcpResource = gcp.compute.ComputeV1.GcpResource |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclasses.dataclass(frozen=True) |
|
|
|
@dataclasses.dataclass(frozen=True) |
|
|
@ -32,12 +33,25 @@ class EndpointPolicy: |
|
|
|
url: str |
|
|
|
url: str |
|
|
|
name: str |
|
|
|
name: str |
|
|
|
type: str |
|
|
|
type: str |
|
|
|
server_tls_policy: Optional[str] |
|
|
|
|
|
|
|
traffic_port_selector: dict |
|
|
|
traffic_port_selector: dict |
|
|
|
endpoint_matcher: dict |
|
|
|
endpoint_matcher: dict |
|
|
|
http_filters: dict |
|
|
|
|
|
|
|
update_time: str |
|
|
|
update_time: str |
|
|
|
create_time: str |
|
|
|
create_time: str |
|
|
|
|
|
|
|
http_filters: Optional[dict] = None |
|
|
|
|
|
|
|
server_tls_policy: Optional[str] = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
|
|
def from_response(cls, name: str, response: Dict[str, |
|
|
|
|
|
|
|
Any]) -> 'EndpointPolicy': |
|
|
|
|
|
|
|
return cls(name=name, |
|
|
|
|
|
|
|
url=response['name'], |
|
|
|
|
|
|
|
type=response['type'], |
|
|
|
|
|
|
|
server_tls_policy=response.get('serverTlsPolicy', None), |
|
|
|
|
|
|
|
traffic_port_selector=response['trafficPortSelector'], |
|
|
|
|
|
|
|
endpoint_matcher=response['endpointMatcher'], |
|
|
|
|
|
|
|
http_filters=response.get('httpFilters', None), |
|
|
|
|
|
|
|
update_time=response['updateTime'], |
|
|
|
|
|
|
|
create_time=response['createTime']) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclasses.dataclass(frozen=True) |
|
|
|
@dataclasses.dataclass(frozen=True) |
|
|
@ -161,10 +175,9 @@ class GrpcRoute: |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NetworkServicesV1Alpha1(gcp.api.GcpStandardCloudApiResource): |
|
|
|
class _NetworkServicesBase(gcp.api.GcpStandardCloudApiResource, |
|
|
|
ENDPOINT_POLICIES = 'endpointPolicies' |
|
|
|
metaclass=abc.ABCMeta): |
|
|
|
GRPC_ROUTES = 'grpcRoutes' |
|
|
|
"""Base class for NetworkServices APIs.""" |
|
|
|
ROUTERS = 'routers' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, api_manager: gcp.api.GcpApiManager, project: str): |
|
|
|
def __init__(self, api_manager: gcp.api.GcpApiManager, project: str): |
|
|
|
super().__init__(api_manager.networkservices(self.api_version), project) |
|
|
|
super().__init__(api_manager.networkservices(self.api_version), project) |
|
|
@ -175,9 +188,30 @@ class NetworkServicesV1Alpha1(gcp.api.GcpStandardCloudApiResource): |
|
|
|
def api_name(self) -> str: |
|
|
|
def api_name(self) -> str: |
|
|
|
return 'networkservices' |
|
|
|
return 'networkservices' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _execute(self, *args, **kwargs): # pylint: disable=signature-differs |
|
|
|
|
|
|
|
# Workaround TD bug: throttled operations are reported as internal. |
|
|
|
|
|
|
|
# Ref b/175345578 |
|
|
|
|
|
|
|
retryer = tenacity.Retrying( |
|
|
|
|
|
|
|
retry=tenacity.retry_if_exception(self._operation_internal_error), |
|
|
|
|
|
|
|
wait=tenacity.wait_fixed(10), |
|
|
|
|
|
|
|
stop=tenacity.stop_after_delay(5 * 60), |
|
|
|
|
|
|
|
before_sleep=tenacity.before_sleep_log(logger, logging.DEBUG), |
|
|
|
|
|
|
|
reraise=True) |
|
|
|
|
|
|
|
retryer(super()._execute, *args, **kwargs) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod |
|
|
|
|
|
|
|
def _operation_internal_error(exception): |
|
|
|
|
|
|
|
return (isinstance(exception, gcp.api.OperationError) and |
|
|
|
|
|
|
|
exception.error.code == code_pb2.INTERNAL) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NetworkServicesV1Beta1(_NetworkServicesBase): |
|
|
|
|
|
|
|
"""NetworkServices API v1beta1.""" |
|
|
|
|
|
|
|
ENDPOINT_POLICIES = 'endpointPolicies' |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def api_version(self) -> str: |
|
|
|
def api_version(self) -> str: |
|
|
|
return 'v1alpha1' |
|
|
|
return 'v1beta1' |
|
|
|
|
|
|
|
|
|
|
|
def create_endpoint_policy(self, name, body: dict) -> GcpResource: |
|
|
|
def create_endpoint_policy(self, name, body: dict) -> GcpResource: |
|
|
|
return self._create_resource( |
|
|
|
return self._create_resource( |
|
|
@ -186,47 +220,41 @@ class NetworkServicesV1Alpha1(gcp.api.GcpStandardCloudApiResource): |
|
|
|
endpointPolicyId=name) |
|
|
|
endpointPolicyId=name) |
|
|
|
|
|
|
|
|
|
|
|
def get_endpoint_policy(self, name: str) -> EndpointPolicy: |
|
|
|
def get_endpoint_policy(self, name: str) -> EndpointPolicy: |
|
|
|
result = self._get_resource( |
|
|
|
response = self._get_resource( |
|
|
|
collection=self._api_locations.endpointPolicies(), |
|
|
|
collection=self._api_locations.endpointPolicies(), |
|
|
|
full_name=self.resource_full_name(name, self.ENDPOINT_POLICIES)) |
|
|
|
full_name=self.resource_full_name(name, self.ENDPOINT_POLICIES)) |
|
|
|
return EndpointPolicy( |
|
|
|
return EndpointPolicy.from_response(name, response) |
|
|
|
name=name, |
|
|
|
|
|
|
|
url=result['name'], |
|
|
|
def delete_endpoint_policy(self, name: str) -> bool: |
|
|
|
type=result['type'], |
|
|
|
|
|
|
|
server_tls_policy=result.get('serverTlsPolicy', None), |
|
|
|
|
|
|
|
traffic_port_selector=result['trafficPortSelector'], |
|
|
|
|
|
|
|
endpoint_matcher=result['endpointMatcher'], |
|
|
|
|
|
|
|
http_filters=result['httpFilters'], |
|
|
|
|
|
|
|
update_time=result['updateTime'], |
|
|
|
|
|
|
|
create_time=result['createTime']) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def delete_endpoint_policy(self, name): |
|
|
|
|
|
|
|
return self._delete_resource( |
|
|
|
return self._delete_resource( |
|
|
|
collection=self._api_locations.endpointPolicies(), |
|
|
|
collection=self._api_locations.endpointPolicies(), |
|
|
|
full_name=self.resource_full_name(name, self.ENDPOINT_POLICIES)) |
|
|
|
full_name=self.resource_full_name(name, self.ENDPOINT_POLICIES)) |
|
|
|
|
|
|
|
|
|
|
|
def _execute(self, *args, **kwargs): # pylint: disable=signature-differs |
|
|
|
|
|
|
|
# Workaround TD bug: throttled operations are reported as internal. |
|
|
|
class NetworkServicesV1Alpha1(NetworkServicesV1Beta1): |
|
|
|
# Ref b/175345578 |
|
|
|
"""NetworkServices API v1alpha1. |
|
|
|
retryer = tenacity.Retrying( |
|
|
|
|
|
|
|
retry=tenacity.retry_if_exception(self._operation_internal_error), |
|
|
|
Note: extending v1beta1 class presumes that v1beta1 is just a v1alpha1 API |
|
|
|
wait=tenacity.wait_fixed(10), |
|
|
|
graduated into a more stable version. This is true in most cases. However, |
|
|
|
stop=tenacity.stop_after_delay(5 * 60), |
|
|
|
v1alpha1 class can always override and reimplement incompatible methods. |
|
|
|
before_sleep=tenacity.before_sleep_log(logger, logging.DEBUG), |
|
|
|
""" |
|
|
|
reraise=True) |
|
|
|
|
|
|
|
retryer(super()._execute, *args, **kwargs) |
|
|
|
GRPC_ROUTES = 'grpcRoutes' |
|
|
|
|
|
|
|
ROUTERS = 'routers' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
|
|
|
|
def api_version(self) -> str: |
|
|
|
|
|
|
|
return 'v1alpha1' |
|
|
|
|
|
|
|
|
|
|
|
def create_router(self, name: str, body: dict) -> GcpResource: |
|
|
|
def create_router(self, name: str, body: dict) -> GcpResource: |
|
|
|
return self._create_resource( |
|
|
|
return self._create_resource(collection=self._api_locations.routers(), |
|
|
|
self._api_locations.routers(), |
|
|
|
body=body, |
|
|
|
body, |
|
|
|
routerId=name) |
|
|
|
routerId=name, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_router(self, name: str) -> Router: |
|
|
|
def get_router(self, name: str) -> Router: |
|
|
|
|
|
|
|
full_name = self.resource_full_name(name, self.ROUTERS) |
|
|
|
result = self._get_resource(collection=self._api_locations.routers(), |
|
|
|
result = self._get_resource(collection=self._api_locations.routers(), |
|
|
|
full_name=self.resource_full_name( |
|
|
|
full_name=full_name) |
|
|
|
name, self.ROUTERS)) |
|
|
|
|
|
|
|
return Router.from_response(name, result) |
|
|
|
return Router.from_response(name, result) |
|
|
|
|
|
|
|
|
|
|
|
def delete_router(self, name: str) -> bool: |
|
|
|
def delete_router(self, name: str) -> bool: |
|
|
@ -235,22 +263,18 @@ class NetworkServicesV1Alpha1(gcp.api.GcpStandardCloudApiResource): |
|
|
|
name, self.ROUTERS)) |
|
|
|
name, self.ROUTERS)) |
|
|
|
|
|
|
|
|
|
|
|
def create_grpc_route(self, name: str, body: dict) -> GcpResource: |
|
|
|
def create_grpc_route(self, name: str, body: dict) -> GcpResource: |
|
|
|
return self._create_resource(self._api_locations.grpcRoutes(), |
|
|
|
return self._create_resource( |
|
|
|
body, |
|
|
|
collection=self._api_locations.grpcRoutes(), |
|
|
|
grpcRouteId=name) |
|
|
|
body=body, |
|
|
|
|
|
|
|
grpcRouteId=name) |
|
|
|
|
|
|
|
|
|
|
|
def get_grpc_route(self, name: str) -> GrpcRoute: |
|
|
|
def get_grpc_route(self, name: str) -> GrpcRoute: |
|
|
|
|
|
|
|
full_name = self.resource_full_name(name, self.GRPC_ROUTES) |
|
|
|
result = self._get_resource(collection=self._api_locations.grpcRoutes(), |
|
|
|
result = self._get_resource(collection=self._api_locations.grpcRoutes(), |
|
|
|
full_name=self.resource_full_name( |
|
|
|
full_name=full_name) |
|
|
|
name, self.GRPC_ROUTES)) |
|
|
|
|
|
|
|
return GrpcRoute.from_response(name, result) |
|
|
|
return GrpcRoute.from_response(name, result) |
|
|
|
|
|
|
|
|
|
|
|
def delete_grpc_route(self, name: str) -> bool: |
|
|
|
def delete_grpc_route(self, name: str) -> bool: |
|
|
|
return self._delete_resource( |
|
|
|
return self._delete_resource( |
|
|
|
collection=self._api_locations.grpcRoutes(), |
|
|
|
collection=self._api_locations.grpcRoutes(), |
|
|
|
full_name=self.resource_full_name(name, self.GRPC_ROUTES)) |
|
|
|
full_name=self.resource_full_name(name, self.GRPC_ROUTES)) |
|
|
|
|
|
|
|
|
|
|
|
@staticmethod |
|
|
|
|
|
|
|
def _operation_internal_error(exception): |
|
|
|
|
|
|
|
return (isinstance(exception, gcp.api.OperationError) and |
|
|
|
|
|
|
|
exception.error.code == code_pb2.INTERNAL) |
|
|
|
|
|
|
|