gcpdiag.queries.looker

Queries related to GCP Looker Core.
class Instance(gcpdiag.models.Resource):
27class Instance(models.Resource):
28  """Represents a Looker Core Instance."""
29
30  _resource_data: dict
31
32  def __init__(self, project_id, resource_data):
33    super().__init__(project_id=project_id)
34    self._resource_data = resource_data
35
36  @property
37  def name(self) -> str:
38    return self._resource_data['name']
39
40  @property
41  def full_path(self) -> str:
42    return self._resource_data['name']
43
44  @property
45  def short_path(self) -> str:
46    return '/'.join(self.full_path.split('/')[-4:])
47
48  @property
49  def status(self) -> str:
50    return self._resource_data.get('state', 'STATE_UNSPECIFIED')
51
52  @property
53  def create_time(self) -> str:
54    return self._resource_data.get('createTime', '')
55
56  @property
57  def update_time(self) -> str:
58    return self._resource_data.get('updateTime', '')
59
60  @property
61  def platform_edition(self) -> str:
62    return self._resource_data.get('platformEdition', '')
63
64  @property
65  def looker_version(self) -> str:
66    return self._resource_data.get('lookerVersion', '')
67
68  @property
69  def looker_uri(self) -> str:
70    return self._resource_data.get('lookerUri', '')

Represents a Looker Core Instance.

Instance(project_id, resource_data)
32  def __init__(self, project_id, resource_data):
33    super().__init__(project_id=project_id)
34    self._resource_data = resource_data
name: str
36  @property
37  def name(self) -> str:
38    return self._resource_data['name']
full_path: str
40  @property
41  def full_path(self) -> str:
42    return self._resource_data['name']

Returns the full path of this resource.

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

short_path: str
44  @property
45  def short_path(self) -> str:
46    return '/'.join(self.full_path.split('/')[-4:])

Returns the short name for this resource.

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

Example: 'gke1'

status: str
48  @property
49  def status(self) -> str:
50    return self._resource_data.get('state', 'STATE_UNSPECIFIED')
create_time: str
52  @property
53  def create_time(self) -> str:
54    return self._resource_data.get('createTime', '')
update_time: str
56  @property
57  def update_time(self) -> str:
58    return self._resource_data.get('updateTime', '')
platform_edition: str
60  @property
61  def platform_edition(self) -> str:
62    return self._resource_data.get('platformEdition', '')
looker_version: str
64  @property
65  def looker_version(self) -> str:
66    return self._resource_data.get('lookerVersion', '')
looker_uri: str
68  @property
69  def looker_uri(self) -> str:
70    return self._resource_data.get('lookerUri', '')
class Operation(gcpdiag.models.Resource):
 73class Operation(models.Resource):
 74  """Represents Looker Core long-running operation."""
 75
 76  def __init__(self, project_id, resource_data):
 77    super().__init__(project_id=project_id)
 78    self._resource_data = resource_data
 79
 80  @property
 81  def full_path(self) -> str:
 82    return self._resource_data.get('name', '')
 83
 84  @property
 85  def name(self) -> str:
 86    return self._resource_data['name'].split('/')[-1]
 87
 88  @property
 89  def metadata(self) -> dict:
 90    return self._resource_data.get('metadata', {})
 91
 92  @property
 93  def done(self) -> bool:
 94    return self._resource_data.get('done', False)
 95
 96  @property
 97  def target(self) -> str:
 98    return self._resource_data.get('metadata', {}).get('target', '')
 99
100  @property
101  def verb(self) -> str:
102    return self._resource_data.get('metadata', {}).get('verb', '')
103
104  @property
105  def status(self) -> str:
106    return 'Completed' if self._resource_data.get('done') else 'In Progress'
107
108  @property
109  def location_id(self) -> str:
110    parts = self._resource_data.get('name', '').split('/')
111    return parts[3] if len(parts) > 3 else ''
112
113  @property
114  def instance_name(self) -> str:
115    parts = self.target.split('/')
116    return parts[5] if len(parts) >= 6 else ''
117
118  @property
119  def operation_type(self) -> str:
120    return self.verb
121
122  @property
123  def action(self) -> str:
124    if self.verb == 'update' and not self.done:
125      return 'Updating Instance'
126    else:
127      parts = self.target.split('/')
128      return parts[6] if len(parts) >= 7 else ''
129
130  @property
131  def create_time(self) -> datetime:
132    create_time_str = self._resource_data.get('metadata', {}).get('createTime', '')
133    if create_time_str:
134      return datetime.fromisoformat(create_time_str.rstrip('Z')).replace(tzinfo=timezone.utc)
135    return datetime.now(timezone.utc)

Represents Looker Core long-running operation.

Operation(project_id, resource_data)
76  def __init__(self, project_id, resource_data):
77    super().__init__(project_id=project_id)
78    self._resource_data = resource_data
full_path: str
80  @property
81  def full_path(self) -> str:
82    return self._resource_data.get('name', '')

Returns the full path of this resource.

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

name: str
84  @property
85  def name(self) -> str:
86    return self._resource_data['name'].split('/')[-1]
metadata: dict
88  @property
89  def metadata(self) -> dict:
90    return self._resource_data.get('metadata', {})
done: bool
92  @property
93  def done(self) -> bool:
94    return self._resource_data.get('done', False)
target: str
96  @property
97  def target(self) -> str:
98    return self._resource_data.get('metadata', {}).get('target', '')
verb: str
100  @property
101  def verb(self) -> str:
102    return self._resource_data.get('metadata', {}).get('verb', '')
status: str
104  @property
105  def status(self) -> str:
106    return 'Completed' if self._resource_data.get('done') else 'In Progress'
location_id: str
108  @property
109  def location_id(self) -> str:
110    parts = self._resource_data.get('name', '').split('/')
111    return parts[3] if len(parts) > 3 else ''
instance_name: str
113  @property
114  def instance_name(self) -> str:
115    parts = self.target.split('/')
116    return parts[5] if len(parts) >= 6 else ''
operation_type: str
118  @property
119  def operation_type(self) -> str:
120    return self.verb
action: str
122  @property
123  def action(self) -> str:
124    if self.verb == 'update' and not self.done:
125      return 'Updating Instance'
126    else:
127      parts = self.target.split('/')
128      return parts[6] if len(parts) >= 7 else ''
create_time: datetime.datetime
130  @property
131  def create_time(self) -> datetime:
132    create_time_str = self._resource_data.get('metadata', {}).get('createTime', '')
133    if create_time_str:
134      return datetime.fromisoformat(create_time_str.rstrip('Z')).replace(tzinfo=timezone.utc)
135    return datetime.now(timezone.utc)
@caching.cached_api_call
def get_instances( context: gcpdiag.models.Context) -> Dict[str, Instance]:
157@caching.cached_api_call
158def get_instances(context: models.Context) -> Dict[str, Instance]:
159  """Get a list of Instances from the given GCP project."""
160  instances: Dict[str, Instance] = {}
161  if not apis.is_enabled(context.project_id, 'looker'):
162    return instances
163  looker_api = apis.get_api('looker', 'v1', context.project_id)
164
165  try:
166    locations_to_scan = _get_locations_to_scan(context, looker_api)
167  except utils.GcpApiError as err:
168    raise err
169
170  for loc_id in locations_to_scan:
171    try:
172      parent_path = f'projects/{context.project_id}/locations/{loc_id}'
173      request = looker_api.projects().locations().instances().list(parent=parent_path)
174      for inst in apis_utils.list_all(
175        request=request,
176        next_function=looker_api.projects().locations().instances().list_next,
177        response_keyword='instances',
178      ):
179        if not context.match_project_resource(resource=inst.get('name', '')):
180          continue
181        instance = Instance(project_id=context.project_id, resource_data=inst)
182        instances[instance.name] = instance
183    except googleapiclient.errors.HttpError as err:
184      logging.warning('Could not list instances for location %s: %s', loc_id, err)
185      continue
186  return instances

Get a list of Instances from the given GCP project.

@caching.cached_api_call
def get_operations( context: gcpdiag.models.Context) -> MutableMapping[str, MutableMapping[str, List[Operation]]]:
189@caching.cached_api_call
190def get_operations(
191  context: models.Context,
192) -> MutableMapping[str, MutableMapping[str, List[Operation]]]:
193  """Get a list of recent operations from the given GCP project."""
194  location_instance_operations: MutableMapping[str, MutableMapping[str, List[Operation]]] = {}
195  if not apis.is_enabled(context.project_id, 'looker'):
196    return location_instance_operations
197
198  looker_api = apis.get_api('looker', 'v1', context.project_id)
199
200  now = context.parameters.get('now', datetime.now(timezone.utc))
201  one_day_ago = now - timedelta(days=1)
202
203  try:
204    locations_to_scan = _get_locations_to_scan(context, looker_api)
205  except utils.GcpApiError:
206    return {}
207
208  for location_id in locations_to_scan:
209    try:
210      op_request_name = f'projects/{context.project_id}/locations/{location_id}'
211      operations_request = looker_api.projects().locations().operations().list(name=op_request_name)
212      for resp_op in apis_utils.list_all(
213        request=operations_request,
214        next_function=looker_api.projects().locations().operations().list_next,
215        response_keyword='operations',
216      ):
217        operation_details = (
218          looker_api.projects()
219          .locations()
220          .operations()
221          .get(name=resp_op['name'])
222          .execute(num_retries=config.API_RETRIES)
223        )
224        operation = Operation(project_id=context.project_id, resource_data=operation_details)
225
226        if operation.create_time >= one_day_ago:
227          location_instance_operations.setdefault(operation.location_id, {}).setdefault(
228            operation.instance_name, []
229          ).append(operation)
230    except googleapiclient.errors.HttpError as err:
231      logging.warning('Could not list operations for location %s: %s', location_id, err)
232      continue
233
234  return location_instance_operations

Get a list of recent operations from the given GCP project.