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]:
314@caching.cached_api_call(in_memory=True)
315def get_backend_service_health(
316    project_id: str,
317    backend_service_name: str,
318    backend_service_region: str = None,
319) -> List[BackendHealth]:
320  """Returns health data for backend service."""
321  try:
322    backend_service = get_backend_service(project_id, backend_service_name,
323                                          backend_service_region)
324  except googleapiclient.errors.HttpError:
325    return []
326
327  backend_heath_statuses: List[BackendHealth] = []
328
329  compute = apis.get_api('compute', 'v1', project_id)
330
331  for backend in backend_service.backends:
332    group = backend['group']
333    if not backend_service.region:
334      response = compute.backendServices().getHealth(
335          project=project_id,
336          backendService=backend_service.name,
337          body={
338              'group': group
339          },
340      ).execute(num_retries=config.API_RETRIES)
341      # None is returned when backend type doesn't support health check
342      if response is not None:
343        for health_status in response.get('healthStatus', []):
344          backend_heath_statuses.append(BackendHealth(health_status, group))
345    else:
346      response = compute.regionBackendServices().getHealth(
347          project=project_id,
348          region=backend_service.region,
349          backendService=backend_service.name,
350          body={
351              'group': group
352          },
353      ).execute(num_retries=config.API_RETRIES)
354      if response is not None:
355        for health_status in response.get('healthStatus', []):
356          backend_heath_statuses.append(BackendHealth(health_status, group))
357
358  return backend_heath_statuses

Returns health data for backend service.

class SslCertificate(gcpdiag.models.Resource):
361class SslCertificate(models.Resource):
362  """A SSL Certificate resource."""
363
364  _resource_data: dict
365  _type: str
366
367  def __init__(self, project_id, resource_data):
368    super().__init__(project_id=project_id)
369    self._resource_data = resource_data
370
371  @property
372  def name(self) -> str:
373    return self._resource_data['name']
374
375  @property
376  def id(self) -> str:
377    return self._resource_data['id']
378
379  @property
380  def full_path(self) -> str:
381    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
382                      self.self_link)
383    if result:
384      return result.group(1)
385    else:
386      return f'>> {self.self_link}'
387
388  @property
389  def self_link(self) -> str:
390    return self._resource_data['selfLink']
391
392  @property
393  def type(self) -> str:
394    return self._resource_data.get('type', 'SELF_MANAGED')
395
396  @property
397  def status(self) -> str:
398    return self._resource_data.get('managed', {}).get('status')
399
400  @property
401  def domains(self) -> List[str]:
402    return self._resource_data.get('managed', {}).get('domains', [])
403
404  @property
405  def domain_status(self) -> Dict[str, str]:
406    return self._resource_data.get('managed', {}).get('domainStatus', {})

A SSL Certificate resource.

SslCertificate(project_id, resource_data)
367  def __init__(self, project_id, resource_data):
368    super().__init__(project_id=project_id)
369    self._resource_data = resource_data
name: str
371  @property
372  def name(self) -> str:
373    return self._resource_data['name']
id: str
375  @property
376  def id(self) -> str:
377    return self._resource_data['id']
full_path: str
379  @property
380  def full_path(self) -> str:
381    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
382                      self.self_link)
383    if result:
384      return result.group(1)
385    else:
386      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
392  @property
393  def type(self) -> str:
394    return self._resource_data.get('type', 'SELF_MANAGED')
status: str
396  @property
397  def status(self) -> str:
398    return self._resource_data.get('managed', {}).get('status')
domains: List[str]
400  @property
401  def domains(self) -> List[str]:
402    return self._resource_data.get('managed', {}).get('domains', [])
domain_status: Dict[str, str]
404  @property
405  def domain_status(self) -> Dict[str, str]:
406    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:
409@caching.cached_api_call(in_memory=True)
410def get_ssl_certificate(
411    project_id: str,
412    certificate_name: str,
413) -> SslCertificate:
414  """Returns object matching certificate name and region"""
415  compute = apis.get_api('compute', 'v1', project_id)
416
417  request = compute.sslCertificates().get(project=project_id,
418                                          sslCertificate=certificate_name)
419
420  response = request.execute(num_retries=config.API_RETRIES)
421  return SslCertificate(project_id, resource_data=response)

Returns object matching certificate name and region

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

A Forwarding Rule resource.

ForwardingRules(project_id, resource_data)
430  def __init__(self, project_id, resource_data):
431    super().__init__(project_id=project_id)
432    self._resource_data = resource_data
name: str
434  @property
435  def name(self) -> str:
436    return self._resource_data['name']
id: str
438  @property
439  def id(self) -> str:
440    return self._resource_data['id']
full_path: str
442  @property
443  def full_path(self) -> str:
444    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
445                      self.self_link)
446    if result:
447      return result.group(1)
448    else:
449      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
451  @property
452  def short_path(self) -> str:
453    path = self.project_id + '/' + self.name
454    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
456  @property
457  def region(self):
458    url = self._resource_data.get('region', '')
459    if url is not None:
460      match = re.search(r'/([^/]+)/?$', url)
461      if match is not None:
462        region = match.group(1)
463        return region
464    return 'global'
global_access_allowed: bool
470  @property
471  def global_access_allowed(self) -> bool:
472    return self._resource_data.get('allowGlobalAccess', False)
load_balancing_scheme: str
474  @property
475  def load_balancing_scheme(self) -> str:
476    return self._resource_data.get('loadBalancingScheme', None)
target: str
478  @property
479  def target(self) -> str:
480    full_path = self._resource_data.get('target', '')
481    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)', full_path)
482    if result:
483      return result.group(1)
484    else:
485      return ''
backend_service: str
487  @property
488  def backend_service(self) -> str:
489    full_path = self._resource_data.get('backendService', '')
490    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)', full_path)
491    if result:
492      return result.group(1)
493    else:
494      return ''
ip_address: str
496  @property
497  def ip_address(self) -> str:
498    return self._resource_data.get('IPAddress', '')
port_range: str
500  @property
501  def port_range(self) -> str:
502    return self._resource_data.get('portRange', '')
load_balancer_type: LoadBalancerType
527  @property
528  def load_balancer_type(self) -> LoadBalancerType:
529    target_type = None
530    if self.target:
531      parts = self.target.split('/')
532      if len(parts) >= 2:
533        target_type = parts[-2]
534
535    application_targets = [
536        'targetHttpProxies',
537        'targetHttpsProxies',
538        'targetGrpcProxies',
539    ]
540
541    return get_load_balancer_type(
542        self.load_balancing_scheme,
543        self.region,
544        'application' if target_type in application_targets else 'network',
545        target_type != 'targetPools',
546    )
@caching.cached_api_call(in_memory=True)
def get_target_proxy_reference(target_proxy_self_link: str) -> str:
549@caching.cached_api_call(in_memory=True)
550def get_target_proxy_reference(target_proxy_self_link: str) -> str:
551  """Retrieves the URL map or backend service associated with a given target proxy.
552
553  Args:
554    target_proxy_self_link: self link of the target proxy
555
556  Returns:
557    The url map or the backend service self link
558  """
559  target_proxy_type = target_proxy_self_link.split('/')[-2]
560  target_proxy_name = target_proxy_self_link.split('/')[-1]
561  target_proxy_scope = target_proxy_self_link.split('/')[-3]
562  match_result = re.match(r'projects/([^/]+)/', target_proxy_self_link)
563  if not match_result:
564    return ''
565  project_id = match_result.group(1)
566  compute = apis.get_api('compute', 'v1', project_id)
567
568  request = None
569  if target_proxy_type == 'targetHttpsProxies':
570    if target_proxy_scope == 'global':
571      request = compute.targetHttpsProxies().get(
572          project=project_id, targetHttpsProxy=target_proxy_name)
573    else:
574      request = compute.regionTargetHttpsProxies().get(
575          project=project_id,
576          region=target_proxy_scope,
577          targetHttpsProxy=target_proxy_name,
578      )
579  elif target_proxy_type == 'targetHttpProxies':
580    if target_proxy_scope == 'global':
581      request = compute.targetHttpProxies().get(
582          project=project_id, targetHttpProxy=target_proxy_name)
583    else:
584      request = compute.regionTargetHttpProxies().get(
585          project=project_id,
586          region=target_proxy_scope,
587          targetHttpProxy=target_proxy_name,
588      )
589  elif target_proxy_type == 'targetTcpProxies':
590    if target_proxy_scope == 'global':
591      request = compute.targetTcpProxies().get(project=project_id,
592                                               targetTcpProxy=target_proxy_name)
593    else:
594      request = compute.regionTargetTcpProxies().get(
595          project=project_id,
596          region=target_proxy_scope,
597          targetTcpProxy=target_proxy_name,
598      )
599  elif target_proxy_type == 'targetSslProxies':
600    request = compute.targetSslProxies().get(project=project_id,
601                                             targetSslProxy=target_proxy_name)
602  elif target_proxy_type == 'targetGrcpProxies':
603    request = compute.targetGrpcProxies().get(project=project_id,
604                                              targetGrpcProxy=target_proxy_name)
605  if not request:
606    # target is not target proxy
607    return ''
608  response = request.execute(num_retries=config.API_RETRIES)
609  if 'urlMap' in response:
610    return normalize_url(response['urlMap'])
611  if 'service' in response:
612    return normalize_url(response['service'])
613  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]:
616@caching.cached_api_call(in_memory=True)
617def get_forwarding_rules(project_id: str) -> List[ForwardingRules]:
618  logging.info('fetching Forwarding Rules: %s', project_id)
619  compute = apis.get_api('compute', 'v1', project_id)
620  forwarding_rules = []
621  request = compute.forwardingRules().aggregatedList(project=project_id)
622  response = request.execute(num_retries=config.API_RETRIES)
623  forwarding_rules_by_region = response['items']
624  for _, data_ in forwarding_rules_by_region.items():
625    if 'forwardingRules' not in data_:
626      continue
627    forwarding_rules.extend([
628        ForwardingRules(project_id, forwarding_rule)
629        for forwarding_rule in data_['forwardingRules']
630    ])
631  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:
634@caching.cached_api_call(in_memory=True)
635def get_forwarding_rule(project_id: str,
636                        forwarding_rule_name: str,
637                        region: str = None) -> ForwardingRules:
638  compute = apis.get_api('compute', 'v1', project_id)
639  if not region or region == 'global':
640    request = compute.globalForwardingRules().get(
641        project=project_id, forwardingRule=forwarding_rule_name)
642  else:
643    request = compute.forwardingRules().get(project=project_id,
644                                            region=region,
645                                            forwardingRule=forwarding_rule_name)
646  response = request.execute(num_retries=config.API_RETRIES)
647  return ForwardingRules(project_id, resource_data=response)
class TargetHttpsProxy(gcpdiag.models.Resource):
650class TargetHttpsProxy(models.Resource):
651  """A Target HTTPS Proxy resource."""
652
653  _resource_data: dict
654  _type: str
655
656  def __init__(self, project_id, resource_data):
657    super().__init__(project_id=project_id)
658    self._resource_data = resource_data
659
660  @property
661  def name(self) -> str:
662    return self._resource_data['name']
663
664  @property
665  def id(self) -> str:
666    return self._resource_data['id']
667
668  @property
669  def full_path(self) -> str:
670    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
671                      self.self_link)
672    if result:
673      return result.group(1)
674    else:
675      return f'>> {self.self_link}'
676
677  @property
678  def self_link(self) -> str:
679    return self._resource_data['selfLink']
680
681  @property
682  def region(self):
683    url = self._resource_data.get('region', '')
684    if url is not None:
685      match = re.search(r'/([^/]+)/?$', url)
686      if match is not None:
687        region = match.group(1)
688        return region
689    return 'global'
690
691  @property
692  def ssl_certificates(self) -> List[str]:
693    return self._resource_data.get('sslCertificates', [])
694
695  @property
696  def certificate_map(self) -> str:
697    certificate_map = self._resource_data.get('certificateMap', '')
698    result = re.match(r'https://certificatemanager.googleapis.com/v1/(.*)',
699                      certificate_map)
700    if result:
701      return result.group(1)
702    return certificate_map

A Target HTTPS Proxy resource.

TargetHttpsProxy(project_id, resource_data)
656  def __init__(self, project_id, resource_data):
657    super().__init__(project_id=project_id)
658    self._resource_data = resource_data
name: str
660  @property
661  def name(self) -> str:
662    return self._resource_data['name']
id: str
664  @property
665  def id(self) -> str:
666    return self._resource_data['id']
full_path: str
668  @property
669  def full_path(self) -> str:
670    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
671                      self.self_link)
672    if result:
673      return result.group(1)
674    else:
675      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
681  @property
682  def region(self):
683    url = self._resource_data.get('region', '')
684    if url is not None:
685      match = re.search(r'/([^/]+)/?$', url)
686      if match is not None:
687        region = match.group(1)
688        return region
689    return 'global'
ssl_certificates: List[str]
691  @property
692  def ssl_certificates(self) -> List[str]:
693    return self._resource_data.get('sslCertificates', [])
certificate_map: str
695  @property
696  def certificate_map(self) -> str:
697    certificate_map = self._resource_data.get('certificateMap', '')
698    result = re.match(r'https://certificatemanager.googleapis.com/v1/(.*)',
699                      certificate_map)
700    if result:
701      return result.group(1)
702    return certificate_map
@caching.cached_api_call(in_memory=True)
def get_target_https_proxies(project_id: str) -> List[TargetHttpsProxy]:
705@caching.cached_api_call(in_memory=True)
706def get_target_https_proxies(project_id: str) -> List[TargetHttpsProxy]:
707  logging.info('fetching Target HTTPS Proxies: %s', project_id)
708  compute = apis.get_api('compute', 'v1', project_id)
709  target_https_proxies = []
710  request = compute.targetHttpsProxies().aggregatedList(project=project_id)
711  response = request.execute(num_retries=config.API_RETRIES)
712  target_https_proxies_by_region = response['items']
713  for _, data_ in target_https_proxies_by_region.items():
714    if 'targetHttpsProxies' not in data_:
715      continue
716    target_https_proxies.extend([
717        TargetHttpsProxy(project_id, target_https_proxy)
718        for target_https_proxy in data_['targetHttpsProxies']
719    ])
720
721  return target_https_proxies
class TargetSslProxy(gcpdiag.models.Resource):
724class TargetSslProxy(models.Resource):
725  """A Target SSL Proxy resource."""
726
727  _resource_data: dict
728  _type: str
729
730  def __init__(self, project_id, resource_data):
731    super().__init__(project_id=project_id)
732    self._resource_data = resource_data
733
734  @property
735  def name(self) -> str:
736    return self._resource_data['name']
737
738  @property
739  def id(self) -> str:
740    return self._resource_data['id']
741
742  @property
743  def full_path(self) -> str:
744    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
745                      self.self_link)
746    if result:
747      return result.group(1)
748    else:
749      return f'>> {self.self_link}'
750
751  @property
752  def self_link(self) -> str:
753    return self._resource_data['selfLink']
754
755  @property
756  def region(self):
757    url = self._resource_data.get('region', '')
758    if url is not None:
759      match = re.search(r'/([^/]+)/?$', url)
760      if match is not None:
761        region = match.group(1)
762        return region
763    return 'global'
764
765  @property
766  def ssl_certificates(self) -> List[str]:
767    return self._resource_data.get('sslCertificates', [])
768
769  @property
770  def certificate_map(self) -> str:
771    certificate_map = self._resource_data.get('certificateMap', '')
772    result = re.match(r'https://certificatemanager.googleapis.com/v1/(.*)',
773                      certificate_map)
774    if result:
775      return result.group(1)
776    return certificate_map

A Target SSL Proxy resource.

TargetSslProxy(project_id, resource_data)
730  def __init__(self, project_id, resource_data):
731    super().__init__(project_id=project_id)
732    self._resource_data = resource_data
name: str
734  @property
735  def name(self) -> str:
736    return self._resource_data['name']
id: str
738  @property
739  def id(self) -> str:
740    return self._resource_data['id']
full_path: str
742  @property
743  def full_path(self) -> str:
744    result = re.match(r'https://www.googleapis.com/compute/v1/(.*)',
745                      self.self_link)
746    if result:
747      return result.group(1)
748    else:
749      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
755  @property
756  def region(self):
757    url = self._resource_data.get('region', '')
758    if url is not None:
759      match = re.search(r'/([^/]+)/?$', url)
760      if match is not None:
761        region = match.group(1)
762        return region
763    return 'global'
ssl_certificates: List[str]
765  @property
766  def ssl_certificates(self) -> List[str]:
767    return self._resource_data.get('sslCertificates', [])
certificate_map: str
769  @property
770  def certificate_map(self) -> str:
771    certificate_map = self._resource_data.get('certificateMap', '')
772    result = re.match(r'https://certificatemanager.googleapis.com/v1/(.*)',
773                      certificate_map)
774    if result:
775      return result.group(1)
776    return certificate_map
@caching.cached_api_call(in_memory=True)
def get_target_ssl_proxies(project_id: str) -> List[TargetSslProxy]:
779@caching.cached_api_call(in_memory=True)
780def get_target_ssl_proxies(project_id: str) -> List[TargetSslProxy]:
781  logging.info('fetching Target SSL Proxies: %s', project_id)
782  compute = apis.get_api('compute', 'v1', project_id)
783  request = compute.targetSslProxies().list(project=project_id)
784  response = request.execute(num_retries=config.API_RETRIES)
785
786  return [
787      TargetSslProxy(project_id, item) for item in response.get('items', [])
788  ]
class LoadBalancerInsight(gcpdiag.models.Resource):
791class LoadBalancerInsight(models.Resource):
792  """Represents a Load Balancer Insights object"""
793
794  @property
795  def full_path(self) -> str:
796    return self._resource_data['name']
797
798  @property
799  def description(self) -> str:
800    return self._resource_data['description']
801
802  @property
803  def insight_subtype(self) -> str:
804    return self._resource_data['insightSubtype']
805
806  @property
807  def details(self) -> dict:
808    return self._resource_data['content']
809
810  @property
811  def is_firewall_rule_insight(self) -> bool:
812    firewall_rule_subtypes = (
813        'HEALTH_CHECK_FIREWALL_NOT_CONFIGURED',
814        'HEALTH_CHECK_FIREWALL_FULLY_BLOCKING',
815        'HEALTH_CHECK_FIREWALL_PARTIALLY_BLOCKING',
816        'HEALTH_CHECK_FIREWALL_INCONSISTENT',
817    )
818    return self.insight_subtype.startswith(firewall_rule_subtypes)
819
820  @property
821  def is_health_check_port_mismatch_insight(self) -> bool:
822    return self.insight_subtype == 'HEALTH_CHECK_PORT_MISMATCH'
823
824  def __init__(self, project_id, resource_data):
825    super().__init__(project_id=project_id)
826    self._resource_data = resource_data

Represents a Load Balancer Insights object

LoadBalancerInsight(project_id, resource_data)
824  def __init__(self, project_id, resource_data):
825    super().__init__(project_id=project_id)
826    self._resource_data = resource_data
full_path: str
794  @property
795  def full_path(self) -> str:
796    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
798  @property
799  def description(self) -> str:
800    return self._resource_data['description']
insight_subtype: str
802  @property
803  def insight_subtype(self) -> str:
804    return self._resource_data['insightSubtype']
details: dict
806  @property
807  def details(self) -> dict:
808    return self._resource_data['content']
is_firewall_rule_insight: bool
810  @property
811  def is_firewall_rule_insight(self) -> bool:
812    firewall_rule_subtypes = (
813        'HEALTH_CHECK_FIREWALL_NOT_CONFIGURED',
814        'HEALTH_CHECK_FIREWALL_FULLY_BLOCKING',
815        'HEALTH_CHECK_FIREWALL_PARTIALLY_BLOCKING',
816        'HEALTH_CHECK_FIREWALL_INCONSISTENT',
817    )
818    return self.insight_subtype.startswith(firewall_rule_subtypes)
is_health_check_port_mismatch_insight: bool
820  @property
821  def is_health_check_port_mismatch_insight(self) -> bool:
822    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'):
829@caching.cached_api_call
830def get_lb_insights_for_a_project(project_id: str, region: str = 'global'):
831  api = apis.get_api('recommender', 'v1', project_id)
832
833  insight_name = (f'projects/{project_id}/locations/{region}/insightTypes/'
834                  'google.networkanalyzer.networkservices.loadBalancerInsight')
835  insights = []
836  for insight in apis_utils.list_all(
837      request=api.projects().locations().insightTypes().insights().list(
838          parent=insight_name),
839      next_function=api.projects().locations().insightTypes().insights().
840      list_next,
841      response_keyword='insights',
842  ):
843    insights.append(LoadBalancerInsight(project_id, insight))
844  return insights