17 from typing
import Any, Dict, List, Optional, Set
19 from framework
import xds_flags
22 logger = logging.getLogger(__name__)
27 GcpResource = _ComputeV1.GcpResource
28 HealthCheckProtocol = _ComputeV1.HealthCheckProtocol
29 ZonalGcpResource = _ComputeV1.ZonalGcpResource
30 BackendServiceProtocol = _ComputeV1.BackendServiceProtocol
31 _BackendGRPC = BackendServiceProtocol.GRPC
32 _HealthCheckGRPC = HealthCheckProtocol.GRPC
48 TEST_AFFINITY_METADATA_KEY =
'xds_md'
56 BACKEND_SERVICE_NAME =
"backend-service"
57 ALTERNATIVE_BACKEND_SERVICE_NAME =
"backend-service-alt"
58 AFFINITY_BACKEND_SERVICE_NAME =
"backend-service-affinity"
59 HEALTH_CHECK_NAME =
"health-check"
60 URL_MAP_NAME =
"url-map"
61 ALTERNATIVE_URL_MAP_NAME =
"url-map-alt"
62 URL_MAP_PATH_MATCHER_NAME =
"path-matcher"
63 TARGET_PROXY_NAME =
"target-proxy"
64 ALTERNATIVE_TARGET_PROXY_NAME =
"target-proxy-alt"
65 FORWARDING_RULE_NAME =
"forwarding-rule"
66 ALTERNATIVE_FORWARDING_RULE_NAME =
"forwarding-rule-alt"
67 FIREWALL_RULE_NAME =
"allow-health-checks"
71 gcp_api_manager: gcp.api.GcpApiManager,
76 network: str =
'default',
77 compute_api_version: str =
'v1',
82 version=compute_api_version)
85 self.project: str = project
86 self.network: str = network
87 self.resource_prefix: str = resource_prefix
88 self.resource_suffix: str = resource_suffix
95 self.
url_map: Optional[GcpResource] =
None
104 self.backends: Set[ZonalGcpResource] =
set()
108 BackendServiceProtocol] =
None
109 self.alternative_backends: Set[ZonalGcpResource] =
set()
113 BackendServiceProtocol] =
None
114 self.affinity_backends: Set[ZonalGcpResource] =
set()
118 return f
'global/networks/{self.network}'
125 backend_protocol: Optional[BackendServiceProtocol] = _BackendGRPC,
126 health_check_port: Optional[int] =
None):
128 health_check_port=health_check_port)
134 protocol: Optional[BackendServiceProtocol] = _BackendGRPC,
135 health_check_port: Optional[int] =
None):
158 @functools.lru_cache(
None)
160 """Make dash-separated resource name with resource prefix and suffix."""
161 parts = [self.resource_prefix, name]
163 if self.resource_suffix:
164 parts.append(self.resource_suffix)
165 return '-'.join(parts)
170 protocol: Optional[HealthCheckProtocol] = _HealthCheckGRPC,
171 port: Optional[int] =
None):
173 raise ValueError(f
'Health check {self.health_check.name} '
174 'already created, delete it first')
176 protocol = _HealthCheckGRPC
179 logger.info(
'Creating %s Health Check "%s"', protocol.name, name)
190 logger.info(
'Deleting Health Check "%s"', name)
196 protocol: Optional[BackendServiceProtocol] = _BackendGRPC,
197 subset_size: Optional[int] =
None,
198 affinity_header: Optional[str] =
None,
199 locality_lb_policies: Optional[List[dict]] =
None):
201 protocol = _BackendGRPC
204 logger.info(
'Creating %s Backend Service "%s"', protocol.name, name)
205 resource = self.
compute.create_backend_service_traffic_director(
209 subset_size=subset_size,
210 affinity_header=affinity_header,
211 locality_lb_policies=locality_lb_policies)
217 resource = self.
compute.get_backend_service_traffic_director(name)
227 logger.info(
'Deleting Backend Service "%s"', name)
234 max_rate_per_endpoint: Optional[
236 logger.info(
'Waiting for Network Endpoint Groups to load endpoints.')
238 backend = self.
compute.wait_for_network_endpoint_group(name, zone)
239 logger.info(
'Loaded NEG "%s" in zone %s', backend.name,
241 self.backends.
add(backend)
245 logger.info(
'Waiting for Network Endpoint Groups to load endpoints.')
247 backend = self.
compute.wait_for_network_endpoint_group(name, zone)
248 logger.info(
'Loaded NEG "%s" in zone %s', backend.name,
250 self.backends.remove(backend)
254 self, max_rate_per_endpoint: Optional[int] =
None):
255 logging.info(
'Adding backends to Backend Service %s: %r',
259 max_rate_per_endpoint)
262 logging.info(
'Removing backends from Backend Service %s',
268 "Waiting for Backend Service %s to report all backends healthy %r",
274 self, protocol: Optional[BackendServiceProtocol] = _BackendGRPC):
276 protocol = _BackendGRPC
278 logger.info(
'Creating %s Alternative Backend Service "%s"',
280 resource = self.
compute.create_backend_service_traffic_director(
287 resource = self.
compute.get_backend_service_traffic_director(name)
298 logger.info(
'Deleting Alternative Backend Service "%s"', name)
303 logger.info(
'Waiting for Network Endpoint Groups to load endpoints.')
305 backend = self.
compute.wait_for_network_endpoint_group(name, zone)
306 logger.info(
'Loaded NEG "%s" in zone %s', backend.name,
308 self.alternative_backends.
add(backend)
312 logging.info(
'Adding backends to Backend Service %s: %r',
314 self.alternative_backends)
319 logging.info(
'Removing backends from Backend Service %s',
326 "Waiting for Backend Service %s to report all backends healthy %r",
332 self, protocol: Optional[BackendServiceProtocol] = _BackendGRPC):
334 protocol = _BackendGRPC
336 logger.info(
'Creating %s Affinity Backend Service "%s"', protocol.name,
338 resource = self.
compute.create_backend_service_traffic_director(
342 affinity_header=TEST_AFFINITY_METADATA_KEY)
348 resource = self.
compute.get_backend_service_traffic_director(name)
358 logger.info(
'Deleting Affinity Backend Service "%s"', name)
363 logger.info(
'Waiting for Network Endpoint Groups to load endpoints.')
365 backend = self.
compute.wait_for_network_endpoint_group(name, zone)
366 logger.info(
'Loaded NEG "%s" in zone %s', backend.name,
368 self.affinity_backends.
add(backend)
372 logging.info(
'Adding backends to Backend Service %s: %r',
378 logging.info(
'Removing backends from Backend Service %s',
385 "Waiting for Backend Service %s to report all backends healthy %r",
395 dst_default_backend_service: GcpResource,
396 dst_host_rule_match_backend_service: Optional[GcpResource] =
None,
398 if dst_host_rule_match_backend_service
is None:
399 dst_host_rule_match_backend_service = dst_default_backend_service
404 dst_default_backend_service.url,
407 'pathMatcher': matcher_name,
410 'name': matcher_name,
411 'defaultService': dst_host_rule_match_backend_service.url,
416 src_address = f
'{src_host}:{src_port}'
419 logger.info(
'Creating URL map "%s": %s -> %s', name, src_address,
428 backend_service: GcpResource):
429 src_address = f
'{src_host}:{src_port}'
432 logger.info(
'Patching URL map "%s": %s -> %s', name, src_address,
433 backend_service.name)
440 logger.info(
'Creating URL map: %s', url_map_body)
452 logger.info(
'Deleting URL Map "%s"', name)
460 backend_service: Optional[GcpResource] =
None) -> GcpResource:
462 src_address = f
'{src_host}:{src_port}'
464 if backend_service
is None:
466 logger.info(
'Creating alternative URL map "%s": %s -> %s', name,
467 src_address, backend_service.name)
481 logger.info(
'Deleting alternative URL Map "%s"', name)
488 target_proxy_type =
'GRPC'
489 create_proxy_fn = self.
compute.create_target_grpc_proxy
492 target_proxy_type =
'HTTP'
493 create_proxy_fn = self.
compute.create_target_http_proxy
496 raise TypeError(
'Unexpected backend service protocol')
498 logger.info(
'Creating target %s proxy "%s" to URL map %s', name,
499 target_proxy_type, self.
url_map.name)
509 logger.info(
'Deleting Target GRPC proxy "%s"', name)
521 logger.info(
'Deleting HTTP Target proxy "%s"', name)
530 'Creating alternative target GRPC proxy "%s" to URL map %s',
535 raise TypeError(
'Unexpected backend service protocol')
544 logger.info(
'Deleting alternative Target GRPC proxy "%s"', name)
553 attempts: int = 25) -> int:
554 for _
in range(attempts):
555 src_port = random.randint(lo, hi)
556 if not self.
compute.exists_forwarding_rule(src_port):
559 raise RuntimeError(
"Couldn't find unused forwarding rule port")
563 src_port =
int(src_port)
565 'Creating forwarding rule "%s" in network "%s": 0.0.0.0:%s -> %s',
580 logger.info(
'Deleting Forwarding rule "%s"', name)
586 ip_address=
'0.0.0.0'):
588 src_port =
int(src_port)
590 'Creating alternative forwarding rule "%s" in network "%s": %s:%s -> %s',
591 name, self.network, ip_address, src_port,
598 ip_address=ip_address)
610 logger.info(
'Deleting alternative Forwarding rule "%s"', name)
617 'Creating firewall rule "%s" in network "%s" with allowed ports %s',
618 name, self.network, allowed_ports)
620 name, self.
network_url, xds_flags.FIREWALL_SOURCE_RANGE.value,
625 """The firewall rule won't be automatically removed."""
632 logger.info(
'Deleting Firewall Rule "%s"', name)
639 GRPC_ROUTE_NAME =
"grpc-route"
642 netsvc: _NetworkServicesV1Alpha1
645 gcp_api_manager: gcp.api.GcpApiManager,
648 resource_prefix: str,
649 resource_suffix: Optional[str] =
None,
650 network: str =
'default',
651 compute_api_version: str =
'v1'):
654 resource_prefix=resource_prefix,
655 resource_suffix=resource_suffix,
657 compute_api_version=compute_api_version)
665 self.
mesh: Optional[Mesh] =
None
669 logger.info(
"Creating Mesh %s", name)
673 logger.debug(
"Loaded Mesh: %s", self.
mesh)
680 name = self.
mesh.name
683 logger.info(
'Deleting Mesh %s', name)
688 host = f
'{src_host}:{src_port}'
692 "meshes": [self.
mesh.url],
698 "serviceName": service_name
704 logger.info(
"Creating GrpcRoute %s", name)
707 logger.debug(
"Loaded GrpcRoute: %s", self.
grpc_route)
712 logger.info(
"Creating GrpcRoute %s", name)
715 logger.debug(
"Loaded GrpcRoute: %s", self.
grpc_route)
725 logger.info(
'Deleting GrpcRoute %s', name)
736 SERVER_TLS_POLICY_NAME =
"server-tls-policy"
737 CLIENT_TLS_POLICY_NAME =
"client-tls-policy"
738 AUTHZ_POLICY_NAME =
"authz-policy"
739 ENDPOINT_POLICY =
"endpoint-policy"
740 CERTIFICATE_PROVIDER_INSTANCE =
"google_cloud_private_spiffe"
742 netsec: _NetworkSecurityV1Beta1
743 netsvc: _NetworkServicesV1Beta1
747 gcp_api_manager: gcp.api.GcpApiManager,
750 resource_prefix: str,
751 resource_suffix: Optional[str] =
None,
752 network: str =
'default',
753 compute_api_version: str =
'v1',
757 resource_prefix=resource_prefix,
758 resource_suffix=resource_suffix,
760 compute_api_version=compute_api_version)
781 server_name=server_name,
782 server_port=server_port)
804 logger.info(
'Creating Server TLS Policy %s', name)
805 if not tls
and not mtls:
807 'Server TLS Policy %s neither TLS, nor mTLS '
808 'policy. Skipping creation', name)
814 policy[
"serverCertificate"] = certificate_provider
816 policy[
"mtlsPolicy"] = {
817 "clientValidationCa": [certificate_provider],
831 logger.info(
'Deleting Server TLS Policy %s', name)
837 logger.info(
'Creating Authz Policy %s', name)
845 logger.debug(
'Authz Policy loaded: %r', self.
authz_policy)
854 logger.info(
'Deleting Authz Policy %s', name)
859 server_port: int) ->
None:
861 logger.info(
'Creating Endpoint Policy %s', name)
862 endpoint_matcher_labels = [{
864 "labelValue": f
"{server_namespace}-{server_name}"
866 port_selector = {
"ports": [
str(server_port)]}
867 label_matcher_all = {
868 "metadataLabelMatchCriteria":
"MATCH_ALL",
869 "metadataLabels": endpoint_matcher_labels,
872 "type":
"GRPC_SERVER",
873 "trafficPortSelector": port_selector,
875 "metadataLabelMatcher": label_matcher_all,
882 'Creating Endpoint Policy %s with '
883 'no Server TLS policy attached', name)
898 logger.info(
'Deleting Endpoint Policy %s', name)
904 logger.info(
'Creating Client TLS Policy %s', name)
905 if not tls
and not mtls:
907 'Client TLS Policy %s neither TLS, nor mTLS '
908 'policy. Skipping creation', name)
914 policy[
"serverValidationCa"] = [certificate_provider]
916 policy[
"clientCertificate"] = certificate_provider
929 logger.info(
'Deleting Client TLS Policy %s', name)
940 'Client TLS policy not created, '
941 'skipping attaching to Backend Service %s',
945 server_spiffe = (f
'spiffe://{self.project}.svc.id.goog/'
946 f
'ns/{server_namespace}/sa/{server_name}')
948 'Adding Client TLS Policy to Backend Service %s: %s, '
954 'securitySettings': {
956 'subjectAltNames': [server_spiffe]
963 "certificateProviderInstance": {