xds-k8s: PSM Security tests upgrade networksecurity, networkservices to v1beta1 (#27005)

* xds-k8s: PSM Security uses Network Services v1beta1

* xds-k8s: PSM Security uses Network Security v1beta1

* Explain assumptions v1alpha1 extending v1beta1
pull/26973/head^2
Sergii Tkachenko 3 years ago committed by GitHub
parent bbea27de46
commit 1d9a242931
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/api.py
  2. 166
      tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/network_security.py
  3. 122
      tools/run_tests/xds_k8s_test_driver/framework/infrastructure/gcp/network_services.py
  4. 20
      tools/run_tests/xds_k8s_test_driver/framework/infrastructure/traffic_director.py

@ -125,6 +125,8 @@ class GcpApiManager:
version, version,
api_key=self.private_api_key, api_key=self.private_api_key,
visibility_labels=['NETWORKSECURITY_ALPHA']) visibility_labels=['NETWORKSECURITY_ALPHA'])
elif version == 'v1beta1':
return self._build_from_discovery_v2(api_name, version)
raise NotImplementedError(f'Network Security {version} not supported') raise NotImplementedError(f'Network Security {version} not supported')
@ -137,6 +139,8 @@ class GcpApiManager:
version, version,
api_key=self.private_api_key, api_key=self.private_api_key,
visibility_labels=['NETWORKSERVICES_ALPHA']) visibility_labels=['NETWORKSERVICES_ALPHA'])
elif version == 'v1beta1':
return self._build_from_discovery_v2(api_name, version)
raise NotImplementedError(f'Network Services {version} not supported') raise NotImplementedError(f'Network Services {version} not supported')

@ -11,8 +11,11 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# 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
from google.rpc import code_pb2 from google.rpc import code_pb2
import tenacity import tenacity
@ -21,28 +24,53 @@ from framework.infrastructure import gcp
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Type aliases
class NetworkSecurityV1Alpha1(gcp.api.GcpStandardCloudApiResource): GcpResource = gcp.compute.ComputeV1.GcpResource
SERVER_TLS_POLICIES = 'serverTlsPolicies'
CLIENT_TLS_POLICIES = 'clientTlsPolicies'
@dataclasses.dataclass(frozen=True)
@dataclasses.dataclass(frozen=True) class ServerTlsPolicy:
class ServerTlsPolicy: url: str
url: str name: str
name: str server_certificate: dict
server_certificate: dict mtls_policy: dict
mtls_policy: dict update_time: str
update_time: str create_time: str
create_time: str
@classmethod
@dataclasses.dataclass(frozen=True) def from_response(cls, name: str, response: Dict[str,
class ClientTlsPolicy: Any]) -> 'ServerTlsPolicy':
url: str return cls(name=name,
name: str url=response['name'],
client_certificate: dict server_certificate=response.get('serverCertificate', {}),
server_validation_ca: list mtls_policy=response.get('mtlsPolicy', {}),
update_time: str create_time=response['createTime'],
create_time: str update_time=response['updateTime'])
@dataclasses.dataclass(frozen=True)
class ClientTlsPolicy:
url: str
name: str
client_certificate: dict
server_validation_ca: list
update_time: str
create_time: str
@classmethod
def from_response(cls, name: str, response: Dict[str,
Any]) -> 'ClientTlsPolicy':
return cls(name=name,
url=response['name'],
client_certificate=response.get('clientCertificate', {}),
server_validation_ca=response.get('serverValidationCa', []),
create_time=response['createTime'],
update_time=response['updateTime'])
class _NetworkSecurityBase(gcp.api.GcpStandardCloudApiResource,
metaclass=abc.ABCMeta):
"""Base class for NetworkSecurity APIs."""
def __init__(self, api_manager: gcp.api.GcpApiManager, project: str): def __init__(self, api_manager: gcp.api.GcpApiManager, project: str):
super().__init__(api_manager.networksecurity(self.api_version), project) super().__init__(api_manager.networksecurity(self.api_version), project)
@ -53,68 +81,76 @@ class NetworkSecurityV1Alpha1(gcp.api.GcpStandardCloudApiResource):
def api_name(self) -> str: def api_name(self) -> str:
return 'networksecurity' return 'networksecurity'
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 NetworkSecurityV1Beta1(_NetworkSecurityBase):
"""NetworkSecurity API v1beta1."""
SERVER_TLS_POLICIES = 'serverTlsPolicies'
CLIENT_TLS_POLICIES = 'clientTlsPolicies'
@property @property
def api_version(self) -> str: def api_version(self) -> str:
return 'v1alpha1' return 'v1beta1'
def create_server_tls_policy(self, name, body: dict): def create_server_tls_policy(self, name: str, body: dict) -> GcpResource:
return self._create_resource(self._api_locations.serverTlsPolicies(), return self._create_resource(
body, collection=self._api_locations.serverTlsPolicies(),
serverTlsPolicyId=name) body=body,
serverTlsPolicyId=name)
def get_server_tls_policy(self, name: str) -> ServerTlsPolicy: def get_server_tls_policy(self, name: str) -> ServerTlsPolicy:
result = self._get_resource( response = self._get_resource(
collection=self._api_locations.serverTlsPolicies(), collection=self._api_locations.serverTlsPolicies(),
full_name=self.resource_full_name(name, self.SERVER_TLS_POLICIES)) full_name=self.resource_full_name(name, self.SERVER_TLS_POLICIES))
return ServerTlsPolicy.from_response(name, response)
return self.ServerTlsPolicy(name=name, def delete_server_tls_policy(self, name: str) -> bool:
url=result['name'],
server_certificate=result.get(
'serverCertificate', {}),
mtls_policy=result.get('mtlsPolicy', {}),
create_time=result['createTime'],
update_time=result['updateTime'])
def delete_server_tls_policy(self, name):
return self._delete_resource( return self._delete_resource(
collection=self._api_locations.serverTlsPolicies(), collection=self._api_locations.serverTlsPolicies(),
full_name=self.resource_full_name(name, self.SERVER_TLS_POLICIES)) full_name=self.resource_full_name(name, self.SERVER_TLS_POLICIES))
def create_client_tls_policy(self, name, body: dict): def create_client_tls_policy(self, name: str, body: dict) -> GcpResource:
return self._create_resource(self._api_locations.clientTlsPolicies(), return self._create_resource(
body, collection=self._api_locations.clientTlsPolicies(),
clientTlsPolicyId=name) body=body,
clientTlsPolicyId=name)
def get_client_tls_policy(self, name: str) -> ClientTlsPolicy: def get_client_tls_policy(self, name: str) -> ClientTlsPolicy:
result = self._get_resource( response = self._get_resource(
collection=self._api_locations.clientTlsPolicies(), collection=self._api_locations.clientTlsPolicies(),
full_name=self.resource_full_name(name, self.CLIENT_TLS_POLICIES)) full_name=self.resource_full_name(name, self.CLIENT_TLS_POLICIES))
return ClientTlsPolicy.from_response(name, response)
return self.ClientTlsPolicy( def delete_client_tls_policy(self, name: str) -> bool:
name=name,
url=result['name'],
client_certificate=result.get('clientCertificate', {}),
server_validation_ca=result.get('serverValidationCa', []),
create_time=result['createTime'],
update_time=result['updateTime'])
def delete_client_tls_policy(self, name):
return self._delete_resource( return self._delete_resource(
collection=self._api_locations.clientTlsPolicies(), collection=self._api_locations.clientTlsPolicies(),
full_name=self.resource_full_name(name, self.CLIENT_TLS_POLICIES)) full_name=self.resource_full_name(name, self.CLIENT_TLS_POLICIES))
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 class NetworkSecurityV1Alpha1(NetworkSecurityV1Beta1):
def _operation_internal_error(exception): """NetworkSecurity API v1alpha1.
return (isinstance(exception, gcp.api.OperationError) and
exception.error.code == code_pb2.INTERNAL) Note: extending v1beta1 class presumes that v1beta1 is just a v1alpha1 API
graduated into a more stable version. This is true in most cases. However,
v1alpha1 class can always override and reimplement incompatible methods.
"""
@property
def api_version(self) -> str:
return 'v1alpha1'

@ -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)

@ -14,7 +14,7 @@
import functools import functools
import logging import logging
import random import random
from typing import Any, Dict, Iterable, List, Optional, Set from typing import Any, Dict, List, Optional, Set
from framework import xds_flags from framework import xds_flags
from framework.infrastructure import gcp from framework.infrastructure import gcp
@ -32,12 +32,13 @@ _BackendGRPC = BackendServiceProtocol.GRPC
_HealthCheckGRPC = HealthCheckProtocol.GRPC _HealthCheckGRPC = HealthCheckProtocol.GRPC
# Network Security # Network Security
_NetworkSecurityV1Alpha1 = gcp.network_security.NetworkSecurityV1Alpha1 _NetworkSecurityV1Beta1 = gcp.network_security.NetworkSecurityV1Beta1
ServerTlsPolicy = _NetworkSecurityV1Alpha1.ServerTlsPolicy ServerTlsPolicy = gcp.network_security.ServerTlsPolicy
ClientTlsPolicy = _NetworkSecurityV1Alpha1.ClientTlsPolicy ClientTlsPolicy = gcp.network_security.ClientTlsPolicy
# Network Services # Network Services
_NetworkServicesV1Alpha1 = gcp.network_services.NetworkServicesV1Alpha1 _NetworkServicesV1Alpha1 = gcp.network_services.NetworkServicesV1Alpha1
_NetworkServicesV1Beta1 = gcp.network_services.NetworkServicesV1Beta1
EndpointPolicy = gcp.network_services.EndpointPolicy EndpointPolicy = gcp.network_services.EndpointPolicy
# Testing metadata consts # Testing metadata consts
@ -537,6 +538,8 @@ class TrafficDirectorAppNetManager(TrafficDirectorManager):
GRPC_ROUTE_NAME = "grpc-route" GRPC_ROUTE_NAME = "grpc-route"
ROUTER_NAME = "router" ROUTER_NAME = "router"
netsvc: _NetworkServicesV1Alpha1
def __init__(self, def __init__(self,
gcp_api_manager: gcp.api.GcpApiManager, gcp_api_manager: gcp.api.GcpApiManager,
project: str, project: str,
@ -627,12 +630,14 @@ class TrafficDirectorAppNetManager(TrafficDirectorManager):
class TrafficDirectorSecureManager(TrafficDirectorManager): class TrafficDirectorSecureManager(TrafficDirectorManager):
netsec: Optional[_NetworkSecurityV1Alpha1]
SERVER_TLS_POLICY_NAME = "server-tls-policy" SERVER_TLS_POLICY_NAME = "server-tls-policy"
CLIENT_TLS_POLICY_NAME = "client-tls-policy" CLIENT_TLS_POLICY_NAME = "client-tls-policy"
ENDPOINT_POLICY = "endpoint-policy" ENDPOINT_POLICY = "endpoint-policy"
CERTIFICATE_PROVIDER_INSTANCE = "google_cloud_private_spiffe" CERTIFICATE_PROVIDER_INSTANCE = "google_cloud_private_spiffe"
netsec: _NetworkSecurityV1Beta1
netsvc: _NetworkServicesV1Beta1
def __init__( def __init__(
self, self,
gcp_api_manager: gcp.api.GcpApiManager, gcp_api_manager: gcp.api.GcpApiManager,
@ -649,8 +654,8 @@ class TrafficDirectorSecureManager(TrafficDirectorManager):
network=network) network=network)
# API # API
self.netsec = _NetworkSecurityV1Alpha1(gcp_api_manager, project) self.netsec = _NetworkSecurityV1Beta1(gcp_api_manager, project)
self.netsvc = _NetworkServicesV1Alpha1(gcp_api_manager, project) self.netsvc = _NetworkServicesV1Beta1(gcp_api_manager, project)
# Managed resources # Managed resources
self.server_tls_policy: Optional[ServerTlsPolicy] = None self.server_tls_policy: Optional[ServerTlsPolicy] = None
@ -734,7 +739,6 @@ class TrafficDirectorSecureManager(TrafficDirectorManager):
} }
config = { config = {
"type": "GRPC_SERVER", "type": "GRPC_SERVER",
"httpFilters": {},
"trafficPortSelector": port_selector, "trafficPortSelector": port_selector,
"endpointMatcher": { "endpointMatcher": {
"metadataLabelMatcher": label_matcher_all, "metadataLabelMatcher": label_matcher_all,

Loading…
Cancel
Save