gcpdiag.queries.lb

Queries related to load balancer.
class LoadBalancerType(enum.Enum):
28class LoadBalancerType(Enum):
29  """Load balancer type."""
30
31  LOAD_BALANCER_TYPE_UNSPECIFIED = 0
32  EXTERNAL_PASSTHROUGH_LB = 1
33  INTERNAL_PASSTHROUGH_LB = 2
34  TARGET_POOL_LB = 3  # deprecated but customers still have them
35  GLOBAL_EXTERNAL_PROXY_NETWORK_LB = 4  # envoy based proxy lb
36  REGIONAL_INTERNAL_PROXY_NETWORK_LB = 5
37  REGIONAL_EXTERNAL_PROXY_NETWORK_LB = 6
38  CROSS_REGION_INTERNAL_PROXY_NETWORK_LB = 7
39  CLASSIC_PROXY_NETWORK_LB = 8
40  GLOBAL_EXTERNAL_APPLICATION_LB = 9  # envoy based application lb
41  REGIONAL_INTERNAL_APPLICATION_LB = 10
42  REGIONAL_EXTERNAL_APPLICATION_LB = 11
43  CROSS_REGION_INTERNAL_APPLICATION_LB = 12
44  CLASSIC_APPLICATION_LB = 13

Load balancer type.

LOAD_BALANCER_TYPE_UNSPECIFIED = <LoadBalancerType.LOAD_BALANCER_TYPE_UNSPECIFIED: 0>
EXTERNAL_PASSTHROUGH_LB = <LoadBalancerType.EXTERNAL_PASSTHROUGH_LB: 1>
INTERNAL_PASSTHROUGH_LB = <LoadBalancerType.INTERNAL_PASSTHROUGH_LB: 2>
TARGET_POOL_LB = <LoadBalancerType.TARGET_POOL_LB: 3>
GLOBAL_EXTERNAL_PROXY_NETWORK_LB = <LoadBalancerType.GLOBAL_EXTERNAL_PROXY_NETWORK_LB: 4>
REGIONAL_INTERNAL_PROXY_NETWORK_LB = <LoadBalancerType.REGIONAL_INTERNAL_PROXY_NETWORK_LB: 5>
REGIONAL_EXTERNAL_PROXY_NETWORK_LB = <LoadBalancerType.REGIONAL_EXTERNAL_PROXY_NETWORK_LB: 6>
CROSS_REGION_INTERNAL_PROXY_NETWORK_LB = <LoadBalancerType.CROSS_REGION_INTERNAL_PROXY_NETWORK_LB: 7>
CLASSIC_PROXY_NETWORK_LB = <LoadBalancerType.CLASSIC_PROXY_NETWORK_LB: 8>
GLOBAL_EXTERNAL_APPLICATION_LB = <LoadBalancerType.GLOBAL_EXTERNAL_APPLICATION_LB: 9>
REGIONAL_INTERNAL_APPLICATION_LB = <LoadBalancerType.REGIONAL_INTERNAL_APPLICATION_LB: 10>
REGIONAL_EXTERNAL_APPLICATION_LB = <LoadBalancerType.REGIONAL_EXTERNAL_APPLICATION_LB: 11>
CROSS_REGION_INTERNAL_APPLICATION_LB = <LoadBalancerType.CROSS_REGION_INTERNAL_APPLICATION_LB: 12>
CLASSIC_APPLICATION_LB = <LoadBalancerType.CLASSIC_APPLICATION_LB: 13>
def get_load_balancer_type_name(lb_type: LoadBalancerType) -> str:
47def get_load_balancer_type_name(lb_type: LoadBalancerType) -> str:
48  """Returns a human-readable name for the given load balancer type."""
49
50  type_names = {
51      LoadBalancerType.LOAD_BALANCER_TYPE_UNSPECIFIED:
52          'Unspecified',
53      LoadBalancerType.EXTERNAL_PASSTHROUGH_LB:
54          ('External Passthrough Network Load Balancer'),
55      LoadBalancerType.INTERNAL_PASSTHROUGH_LB:
56          ('Internal Passthrough Network Load Balancer'),
57      LoadBalancerType.TARGET_POOL_LB:
58          'Target Pool Network Load Balancer',
59      LoadBalancerType.GLOBAL_EXTERNAL_PROXY_NETWORK_LB:
60          ('Global External Proxy Network Load Balancer'),
61      LoadBalancerType.REGIONAL_INTERNAL_PROXY_NETWORK_LB:
62          ('Regional Internal Proxy Network Load Balancer'),
63      LoadBalancerType.REGIONAL_EXTERNAL_PROXY_NETWORK_LB:
64          ('Regional External Proxy Network Load Balancer'),
65      LoadBalancerType.CROSS_REGION_INTERNAL_PROXY_NETWORK_LB:
66          ('Cross-Region Internal Proxy Network Load Balancer'),
67      LoadBalancerType.CLASSIC_PROXY_NETWORK_LB:
68          ('Classic Proxy Network Load Balancer'),
69      LoadBalancerType.GLOBAL_EXTERNAL_APPLICATION_LB:
70          ('Global External Application Load Balancer'),
71      LoadBalancerType.REGIONAL_INTERNAL_APPLICATION_LB:
72          ('Regional Internal Application Load Balancer'),
73      LoadBalancerType.REGIONAL_EXTERNAL_APPLICATION_LB:
74          ('Regional External Application Load Balancer'),
75      LoadBalancerType.CROSS_REGION_INTERNAL_APPLICATION_LB:
76          ('Cross-Region Internal Application Load Balancer'),
77      LoadBalancerType.CLASSIC_APPLICATION_LB:
78          ('Classic Application Load Balancer'),
79  }
80  return type_names.get(lb_type, 'Unspecified')

Returns a human-readable name for the given load balancer type.

def get_load_balancer_type( load_balancing_scheme: str, scope: str, layer: Literal['application', 'network'], backend_service_based: bool = True) -> LoadBalancerType:
 83def get_load_balancer_type(
 84    load_balancing_scheme: str,
 85    scope: str,
 86    layer: Literal['application', 'network'],
 87    backend_service_based: bool = True,
 88) -> LoadBalancerType:
 89  if load_balancing_scheme == 'EXTERNAL':
 90    if not scope or scope == 'global':
 91      if layer == 'application':
 92        return LoadBalancerType.CLASSIC_APPLICATION_LB
 93      else:
 94        return LoadBalancerType.CLASSIC_PROXY_NETWORK_LB
 95    else:
 96      return (LoadBalancerType.EXTERNAL_PASSTHROUGH_LB
 97              if backend_service_based else LoadBalancerType.TARGET_POOL_LB)
 98  elif load_balancing_scheme == 'INTERNAL':
 99    return LoadBalancerType.INTERNAL_PASSTHROUGH_LB
100  elif load_balancing_scheme == 'INTERNAL_MANAGED':
101    if not scope or scope == 'global':
102      if layer == 'application':
103        return LoadBalancerType.CROSS_REGION_INTERNAL_APPLICATION_LB
104      else:
105        return LoadBalancerType.CROSS_REGION_INTERNAL_PROXY_NETWORK_LB
106    else:
107      if layer == 'application':
108        return LoadBalancerType.REGIONAL_INTERNAL_APPLICATION_LB
109      else:
110        return LoadBalancerType.REGIONAL_INTERNAL_PROXY_NETWORK_LB
111  elif load_balancing_scheme == 'EXTERNAL_MANAGED':
112    if not scope or scope == 'global':
113      if layer == 'application':
114        return LoadBalancerType.GLOBAL_EXTERNAL_APPLICATION_LB
115      else:
116        return LoadBalancerType.GLOBAL_EXTERNAL_PROXY_NETWORK_LB
117    else:
118      if layer == 'application':
119        return LoadBalancerType.REGIONAL_EXTERNAL_APPLICATION_LB
120      else:
121        return LoadBalancerType.REGIONAL_EXTERNAL_PROXY_NETWORK_LB
122  return LoadBalancerType.LOAD_BALANCER_TYPE_UNSPECIFIED
def normalize_url(url: str) -> str:
125def normalize_url(url: str) -> str:
126  """Returns normalized url."""
127  result = re.match(r'https://www.googleapis.com/compute/v1/(.*)', url)
128  if result:
129    return result.group(1)
130  else:
131    return ''

Returns normalized url.

class BackendServices(gcpdiag.models.Resource):
134class BackendServices(models.Resource):
135  """A Backend Service resource."""
136
137  _resource_data: dict
138  _type: str
139
140  def __init__(self, project_id, resource_data):
141    super().__init__(project_id=project_id)
142    self._resource_data = resource_data
143
144  @property
145  def name(self) -> str:
146    return self._resource_data['name']
147
148  @property
149  def id(self) -> str:
150    return self._resource_data['id']
151
152  @property
153  def full_path(self) -> str:
154    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
155                      self.self_link)
156    if result:
157      return result.group(1)
158    else:
159      return f'>> {self.self_link}'
160
161  @property
162  def short_path(self) -> str:
163    path = self.project_id + '/' + self.name
164    return path
165
166  @property
167  def self_link(self) -> str:
168    return self._resource_data['selfLink']
169
170  @property
171  def session_affinity(self) -> str:
172    return self._resource_data.get('sessionAffinity', 'NONE')
173
174  @property
175  def timeout_sec(self) -> int:
176    return self._resource_data.get('timeoutSec', None)
177
178  @property
179  def locality_lb_policy(self) -> str:
180    return self._resource_data.get('localityLbPolicy', 'ROUND_ROBIN')
181
182  @property
183  def is_enable_cdn(self) -> str:
184    return self._resource_data.get('enableCDN', False)
185
186  @property
187  def load_balancing_scheme(self) -> str:
188    return self._resource_data.get('loadBalancingScheme', None)
189
190  @property
191  def health_check(self) -> str:
192    health_check_url = self._resource_data['healthChecks'][0]
193    matches = re.search(r'/([^/]+)$', health_check_url)
194    if matches:
195      healthcheck_name = matches.group(1)
196      return healthcheck_name
197    else:
198      return ''
199
200  @property
201  def backends(self) -> List[dict]:
202    return self._resource_data.get('backends', [])
203
204  @property
205  def region(self):
206    try:
207      url = self._resource_data.get('region')
208      if url is not None:
209        match = re.search(r'/([^/]+)/?$', url)
210        if match is not None:
211          region = match.group(1)
212          return region
213        else:
214          return None
215    except KeyError:
216      return None
217
218  @property
219  def protocol(self) -> str:
220    return self._resource_data.get('protocol', None)
221
222  @property
223  def used_by_refs(self) -> List[str]:
224    used_by = []
225    for x in self._resource_data.get('usedBy', []):
226      reference = x.get('reference')
227      if reference:
228        match = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
229                         reference)
230        if match:
231          used_by.append(match.group(1))
232    return used_by
233
234  @property
235  def load_balancer_type(self) -> LoadBalancerType:
236    application_protocols = ['HTTP', 'HTTPS', 'HTTP2']
237    return get_load_balancer_type(
238        self.load_balancing_scheme,
239        self.region,
240        'application' if self.protocol in application_protocols else 'network',
241        backend_service_based=True,
242    )

A Backend Service resource.

BackendServices(project_id, resource_data)
140  def __init__(self, project_id, resource_data):
141    super().__init__(project_id=project_id)
142    self._resource_data = resource_data
name: str
144  @property
145  def name(self) -> str:
146    return self._resource_data['name']
id: str
148  @property
149  def id(self) -> str:
150    return self._resource_data['id']
full_path: str
152  @property
153  def full_path(self) -> str:
154    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
155                      self.self_link)
156    if result:
157      return result.group(1)
158    else:
159      return f'>> {self.self_link}'

Returns the full path of this resource.

Example: 'projects/gcpdiag-gke-1-9b90/zones/europe-west4-a/clusters/gke1'

short_path: str
161  @property
162  def short_path(self) -> str:
163    path = self.project_id + '/' + self.name
164    return path

Returns the short name for this resource.

Note that it isn't clear from this name what kind of resource it is.

Example: 'gke1'

session_affinity: str
170  @property
171  def session_affinity(self) -> str:
172    return self._resource_data.get('sessionAffinity', 'NONE')
timeout_sec: int
174  @property
175  def timeout_sec(self) -> int:
176    return self._resource_data.get('timeoutSec', None)
locality_lb_policy: str
178  @property
179  def locality_lb_policy(self) -> str:
180    return self._resource_data.get('localityLbPolicy', 'ROUND_ROBIN')
is_enable_cdn: str
182  @property
183  def is_enable_cdn(self) -> str:
184    return self._resource_data.get('enableCDN', False)
load_balancing_scheme: str
186  @property
187  def load_balancing_scheme(self) -> str:
188    return self._resource_data.get('loadBalancingScheme', None)
health_check: str
190  @property
191  def health_check(self) -> str:
192    health_check_url = self._resource_data['healthChecks'][0]
193    matches = re.search(r'/([^/]+)$', health_check_url)
194    if matches:
195      healthcheck_name = matches.group(1)
196      return healthcheck_name
197    else:
198      return ''
backends: List[dict]
200  @property
201  def backends(self) -> List[dict]:
202    return self._resource_data.get('backends', [])
region
204  @property
205  def region(self):
206    try:
207      url = self._resource_data.get('region')
208      if url is not None:
209        match = re.search(r'/([^/]+)/?$', url)
210        if match is not None:
211          region = match.group(1)
212          return region
213        else:
214          return None
215    except KeyError:
216      return None
protocol: str
218  @property
219  def protocol(self) -> str:
220    return self._resource_data.get('protocol', None)
used_by_refs: List[str]
222  @property
223  def used_by_refs(self) -> List[str]:
224    used_by = []
225    for x in self._resource_data.get('usedBy', []):
226      reference = x.get('reference')
227      if reference:
228        match = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
229                         reference)
230        if match:
231          used_by.append(match.group(1))
232    return used_by
load_balancer_type: LoadBalancerType
234  @property
235  def load_balancer_type(self) -> LoadBalancerType:
236    application_protocols = ['HTTP', 'HTTPS', 'HTTP2']
237    return get_load_balancer_type(
238        self.load_balancing_scheme,
239        self.region,
240        'application' if self.protocol in application_protocols else 'network',
241        backend_service_based=True,
242    )
@caching.cached_api_call(in_memory=True)
def get_backend_services(project_id: str) -> List[BackendServices]:
245@caching.cached_api_call(in_memory=True)
246def get_backend_services(project_id: str) -> List[BackendServices]:
247  logging.info('fetching Backend Services: %s', project_id)
248  compute = apis.get_api('compute', 'v1', project_id)
249  backend_services = []
250  request = compute.backendServices().aggregatedList(project=project_id)
251  response = request.execute(num_retries=config.API_RETRIES)
252  backend_services_by_region = response['items']
253  for _, data_ in backend_services_by_region.items():
254    if 'backendServices' not in data_:
255      continue
256    backend_services.extend([
257        BackendServices(project_id, backend_service)
258        for backend_service in data_['backendServices']
259    ])
260  return backend_services
@caching.cached_api_call(in_memory=True)
def get_backend_service( project_id: str, backend_service_name: str, region: str = None) -> BackendServices:
263@caching.cached_api_call(in_memory=True)
264def get_backend_service(project_id: str,
265                        backend_service_name: str,
266                        region: str = None) -> BackendServices:
267  """Returns instance object matching backend service name and region"""
268  compute = apis.get_api('compute', 'v1', project_id)
269  if not region or region == 'global':
270    request = compute.backendServices().get(project=project_id,
271                                            backendService=backend_service_name)
272  else:
273    request = compute.regionBackendServices().get(
274        project=project_id, region=region, backendService=backend_service_name)
275
276  response = request.execute(num_retries=config.API_RETRIES)
277  return BackendServices(project_id, resource_data=response)

Returns instance object matching backend service name and region

class BackendHealth:
292class BackendHealth:
293  """A Backend Service resource."""
294
295  _resource_data: dict
296
297  def __init__(self, resource_data, group):
298    self._resource_data = resource_data
299    self._group = group
300
301  @property
302  def instance(self) -> str:
303    return self._resource_data['instance']
304
305  @property
306  def group(self) -> str:
307    return self._group
308
309  @property
310  def health_state(self) -> str:
311    return self._resource_data.get('healthState', 'UNHEALTHY')

A Backend Service resource.

BackendHealth(resource_data, group)
297  def __init__(self, resource_data, group):
298    self._resource_data = resource_data
299    self._group = group
instance: str
301  @property
302  def instance(self) -> str:
303    return self._resource_data['instance']
group: str
305  @property
306  def group(self) -> str:
307    return self._group
health_state: str
309  @property
310  def health_state(self) -> str:
311    return self._resource_data.get('healthState', 'UNHEALTHY')
@caching.cached_api_call(in_memory=True)
def get_backend_service_health( project_id: str, backend_service_name: str, backend_service_region: str = None) -> List[BackendHealth]:
328@caching.cached_api_call(in_memory=True)
329def get_backend_service_health(
330    project_id: str,
331    backend_service_name: str,
332    backend_service_region: str = None,
333) -> List[BackendHealth]:
334  """Returns health data for backend service."""
335  try:
336    backend_service = get_backend_service(project_id, backend_service_name,
337                                          backend_service_region)
338  except googleapiclient.errors.HttpError:
339    return []
340
341  backend_heath_statuses: List[BackendHealth] = []
342
343  compute = apis.get_api('compute', 'v1', project_id)
344  batch = compute.new_batch_http_request()
345
346  for i, backend in enumerate(backend_service.backends):
347    group = backend['group']
348    if not backend_service.region:
349      batch.add(
350          compute.backendServices().getHealth(
351              project=project_id,
352              backendService=backend_service.name,
353              body={'group': group},
354          ),
355          request_id=str(i),
356          callback=_generate_health_response_callback(backend_heath_statuses,
357                                                      group),
358      )
359    else:
360      batch.add(
361          compute.regionBackendServices().getHealth(
362              project=project_id,
363              region=backend_service.region,
364              backendService=backend_service.name,
365              body={'group': group},
366          ),
367          request_id=str(i),
368          callback=_generate_health_response_callback(backend_heath_statuses,
369                                                      group),
370      )
371  batch.execute()
372
373  return backend_heath_statuses

Returns health data for backend service.

class SslCertificate(gcpdiag.models.Resource):
376class SslCertificate(models.Resource):
377  """A SSL Certificate resource."""
378
379  _resource_data: dict
380  _type: str
381
382  def __init__(self, project_id, resource_data):
383    super().__init__(project_id=project_id)
384    self._resource_data = resource_data
385
386  @property
387  def name(self) -> str:
388    return self._resource_data['name']
389
390  @property
391  def id(self) -> str:
392    return self._resource_data['id']
393
394  @property
395  def full_path(self) -> str:
396    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
397                      self.self_link)
398    if result:
399      return result.group(1)
400    else:
401      return f'>> {self.self_link}'
402
403  @property
404  def self_link(self) -> str:
405    return self._resource_data['selfLink']
406
407  @property
408  def type(self) -> str:
409    return self._resource_data.get('type', 'SELF_MANAGED')
410
411  @property
412  def status(self) -> str:
413    return self._resource_data.get('managed', {}).get('status')
414
415  @property
416  def domains(self) -> List[str]:
417    return self._resource_data.get('managed', {}).get('domains', [])
418
419  @property
420  def domain_status(self) -> Dict[str, str]:
421    return self._resource_data.get('managed', {}).get('domainStatus', {})

A SSL Certificate resource.

SslCertificate(project_id, resource_data)
382  def __init__(self, project_id, resource_data):
383    super().__init__(project_id=project_id)
384    self._resource_data = resource_data
name: str
386  @property
387  def name(self) -> str:
388    return self._resource_data['name']
id: str
390  @property
391  def id(self) -> str:
392    return self._resource_data['id']
full_path: str
394  @property
395  def full_path(self) -> str:
396    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
397                      self.self_link)
398    if result:
399      return result.group(1)
400    else:
401      return f'>> {self.self_link}'

Returns the full path of this resource.

Example: 'projects/gcpdiag-gke-1-9b90/zones/europe-west4-a/clusters/gke1'

type: str
407  @property
408  def type(self) -> str:
409    return self._resource_data.get('type', 'SELF_MANAGED')
status: str
411  @property
412  def status(self) -> str:
413    return self._resource_data.get('managed', {}).get('status')
domains: List[str]
415  @property
416  def domains(self) -> List[str]:
417    return self._resource_data.get('managed', {}).get('domains', [])
domain_status: Dict[str, str]
419  @property
420  def domain_status(self) -> Dict[str, str]:
421    return self._resource_data.get('managed', {}).get('domainStatus', {})
@caching.cached_api_call(in_memory=True)
def get_ssl_certificate( project_id: str, certificate_name: str) -> SslCertificate:
424@caching.cached_api_call(in_memory=True)
425def get_ssl_certificate(
426    project_id: str,
427    certificate_name: str,
428) -> SslCertificate:
429  """Returns object matching certificate name and region"""
430  compute = apis.get_api('compute', 'v1', project_id)
431
432  request = compute.sslCertificates().get(project=project_id,
433                                          sslCertificate=certificate_name)
434
435  response = request.execute(num_retries=config.API_RETRIES)
436  return SslCertificate(project_id, resource_data=response)

Returns object matching certificate name and region

class ForwardingRules(gcpdiag.models.Resource):
439class ForwardingRules(models.Resource):
440  """A Forwarding Rule resource."""
441
442  _resource_data: dict
443  _type: str
444
445  def __init__(self, project_id, resource_data):
446    super().__init__(project_id=project_id)
447    self._resource_data = resource_data
448
449  @property
450  def name(self) -> str:
451    return self._resource_data['name']
452
453  @property
454  def id(self) -> str:
455    return self._resource_data['id']
456
457  @property
458  def full_path(self) -> str:
459    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
460                      self.self_link)
461    if result:
462      return result.group(1)
463    else:
464      return f'>> {self.self_link}'
465
466  @property
467  def short_path(self) -> str:
468    path = self.project_id + '/' + self.name
469    return path
470
471  @property
472  def region(self):
473    url = self._resource_data.get('region', '')
474    if url is not None:
475      match = re.search(r'/([^/]+)/?$', url)
476      if match is not None:
477        region = match.group(1)
478        return region
479    return 'global'
480
481  @property
482  def self_link(self) -> str:
483    return self._resource_data['selfLink']
484
485  @property
486  def global_access_allowed(self) -> bool:
487    return self._resource_data.get('allowGlobalAccess', False)
488
489  @property
490  def load_balancing_scheme(self) -> str:
491    return self._resource_data.get('loadBalancingScheme', None)
492
493  @property
494  def target(self) -> str:
495    full_path = self._resource_data.get('target', '')
496    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)', full_path)
497    if result:
498      return result.group(1)
499    else:
500      return ''
501
502  @property
503  def backend_service(self) -> str:
504    full_path = self._resource_data.get('backendService', '')
505    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)', full_path)
506    if result:
507      return result.group(1)
508    else:
509      return ''
510
511  @property
512  def ip_address(self) -> str:
513    return self._resource_data.get('IPAddress', '')
514
515  @property
516  def port_range(self) -> str:
517    return self._resource_data.get('portRange', '')
518
519  @caching.cached_api_call(in_memory=True)
520  def get_related_backend_services(self) -> List[BackendServices]:
521    """Returns the backend services related to the forwarding rule."""
522    if self.backend_service:
523      resource = get_backend_service_by_self_link(self.backend_service)
524      return [resource] if resource else []
525    if self.target:
526      target_proxy_target = get_target_proxy_reference(self.target)
527      if not target_proxy_target:
528        return []
529      target_proxy_target_type = target_proxy_target.split('/')[-2]
530      if target_proxy_target_type == 'backendServices':
531        resource = get_backend_service_by_self_link(target_proxy_target)
532        return [resource] if resource else []
533      elif target_proxy_target_type == 'urlMaps':
534        # Currently it doesn't work for shared-vpc backend services
535        backend_services = get_backend_services(self.project_id)
536        return [
537            backend_service for backend_service in backend_services
538            if target_proxy_target in backend_service.used_by_refs
539        ]
540    return []
541
542  @property
543  def load_balancer_type(self) -> LoadBalancerType:
544    target_type = None
545    if self.target:
546      parts = self.target.split('/')
547      if len(parts) >= 2:
548        target_type = parts[-2]
549
550    application_targets = [
551        'targetHttpProxies',
552        'targetHttpsProxies',
553        'targetGrpcProxies',
554    ]
555
556    return get_load_balancer_type(
557        self.load_balancing_scheme,
558        self.region,
559        'application' if target_type in application_targets else 'network',
560        target_type != 'targetPools',
561    )

A Forwarding Rule resource.

ForwardingRules(project_id, resource_data)
445  def __init__(self, project_id, resource_data):
446    super().__init__(project_id=project_id)
447    self._resource_data = resource_data
name: str
449  @property
450  def name(self) -> str:
451    return self._resource_data['name']
id: str
453  @property
454  def id(self) -> str:
455    return self._resource_data['id']
full_path: str
457  @property
458  def full_path(self) -> str:
459    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
460                      self.self_link)
461    if result:
462      return result.group(1)
463    else:
464      return f'>> {self.self_link}'

Returns the full path of this resource.

Example: 'projects/gcpdiag-gke-1-9b90/zones/europe-west4-a/clusters/gke1'

short_path: str
466  @property
467  def short_path(self) -> str:
468    path = self.project_id + '/' + self.name
469    return path

Returns the short name for this resource.

Note that it isn't clear from this name what kind of resource it is.

Example: 'gke1'

region
471  @property
472  def region(self):
473    url = self._resource_data.get('region', '')
474    if url is not None:
475      match = re.search(r'/([^/]+)/?$', url)
476      if match is not None:
477        region = match.group(1)
478        return region
479    return 'global'
global_access_allowed: bool
485  @property
486  def global_access_allowed(self) -> bool:
487    return self._resource_data.get('allowGlobalAccess', False)
load_balancing_scheme: str
489  @property
490  def load_balancing_scheme(self) -> str:
491    return self._resource_data.get('loadBalancingScheme', None)
target: str
493  @property
494  def target(self) -> str:
495    full_path = self._resource_data.get('target', '')
496    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)', full_path)
497    if result:
498      return result.group(1)
499    else:
500      return ''
backend_service: str
502  @property
503  def backend_service(self) -> str:
504    full_path = self._resource_data.get('backendService', '')
505    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)', full_path)
506    if result:
507      return result.group(1)
508    else:
509      return ''
ip_address: str
511  @property
512  def ip_address(self) -> str:
513    return self._resource_data.get('IPAddress', '')
port_range: str
515  @property
516  def port_range(self) -> str:
517    return self._resource_data.get('portRange', '')
load_balancer_type: LoadBalancerType
542  @property
543  def load_balancer_type(self) -> LoadBalancerType:
544    target_type = None
545    if self.target:
546      parts = self.target.split('/')
547      if len(parts) >= 2:
548        target_type = parts[-2]
549
550    application_targets = [
551        'targetHttpProxies',
552        'targetHttpsProxies',
553        'targetGrpcProxies',
554    ]
555
556    return get_load_balancer_type(
557        self.load_balancing_scheme,
558        self.region,
559        'application' if target_type in application_targets else 'network',
560        target_type != 'targetPools',
561    )
@caching.cached_api_call(in_memory=True)
def get_target_proxy_reference(target_proxy_self_link: str) -> str:
564@caching.cached_api_call(in_memory=True)
565def get_target_proxy_reference(target_proxy_self_link: str) -> str:
566  """Retrieves the URL map or backend service associated with a given target proxy.
567
568  Args:
569    target_proxy_self_link: self link of the target proxy
570
571  Returns:
572    The url map or the backend service self link
573  """
574  target_proxy_type = target_proxy_self_link.split('/')[-2]
575  target_proxy_name = target_proxy_self_link.split('/')[-1]
576  target_proxy_scope = target_proxy_self_link.split('/')[-3]
577  match_result = re.match(r'projects/([^/]+)/', target_proxy_self_link)
578  if not match_result:
579    return ''
580  project_id = match_result.group(1)
581  compute = apis.get_api('compute', 'v1', project_id)
582
583  request = None
584  if target_proxy_type == 'targetHttpsProxies':
585    if target_proxy_scope == 'global':
586      request = compute.targetHttpsProxies().get(
587          project=project_id, targetHttpsProxy=target_proxy_name)
588    else:
589      request = compute.regionTargetHttpsProxies().get(
590          project=project_id,
591          region=target_proxy_scope,
592          targetHttpsProxy=target_proxy_name,
593      )
594  elif target_proxy_type == 'targetHttpProxies':
595    if target_proxy_scope == 'global':
596      request = compute.targetHttpProxies().get(
597          project=project_id, targetHttpProxy=target_proxy_name)
598    else:
599      request = compute.regionTargetHttpProxies().get(
600          project=project_id,
601          region=target_proxy_scope,
602          targetHttpProxy=target_proxy_name,
603      )
604  elif target_proxy_type == 'targetTcpProxies':
605    if target_proxy_scope == 'global':
606      request = compute.targetTcpProxies().get(project=project_id,
607                                               targetTcpProxy=target_proxy_name)
608    else:
609      request = compute.regionTargetTcpProxies().get(
610          project=project_id,
611          region=target_proxy_scope,
612          targetTcpProxy=target_proxy_name,
613      )
614  elif target_proxy_type == 'targetSslProxies':
615    request = compute.targetSslProxies().get(project=project_id,
616                                             targetSslProxy=target_proxy_name)
617  elif target_proxy_type == 'targetGrcpProxies':
618    request = compute.targetGrpcProxies().get(project=project_id,
619                                              targetGrpcProxy=target_proxy_name)
620  if not request:
621    # target is not target proxy
622    return ''
623  response = request.execute(num_retries=config.API_RETRIES)
624  if 'urlMap' in response:
625    return normalize_url(response['urlMap'])
626  if 'service' in response:
627    return normalize_url(response['service'])
628  return ''

Retrieves the URL map or backend service associated with a given target proxy.

Arguments:
  • target_proxy_self_link: self link of the target proxy
Returns:

The url map or the backend service self link

@caching.cached_api_call(in_memory=True)
def get_forwarding_rules(project_id: str) -> List[ForwardingRules]:
631@caching.cached_api_call(in_memory=True)
632def get_forwarding_rules(project_id: str) -> List[ForwardingRules]:
633  logging.info('fetching Forwarding Rules: %s', project_id)
634  compute = apis.get_api('compute', 'v1', project_id)
635  forwarding_rules = []
636  request = compute.forwardingRules().aggregatedList(project=project_id)
637  response = request.execute(num_retries=config.API_RETRIES)
638  forwarding_rules_by_region = response['items']
639  for _, data_ in forwarding_rules_by_region.items():
640    if 'forwardingRules' not in data_:
641      continue
642    forwarding_rules.extend([
643        ForwardingRules(project_id, forwarding_rule)
644        for forwarding_rule in data_['forwardingRules']
645    ])
646  return forwarding_rules
@caching.cached_api_call(in_memory=True)
def get_forwarding_rule( project_id: str, forwarding_rule_name: str, region: str = None) -> ForwardingRules:
649@caching.cached_api_call(in_memory=True)
650def get_forwarding_rule(project_id: str,
651                        forwarding_rule_name: str,
652                        region: str = None) -> ForwardingRules:
653  compute = apis.get_api('compute', 'v1', project_id)
654  if not region or region == 'global':
655    request = compute.globalForwardingRules().get(
656        project=project_id, forwardingRule=forwarding_rule_name)
657  else:
658    request = compute.forwardingRules().get(project=project_id,
659                                            region=region,
660                                            forwardingRule=forwarding_rule_name)
661  response = request.execute(num_retries=config.API_RETRIES)
662  return ForwardingRules(project_id, resource_data=response)
class TargetHttpsProxy(gcpdiag.models.Resource):
665class TargetHttpsProxy(models.Resource):
666  """A Target HTTPS Proxy resource."""
667
668  _resource_data: dict
669  _type: str
670
671  def __init__(self, project_id, resource_data):
672    super().__init__(project_id=project_id)
673    self._resource_data = resource_data
674
675  @property
676  def name(self) -> str:
677    return self._resource_data['name']
678
679  @property
680  def id(self) -> str:
681    return self._resource_data['id']
682
683  @property
684  def full_path(self) -> str:
685    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
686                      self.self_link)
687    if result:
688      return result.group(1)
689    else:
690      return f'>> {self.self_link}'
691
692  @property
693  def self_link(self) -> str:
694    return self._resource_data['selfLink']
695
696  @property
697  def region(self):
698    url = self._resource_data.get('region', '')
699    if url is not None:
700      match = re.search(r'/([^/]+)/?$', url)
701      if match is not None:
702        region = match.group(1)
703        return region
704    return 'global'
705
706  @property
707  def ssl_certificates(self) -> List[str]:
708    return self._resource_data.get('sslCertificates', [])
709
710  @property
711  def certificate_map(self) -> str:
712    certificate_map = self._resource_data.get('certificateMap', '')
713    result = re.match(r'https://certificatemanager.googleapis.com/v1/(.*)',
714                      certificate_map)
715    if result:
716      return result.group(1)
717    return certificate_map

A Target HTTPS Proxy resource.

TargetHttpsProxy(project_id, resource_data)
671  def __init__(self, project_id, resource_data):
672    super().__init__(project_id=project_id)
673    self._resource_data = resource_data
name: str
675  @property
676  def name(self) -> str:
677    return self._resource_data['name']
id: str
679  @property
680  def id(self) -> str:
681    return self._resource_data['id']
full_path: str
683  @property
684  def full_path(self) -> str:
685    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
686                      self.self_link)
687    if result:
688      return result.group(1)
689    else:
690      return f'>> {self.self_link}'

Returns the full path of this resource.

Example: 'projects/gcpdiag-gke-1-9b90/zones/europe-west4-a/clusters/gke1'

region
696  @property
697  def region(self):
698    url = self._resource_data.get('region', '')
699    if url is not None:
700      match = re.search(r'/([^/]+)/?$', url)
701      if match is not None:
702        region = match.group(1)
703        return region
704    return 'global'
ssl_certificates: List[str]
706  @property
707  def ssl_certificates(self) -> List[str]:
708    return self._resource_data.get('sslCertificates', [])
certificate_map: str
710  @property
711  def certificate_map(self) -> str:
712    certificate_map = self._resource_data.get('certificateMap', '')
713    result = re.match(r'https://certificatemanager.googleapis.com/v1/(.*)',
714                      certificate_map)
715    if result:
716      return result.group(1)
717    return certificate_map
@caching.cached_api_call(in_memory=True)
def get_target_https_proxies(project_id: str) -> List[TargetHttpsProxy]:
720@caching.cached_api_call(in_memory=True)
721def get_target_https_proxies(project_id: str) -> List[TargetHttpsProxy]:
722  logging.info('fetching Target HTTPS Proxies: %s', project_id)
723  compute = apis.get_api('compute', 'v1', project_id)
724  target_https_proxies = []
725  request = compute.targetHttpsProxies().aggregatedList(project=project_id)
726  response = request.execute(num_retries=config.API_RETRIES)
727  target_https_proxies_by_region = response['items']
728  for _, data_ in target_https_proxies_by_region.items():
729    if 'targetHttpsProxies' not in data_:
730      continue
731    target_https_proxies.extend([
732        TargetHttpsProxy(project_id, target_https_proxy)
733        for target_https_proxy in data_['targetHttpsProxies']
734    ])
735
736  return target_https_proxies
class TargetSslProxy(gcpdiag.models.Resource):
739class TargetSslProxy(models.Resource):
740  """A Target SSL Proxy resource."""
741
742  _resource_data: dict
743  _type: str
744
745  def __init__(self, project_id, resource_data):
746    super().__init__(project_id=project_id)
747    self._resource_data = resource_data
748
749  @property
750  def name(self) -> str:
751    return self._resource_data['name']
752
753  @property
754  def id(self) -> str:
755    return self._resource_data['id']
756
757  @property
758  def full_path(self) -> str:
759    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
760                      self.self_link)
761    if result:
762      return result.group(1)
763    else:
764      return f'>> {self.self_link}'
765
766  @property
767  def self_link(self) -> str:
768    return self._resource_data['selfLink']
769
770  @property
771  def region(self):
772    url = self._resource_data.get('region', '')
773    if url is not None:
774      match = re.search(r'/([^/]+)/?$', url)
775      if match is not None:
776        region = match.group(1)
777        return region
778    return 'global'
779
780  @property
781  def ssl_certificates(self) -> List[str]:
782    return self._resource_data.get('sslCertificates', [])
783
784  @property
785  def certificate_map(self) -> str:
786    certificate_map = self._resource_data.get('certificateMap', '')
787    result = re.match(r'https://certificatemanager.googleapis.com/v1/(.*)',
788                      certificate_map)
789    if result:
790      return result.group(1)
791    return certificate_map

A Target SSL Proxy resource.

TargetSslProxy(project_id, resource_data)
745  def __init__(self, project_id, resource_data):
746    super().__init__(project_id=project_id)
747    self._resource_data = resource_data
name: str
749  @property
750  def name(self) -> str:
751    return self._resource_data['name']
id: str
753  @property
754  def id(self) -> str:
755    return self._resource_data['id']
full_path: str
757  @property
758  def full_path(self) -> str:
759    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
760                      self.self_link)
761    if result:
762      return result.group(1)
763    else:
764      return f'>> {self.self_link}'

Returns the full path of this resource.

Example: 'projects/gcpdiag-gke-1-9b90/zones/europe-west4-a/clusters/gke1'

region
770  @property
771  def region(self):
772    url = self._resource_data.get('region', '')
773    if url is not None:
774      match = re.search(r'/([^/]+)/?$', url)
775      if match is not None:
776        region = match.group(1)
777        return region
778    return 'global'
ssl_certificates: List[str]
780  @property
781  def ssl_certificates(self) -> List[str]:
782    return self._resource_data.get('sslCertificates', [])
certificate_map: str
784  @property
785  def certificate_map(self) -> str:
786    certificate_map = self._resource_data.get('certificateMap', '')
787    result = re.match(r'https://certificatemanager.googleapis.com/v1/(.*)',
788                      certificate_map)
789    if result:
790      return result.group(1)
791    return certificate_map
@caching.cached_api_call(in_memory=True)
def get_target_ssl_proxies(project_id: str) -> List[TargetSslProxy]:
794@caching.cached_api_call(in_memory=True)
795def get_target_ssl_proxies(project_id: str) -> List[TargetSslProxy]:
796  logging.info('fetching Target SSL Proxies: %s', project_id)
797  compute = apis.get_api('compute', 'v1', project_id)
798  request = compute.targetSslProxies().list(project=project_id)
799  response = request.execute(num_retries=config.API_RETRIES)
800
801  return [
802      TargetSslProxy(project_id, item) for item in response.get('items', [])
803  ]
class LoadBalancerInsight(gcpdiag.models.Resource):
806class LoadBalancerInsight(models.Resource):
807  """Represents a Load Balancer Insights object"""
808
809  @property
810  def full_path(self) -> str:
811    return self._resource_data['name']
812
813  @property
814  def description(self) -> str:
815    return self._resource_data['description']
816
817  @property
818  def insight_subtype(self) -> str:
819    return self._resource_data['insightSubtype']
820
821  @property
822  def details(self) -> dict:
823    return self._resource_data['content']
824
825  @property
826  def is_firewall_rule_insight(self) -> bool:
827    firewall_rule_subtypes = (
828        'HEALTH_CHECK_FIREWALL_NOT_CONFIGURED',
829        'HEALTH_CHECK_FIREWALL_FULLY_BLOCKING',
830        'HEALTH_CHECK_FIREWALL_PARTIALLY_BLOCKING',
831        'HEALTH_CHECK_FIREWALL_INCONSISTENT',
832    )
833    return self.insight_subtype.startswith(firewall_rule_subtypes)
834
835  @property
836  def is_health_check_port_mismatch_insight(self) -> bool:
837    return self.insight_subtype == 'HEALTH_CHECK_PORT_MISMATCH'
838
839  def __init__(self, project_id, resource_data):
840    super().__init__(project_id=project_id)
841    self._resource_data = resource_data

Represents a Load Balancer Insights object

LoadBalancerInsight(project_id, resource_data)
839  def __init__(self, project_id, resource_data):
840    super().__init__(project_id=project_id)
841    self._resource_data = resource_data
full_path: str
809  @property
810  def full_path(self) -> str:
811    return self._resource_data['name']

Returns the full path of this resource.

Example: 'projects/gcpdiag-gke-1-9b90/zones/europe-west4-a/clusters/gke1'

description: str
813  @property
814  def description(self) -> str:
815    return self._resource_data['description']
insight_subtype: str
817  @property
818  def insight_subtype(self) -> str:
819    return self._resource_data['insightSubtype']
details: dict
821  @property
822  def details(self) -> dict:
823    return self._resource_data['content']
is_firewall_rule_insight: bool
825  @property
826  def is_firewall_rule_insight(self) -> bool:
827    firewall_rule_subtypes = (
828        'HEALTH_CHECK_FIREWALL_NOT_CONFIGURED',
829        'HEALTH_CHECK_FIREWALL_FULLY_BLOCKING',
830        'HEALTH_CHECK_FIREWALL_PARTIALLY_BLOCKING',
831        'HEALTH_CHECK_FIREWALL_INCONSISTENT',
832    )
833    return self.insight_subtype.startswith(firewall_rule_subtypes)
is_health_check_port_mismatch_insight: bool
835  @property
836  def is_health_check_port_mismatch_insight(self) -> bool:
837    return self.insight_subtype == 'HEALTH_CHECK_PORT_MISMATCH'
@caching.cached_api_call
def get_lb_insights_for_a_project(project_id: str, region: str = 'global'):
844@caching.cached_api_call
845def get_lb_insights_for_a_project(project_id: str, region: str = 'global'):
846  api = apis.get_api('recommender', 'v1', project_id)
847
848  insight_name = (f'projects/{project_id}/locations/{region}/insightTypes/'
849                  'google.networkanalyzer.networkservices.loadBalancerInsight')
850  insights = []
851  for insight in apis_utils.list_all(
852      request=api.projects().locations().insightTypes().insights().list(
853          parent=insight_name),
854      next_function=api.projects().locations().insightTypes().insights().
855      list_next,
856      response_keyword='insights',
857  ):
858    insights.append(LoadBalancerInsight(project_id, insight))
859  return insights