1# Copyright The Cloud Custodian Authors.
2# SPDX-License-Identifier: Apache-2.0
3from c7n.utils import type_schema, jmespath_search
4from c7n_gcp.query import QueryResourceManager, TypeInfo, ChildTypeInfo, ChildResourceManager
5from c7n_gcp.provider import resources
6from c7n_gcp.actions import MethodAction
7
8
9@resources.register('bq-dataset')
10class DataSet(QueryResourceManager):
11 """GCP resource: https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets
12 """
13 class resource_type(TypeInfo):
14 service = 'bigquery'
15 version = 'v2'
16 component = 'datasets'
17 enum_spec = ('list', 'datasets[]', None)
18 scope = 'project'
19 scope_key = 'projectId'
20 get_requires_event = True
21 id = "id"
22 name = "friendlyName"
23 default_report_fields = [
24 id, name, "description",
25 "creationTime", "lastModifiedTime"]
26 asset_type = "bigquery.googleapis.com/Dataset"
27 scc_type = "google.cloud.bigquery.Dataset"
28 metric_key = "resource.labels.dataset_id"
29 permissions = ('bigquery.datasets.get',)
30 urn_component = "dataset"
31 urn_id_path = "datasetReference.datasetId"
32 labels = True
33 labels_op = 'patch'
34
35 @staticmethod
36 def get(client, event):
37 # dataset creation doesn't include data set name in resource name.
38 if 'protoPayload' in event:
39 _, method = event['protoPayload']['methodName'].split('.')
40 if method not in ('insert', 'update'):
41 raise RuntimeError("unknown event %s" % event)
42 expr = 'protoPayload.serviceData.dataset{}Response.resource.datasetName'.format(
43 method.capitalize())
44 ref = jmespath_search(expr, event)
45 else:
46 ref = event
47 return client.execute_query('get', verb_arguments=ref)
48
49 @staticmethod
50 def get_label_params(resource, all_labels):
51 return {**resource['datasetReference'], 'body': {'labels': all_labels}}
52
53 def augment(self, resources):
54 client = self.get_client()
55 results = []
56 for r in resources:
57 ref = r['datasetReference']
58 results.append(
59 client.execute_query(
60 'get', verb_arguments=ref))
61 return results
62
63
64@resources.register('bq-job')
65class BigQueryJob(QueryResourceManager):
66 """GCP resource: https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs
67 """
68 # its unclear why this is needed
69 class resource_type(TypeInfo):
70 service = 'bigquery'
71 version = 'v2'
72 component = 'jobs'
73 enum_spec = ('list', 'jobs[]', {'allUsers': True, 'projection': 'full'})
74 get_requires_event = True
75 scope = 'project'
76 scope_key = 'projectId'
77 name = id = 'id'
78 default_report_fields = ["id", "user_email", "status.state"]
79 urn_component = "job"
80 # Jobs have labels but no update method, so no labels action
81
82 @staticmethod
83 def get(client, event):
84 return client.execute_query('get', {
85 'projectId': jmespath_search('resource.labels.project_id', event),
86 'jobId': jmespath_search(
87 'protoPayload.metadata.tableCreation.jobName', event
88 ).rsplit('/', 1)[-1]
89 })
90
91 @classmethod
92 def _get_urn_id(cls, resource):
93 jobRef = resource['jobReference']
94 return f"{jobRef['location']}/{jobRef['jobId']}"
95
96
97@resources.register('bq-table')
98class BigQueryTable(ChildResourceManager):
99 """GCP resource: https://cloud.google.com/bigquery/docs/reference/rest/v2/tables
100 """
101
102 class resource_type(ChildTypeInfo):
103 service = 'bigquery'
104 version = 'v2'
105 component = 'tables'
106 enum_spec = ('list', 'tables[]', None)
107 scope_key = 'projectId'
108 id = 'id'
109 name = "friendlyName"
110 default_report_fields = [
111 id, name, "description", "creationTime", "lastModifiedTime", "numRows", "numBytes"]
112 parent_spec = {
113 'resource': 'bq-dataset',
114 'child_enum_params': [
115 ('datasetReference.datasetId', 'datasetId'),
116 ],
117 'parent_get_params': [
118 ('tableReference.projectId', 'projectId'),
119 ('tableReference.datasetId', 'datasetId'),
120 ]
121 }
122 asset_type = "bigquery.googleapis.com/Table"
123 urn_component = "table"
124 urn_id_path = "tableReference.tableId"
125 labels = True
126 labels_op = 'patch'
127
128 @classmethod
129 def _get_urn_id(cls, resource):
130 tableRef = resource['tableReference']
131 return f"{tableRef['datasetId']}/{tableRef['tableId']}"
132
133 @staticmethod
134 def get(client, event):
135 return client.execute_query('get', {
136 'projectId': event['project_id'],
137 'datasetId': event['dataset_id'],
138 'tableId': event['resourceName'].rsplit('/', 1)[-1]
139 })
140
141 @staticmethod
142 def get_label_params(resource, all_labels):
143 return {**resource['tableReference'], 'body': {'labels': all_labels}}
144
145 def augment(self, resources):
146 client = self.get_client()
147 results = []
148 for r in resources:
149 ref = r['tableReference']
150 results.append(
151 client.execute_query(
152 'get', verb_arguments=ref))
153 return results
154
155
156@BigQueryTable.action_registry.register('delete')
157class DeleteBQTable(MethodAction):
158 schema = type_schema('delete')
159 method_spec = {'op': 'delete'}
160 permissions = ('bigquery.tables.get', 'bigquery.tables.delete')
161
162 @staticmethod
163 def get_resource_params(model, r):
164 return {
165 'projectId': r['tableReference']['projectId'],
166 'datasetId': r['tableReference']['datasetId'],
167 'tableId': r['tableReference']['tableId']
168 }
169
170
171@DataSet.action_registry.register('delete')
172class DeleteDataSet(MethodAction):
173 schema = type_schema('delete')
174 method_spec = {'op': 'delete'}
175 permissions = ('bigquery.datasets.get', 'bigquery.datasets.delete')
176
177 @staticmethod
178 def get_resource_params(model, r):
179 return {
180 'projectId': r['datasetReference']['projectId'],
181 'datasetId': r['datasetReference']['datasetId']
182 }