|
|
|
@ -50,7 +50,8 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
HTTP2 = enum.auto() |
|
|
|
|
GRPC = enum.auto() |
|
|
|
|
|
|
|
|
|
def create_health_check_tcp(self, name, |
|
|
|
|
def create_health_check_tcp(self, |
|
|
|
|
name, |
|
|
|
|
use_serving_port=False) -> GcpResource: |
|
|
|
|
health_check_settings = {} |
|
|
|
|
if use_serving_port: |
|
|
|
@ -66,30 +67,31 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
self._delete_resource(self.api.healthChecks(), healthCheck=name) |
|
|
|
|
|
|
|
|
|
def create_backend_service_traffic_director( |
|
|
|
|
self, |
|
|
|
|
name: str, |
|
|
|
|
health_check: GcpResource, |
|
|
|
|
protocol: Optional[BackendServiceProtocol] = None |
|
|
|
|
) -> GcpResource: |
|
|
|
|
self, |
|
|
|
|
name: str, |
|
|
|
|
health_check: GcpResource, |
|
|
|
|
protocol: Optional[BackendServiceProtocol] = None) -> GcpResource: |
|
|
|
|
if not isinstance(protocol, self.BackendServiceProtocol): |
|
|
|
|
raise TypeError(f'Unexpected Backend Service protocol: {protocol}') |
|
|
|
|
return self._insert_resource(self.api.backendServices(), { |
|
|
|
|
'name': name, |
|
|
|
|
'loadBalancingScheme': 'INTERNAL_SELF_MANAGED', # Traffic Director |
|
|
|
|
'healthChecks': [health_check.url], |
|
|
|
|
'protocol': protocol.name, |
|
|
|
|
}) |
|
|
|
|
return self._insert_resource( |
|
|
|
|
self.api.backendServices(), |
|
|
|
|
{ |
|
|
|
|
'name': name, |
|
|
|
|
'loadBalancingScheme': |
|
|
|
|
'INTERNAL_SELF_MANAGED', # Traffic Director |
|
|
|
|
'healthChecks': [health_check.url], |
|
|
|
|
'protocol': protocol.name, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
def get_backend_service_traffic_director(self, name: str) -> GcpResource: |
|
|
|
|
return self._get_resource(self.api.backendServices(), |
|
|
|
|
backendService=name) |
|
|
|
|
|
|
|
|
|
def patch_backend_service(self, backend_service, body, **kwargs): |
|
|
|
|
self._patch_resource( |
|
|
|
|
collection=self.api.backendServices(), |
|
|
|
|
backendService=backend_service.name, |
|
|
|
|
body=body, |
|
|
|
|
**kwargs) |
|
|
|
|
self._patch_resource(collection=self.api.backendServices(), |
|
|
|
|
backendService=backend_service.name, |
|
|
|
|
body=body, |
|
|
|
|
**kwargs) |
|
|
|
|
|
|
|
|
|
def backend_service_add_backends(self, backend_service, backends): |
|
|
|
|
backend_list = [{ |
|
|
|
@ -98,16 +100,14 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
'maxRatePerEndpoint': 5 |
|
|
|
|
} for backend in backends] |
|
|
|
|
|
|
|
|
|
self._patch_resource( |
|
|
|
|
collection=self.api.backendServices(), |
|
|
|
|
body={'backends': backend_list}, |
|
|
|
|
backendService=backend_service.name) |
|
|
|
|
self._patch_resource(collection=self.api.backendServices(), |
|
|
|
|
body={'backends': backend_list}, |
|
|
|
|
backendService=backend_service.name) |
|
|
|
|
|
|
|
|
|
def backend_service_remove_all_backends(self, backend_service): |
|
|
|
|
self._patch_resource( |
|
|
|
|
collection=self.api.backendServices(), |
|
|
|
|
body={'backends': []}, |
|
|
|
|
backendService=backend_service.name) |
|
|
|
|
self._patch_resource(collection=self.api.backendServices(), |
|
|
|
|
body={'backends': []}, |
|
|
|
|
backendService=backend_service.name) |
|
|
|
|
|
|
|
|
|
def delete_backend_service(self, name): |
|
|
|
|
self._delete_resource(self.api.backendServices(), backendService=name) |
|
|
|
@ -122,18 +122,21 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
) -> GcpResource: |
|
|
|
|
if dst_host_rule_match_backend_service is None: |
|
|
|
|
dst_host_rule_match_backend_service = dst_default_backend_service |
|
|
|
|
return self._insert_resource(self.api.urlMaps(), { |
|
|
|
|
'name': name, |
|
|
|
|
'defaultService': dst_default_backend_service.url, |
|
|
|
|
'hostRules': [{ |
|
|
|
|
'hosts': src_hosts, |
|
|
|
|
'pathMatcher': matcher_name, |
|
|
|
|
}], |
|
|
|
|
'pathMatchers': [{ |
|
|
|
|
'name': matcher_name, |
|
|
|
|
'defaultService': dst_host_rule_match_backend_service.url, |
|
|
|
|
}], |
|
|
|
|
}) |
|
|
|
|
return self._insert_resource( |
|
|
|
|
self.api.urlMaps(), { |
|
|
|
|
'name': |
|
|
|
|
name, |
|
|
|
|
'defaultService': |
|
|
|
|
dst_default_backend_service.url, |
|
|
|
|
'hostRules': [{ |
|
|
|
|
'hosts': src_hosts, |
|
|
|
|
'pathMatcher': matcher_name, |
|
|
|
|
}], |
|
|
|
|
'pathMatchers': [{ |
|
|
|
|
'name': matcher_name, |
|
|
|
|
'defaultService': dst_host_rule_match_backend_service.url, |
|
|
|
|
}], |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
def delete_url_map(self, name): |
|
|
|
|
self._delete_resource(self.api.urlMaps(), urlMap=name) |
|
|
|
@ -174,14 +177,17 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
target_proxy: GcpResource, |
|
|
|
|
network_url: str, |
|
|
|
|
) -> GcpResource: |
|
|
|
|
return self._insert_resource(self.api.globalForwardingRules(), { |
|
|
|
|
'name': name, |
|
|
|
|
'loadBalancingScheme': 'INTERNAL_SELF_MANAGED', # Traffic Director |
|
|
|
|
'portRange': src_port, |
|
|
|
|
'IPAddress': '0.0.0.0', |
|
|
|
|
'network': network_url, |
|
|
|
|
'target': target_proxy.url, |
|
|
|
|
}) |
|
|
|
|
return self._insert_resource( |
|
|
|
|
self.api.globalForwardingRules(), |
|
|
|
|
{ |
|
|
|
|
'name': name, |
|
|
|
|
'loadBalancingScheme': |
|
|
|
|
'INTERNAL_SELF_MANAGED', # Traffic Director |
|
|
|
|
'portRange': src_port, |
|
|
|
|
'IPAddress': '0.0.0.0', |
|
|
|
|
'network': network_url, |
|
|
|
|
'target': target_proxy.url, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
def delete_forwarding_rule(self, name): |
|
|
|
|
self._delete_resource(self.api.globalForwardingRules(), |
|
|
|
@ -192,15 +198,16 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
return not neg or neg.get('size', 0) == 0 |
|
|
|
|
|
|
|
|
|
def wait_for_network_endpoint_group(self, name, zone): |
|
|
|
|
|
|
|
|
|
@retrying.retry(retry_on_result=self._network_endpoint_group_not_ready, |
|
|
|
|
stop_max_delay=60 * 1000, |
|
|
|
|
wait_fixed=2 * 1000) |
|
|
|
|
def _wait_for_network_endpoint_group_ready(): |
|
|
|
|
try: |
|
|
|
|
neg = self.get_network_endpoint_group(name, zone) |
|
|
|
|
logger.debug('Waiting for endpoints: NEG %s in zone %s, ' |
|
|
|
|
'current count %s', |
|
|
|
|
neg['name'], zone, neg.get('size')) |
|
|
|
|
logger.debug( |
|
|
|
|
'Waiting for endpoints: NEG %s in zone %s, ' |
|
|
|
|
'current count %s', neg['name'], zone, neg.get('size')) |
|
|
|
|
except googleapiclient.errors.HttpError as error: |
|
|
|
|
# noinspection PyProtectedMember |
|
|
|
|
reason = error._get_reason() |
|
|
|
@ -211,10 +218,8 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
|
|
|
|
|
network_endpoint_group = _wait_for_network_endpoint_group_ready() |
|
|
|
|
# @todo(sergiitk): dataclass |
|
|
|
|
return self.ZonalGcpResource( |
|
|
|
|
network_endpoint_group['name'], |
|
|
|
|
network_endpoint_group['selfLink'], |
|
|
|
|
zone) |
|
|
|
|
return self.ZonalGcpResource(network_endpoint_group['name'], |
|
|
|
|
network_endpoint_group['selfLink'], zone) |
|
|
|
|
|
|
|
|
|
def get_network_endpoint_group(self, name, zone): |
|
|
|
|
neg = self.api.networkEndpointGroups().get(project=self.project, |
|
|
|
@ -232,10 +237,9 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
): |
|
|
|
|
pending = set(backends) |
|
|
|
|
|
|
|
|
|
@retrying.retry( |
|
|
|
|
retry_on_result=lambda result: not result, |
|
|
|
|
stop_max_delay=timeout_sec * 1000, |
|
|
|
|
wait_fixed=wait_sec * 1000) |
|
|
|
|
@retrying.retry(retry_on_result=lambda result: not result, |
|
|
|
|
stop_max_delay=timeout_sec * 1000, |
|
|
|
|
wait_fixed=wait_sec * 1000) |
|
|
|
|
def _retry_backends_health(): |
|
|
|
|
for backend in pending: |
|
|
|
|
result = self.get_backend_service_backend_health( |
|
|
|
@ -250,9 +254,8 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
for instance in result['healthStatus']: |
|
|
|
|
logger.debug( |
|
|
|
|
'Backend %s in zone %s: instance %s:%s health: %s', |
|
|
|
|
backend.name, backend.zone, |
|
|
|
|
instance['ipAddress'], instance['port'], |
|
|
|
|
instance['healthState']) |
|
|
|
|
backend.name, backend.zone, instance['ipAddress'], |
|
|
|
|
instance['port'], instance['healthState']) |
|
|
|
|
if instance['healthState'] != 'HEALTHY': |
|
|
|
|
backend_healthy = False |
|
|
|
|
|
|
|
|
@ -267,8 +270,11 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
|
|
|
|
|
def get_backend_service_backend_health(self, backend_service, backend): |
|
|
|
|
return self.api.backendServices().getHealth( |
|
|
|
|
project=self.project, backendService=backend_service.name, |
|
|
|
|
body={"group": backend.url}).execute() |
|
|
|
|
project=self.project, |
|
|
|
|
backendService=backend_service.name, |
|
|
|
|
body={ |
|
|
|
|
"group": backend.url |
|
|
|
|
}).execute() |
|
|
|
|
|
|
|
|
|
def _get_resource(self, collection: discovery.Resource, |
|
|
|
|
**kwargs) -> GcpResource: |
|
|
|
@ -276,11 +282,8 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
logger.debug("Loaded %r", resp) |
|
|
|
|
return self.GcpResource(resp['name'], resp['selfLink']) |
|
|
|
|
|
|
|
|
|
def _insert_resource( |
|
|
|
|
self, |
|
|
|
|
collection: discovery.Resource, |
|
|
|
|
body: Dict[str, Any] |
|
|
|
|
) -> GcpResource: |
|
|
|
|
def _insert_resource(self, collection: discovery.Resource, |
|
|
|
|
body: Dict[str, Any]) -> GcpResource: |
|
|
|
|
logger.debug("Creating %s", body) |
|
|
|
|
resp = self._execute(collection.insert(project=self.project, body=body)) |
|
|
|
|
return self.GcpResource(body['name'], resp['targetLink']) |
|
|
|
@ -297,14 +300,16 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
except googleapiclient.errors.HttpError as error: |
|
|
|
|
# noinspection PyProtectedMember |
|
|
|
|
reason = error._get_reason() |
|
|
|
|
logger.info('Delete failed. Error: %s %s', |
|
|
|
|
error.resp.status, reason) |
|
|
|
|
logger.info('Delete failed. Error: %s %s', error.resp.status, |
|
|
|
|
reason) |
|
|
|
|
|
|
|
|
|
@staticmethod |
|
|
|
|
def _operation_status_done(operation): |
|
|
|
|
return 'status' in operation and operation['status'] == 'DONE' |
|
|
|
|
|
|
|
|
|
def _execute(self, request, *, |
|
|
|
|
def _execute(self, |
|
|
|
|
request, |
|
|
|
|
*, |
|
|
|
|
test_success_fn=None, |
|
|
|
|
timeout_sec=_WAIT_FOR_OPERATION_SEC): |
|
|
|
|
operation = request.execute(num_retries=self._GCP_API_RETRIES) |
|
|
|
@ -320,10 +325,9 @@ class ComputeV1(gcp.api.GcpProjectApiResource): |
|
|
|
|
|
|
|
|
|
logger.debug('Waiting for global operation %s, timeout %s sec', |
|
|
|
|
operation['name'], timeout_sec) |
|
|
|
|
response = self.wait_for_operation( |
|
|
|
|
operation_request=operation_request, |
|
|
|
|
test_success_fn=test_success_fn, |
|
|
|
|
timeout_sec=timeout_sec) |
|
|
|
|
response = self.wait_for_operation(operation_request=operation_request, |
|
|
|
|
test_success_fn=test_success_fn, |
|
|
|
|
timeout_sec=timeout_sec) |
|
|
|
|
|
|
|
|
|
if 'error' in response: |
|
|
|
|
logger.debug('Waiting for global operation failed, response: %r', |
|
|
|
|