gcpdiag/queries/lb_stub.py (222 lines of code) (raw):
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Lint as: python3
"""Stub API calls used in lb.py for testing.
Instead of doing real API calls, we return test JSON data.
"""
import json
from typing import Any
import httplib2
from googleapiclient import errors
from gcpdiag.queries import apis_stub
# pylint: disable=unused-argument
# pylint: disable=invalid-name
backend_service_states = ('backendServices', 'regionBackendServices')
forwarding_rule_states = ('forwardingRules', 'globalForwardingRules')
target_http_proxy_states = ('targetHttpProxies', 'regionTargetHttpProxies')
target_https_proxy_states = (
'targetHttpsProxies',
'regionTargetHttpsProxies',
)
target_ssl_proxy_states = 'targetSslProxies'
target_grpc_proxy_states = 'targetGrpcProxies'
target_tcp_proxy_states = ('targetTcpProxies', 'regionTargetTcpProxies')
aggregated_supported = (
'backendServices',
'forwardingRules',
'targetHttpProxies',
'targetHttpsProxies',
'targetTcpProxies',
)
class LbApiStub:
"""Mock object to simulate compute engine networking api calls.
This object is created by GceApiStub, not used directly in test scripts.
"""
def __init__(self, mock_state):
self.mock_state = mock_state
def aggregatedList(self, project):
if self.mock_state == 'forwardingRules':
return apis_stub.RestCallStub(project,
'compute-aggregated-forwardingRules')
if self.mock_state == 'backendServices':
return apis_stub.RestCallStub(project,
'compute-aggregated-backendServices')
else:
raise ValueError(f'cannot call method {self.mock_state} here')
# pylint: disable=redefined-builtin
def list(self, project, region=None):
if self.mock_state == 'backendServices':
return apis_stub.RestCallStub(project, 'compute-backendServices')
if self.mock_state == 'regionBackendServices':
return apis_stub.RestCallStub(project,
f'compute-backendServices-{region}')
else:
raise ValueError(f'cannot call method {self.mock_state} here')
def get(
self,
project,
region=None,
backendService=None,
forwardingRule=None,
):
self.region = region
self.project = project
if self.mock_state in backend_service_states and backendService:
self.backend_service = backendService
return self
elif self.mock_state in forwarding_rule_states and forwardingRule:
self.forwarding_rule = forwardingRule
return self
else:
raise ValueError(f'cannot call method {self.mock_state} here')
def getHealth(self, project, backendService, body, region=None):
backend_url_parts = body.get('group').split('/')
backend_name, backend_type, backend_scope = (
backend_url_parts[-1],
backend_url_parts[-2],
backend_url_parts[-3],
)
if self.mock_state == 'backendServices':
stub_name = (f'backendService-{backendService}-get-health-{backend_type}-'
f'{backend_name}-{backend_scope}')
return apis_stub.RestCallStub(project, stub_name)
if self.mock_state == 'regionBackendServices':
stub_name = (f'regionBackendService-{backendService}-{region}-get-health-'
f'{backend_type}-{backend_name}-{backend_scope}')
return apis_stub.RestCallStub(project, stub_name)
else:
raise ValueError(f'cannot call method {self.mock_state} here')
def _get_resources_from_json_items(self, items: Any, resource_name: str):
if resource_name in aggregated_supported:
items_by_scope = items[f'regions/{self.region}' if self.
region else 'global']
return items_by_scope[resource_name]
return items
def execute(self, num_retries=0):
json_dir = apis_stub.get_json_dir(self.project)
if self.mock_state in backend_service_states:
resource_name = 'backendServices'
elif self.mock_state in forwarding_rule_states:
resource_name = 'forwardingRules'
else:
resource_name = self.mock_state
json_file_name = (f'compute-aggregated-{resource_name}.json'
if resource_name in aggregated_supported else
f'compute-{resource_name}.json')
with open(json_dir / f'{json_file_name}', encoding='utf-8') as json_file:
items = json.load(json_file)['items']
resources = self._get_resources_from_json_items(items, resource_name)
if not resources:
raise errors.HttpError(
httplib2.Response({
'status': 404,
'reason': 'Not Found'
}),
b'The resource is not found',
)
if self.mock_state in backend_service_states:
for backend_service in resources:
if backend_service['name'] == self.backend_service:
return backend_service
else:
raise errors.HttpError(
httplib2.Response({
'status': 404,
'reason': 'Not Found'
}),
f'The backend service {self.backend_service} is not found'.
encode(),
)
elif self.mock_state in forwarding_rule_states:
for forwarding_rule in resources:
if forwarding_rule['name'] == self.forwarding_rule:
return forwarding_rule
else:
raise errors.HttpError(
httplib2.Response({
'status': 404,
'reason': 'Not Found'
}),
f'The forwarding rule {self.forwarding_rule} is not found'.
encode(),
)
else:
raise ValueError(f'cannot call method {self.mock_state} here')
def list_next(self, prev_request, prev_response):
return None
class SslCertificateApiStub:
"""Mock object to simulate SSL certificate api calls"""
def __init__(self, mock_state):
self.mock_state = mock_state
def get(self, project, sslCertificate=None, region=None):
if sslCertificate:
self.ssl_certificate = sslCertificate
self.project = project
self.region = region
return self
else:
raise ValueError(f'cannot call method {self.mock_state} here')
def execute(self, num_retries=0):
json_dir = apis_stub.get_json_dir(self.project)
json_file_name = f'compute-{self.mock_state}.json'
if self.mock_state == 'regionSslCertificates':
json_file_name = f'compute-{self.mock_state}-{self.region}.json'
with open(json_dir / json_file_name, encoding='utf-8') as json_file:
ssl_certificates = json.load(json_file)['items']
# search for and get the ssl certificate
if ssl_certificates:
for ssl_certificate in ssl_certificates:
if ssl_certificate['name'] == self.ssl_certificate:
return ssl_certificate
raise errors.HttpError(
httplib2.Response({
'status': 404,
'reason': 'Not Found'
}),
f'The SSL certificate {self.ssl_certificate} is not found'.encode(),
)
else:
raise ValueError(f'cannot call method {self.mock_state} here')
class TargetProxyStub:
"""Mock object to simulate target proxy api calls"""
def __init__(self, mock_state):
self.mock_state = mock_state
def aggregatedList(self, project):
return apis_stub.RestCallStub(project,
f'compute-aggregated-{self.mock_state}')
def list(self, project):
return apis_stub.RestCallStub(project, f'compute-{self.mock_state}')
def get(
self,
project,
region=None,
targetHttpProxy=None,
targetHttpsProxy=None,
targetSslProxy=None,
targetGrpcProxy=None,
targetTcpProxy=None,
):
self.region = region
self.project = project
if self.mock_state in target_tcp_proxy_states and targetTcpProxy:
self.target_proxy = targetTcpProxy
return self
if self.mock_state in target_https_proxy_states and targetHttpsProxy:
self.target_proxy = targetHttpsProxy
return self
if self.mock_state in target_http_proxy_states and targetHttpProxy:
self.target_proxy = targetHttpProxy
return self
if self.mock_state in target_ssl_proxy_states and targetSslProxy:
self.target_proxy = targetSslProxy
return self
if self.mock_state in target_grpc_proxy_states and targetGrpcProxy:
self.target_proxy = targetGrpcProxy
return self
else:
raise ValueError(f'cannot call method {self.mock_state} here')
def execute(self, num_retries=0):
json_dir = apis_stub.get_json_dir(self.project)
json_file_name = f'compute-{self.mock_state}.json'
if self.region:
json_file_name = f'compute-{self.mock_state}-{self.region}.json'
with open(json_dir / json_file_name, encoding='utf-8') as json_file:
target_proxies = json.load(json_file)['items']
# search for and get the ssl certificate
if target_proxies:
for target_proxy in target_proxies:
if target_proxy['name'] == self.target_proxy:
return target_proxy
raise errors.HttpError(
httplib2.Response({
'status': 404,
'reason': 'Not Found'
}),
f'The Target proxy {self.target_proxy} is not found'.encode(),
)
else:
raise ValueError(f'cannot call method {self.mock_state} here')