Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/c7n_gcp/resources/sql.py: 73%
158 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:51 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:51 +0000
1# Copyright The Cloud Custodian Authors.
2# SPDX-License-Identifier: Apache-2.0
4import re
6from c7n.utils import type_schema, jmespath_search
7from c7n.filters.offhours import OffHour, OnHour
8from c7n_gcp.actions import MethodAction
9from c7n_gcp.provider import resources
10from c7n_gcp.query import (
11 QueryResourceManager, TypeInfo, ChildResourceManager, ChildTypeInfo
12)
13from datetime import datetime
14from dateutil.parser import parse
17@resources.register('sql-instance')
18class SqlInstance(QueryResourceManager):
20 class resource_type(TypeInfo):
21 service = 'sqladmin'
22 version = 'v1beta4'
23 component = 'instances'
24 enum_spec = ('list', 'items[]', None)
25 scope = 'project'
26 labels = True
27 labels_op = 'patch'
28 name = id = 'name'
29 default_report_fields = [
30 "name", "state", "databaseVersion", "settings.tier", "settings.dataDiskSizeGb"]
31 asset_type = "sqladmin.googleapis.com/Instance"
32 scc_type = "google.cloud.sql.Instance"
33 metric_key = 'resource.labels.database_id'
34 perm_service = 'cloudsql'
35 urn_component = "instance"
37 @staticmethod
38 def get(client, resource_info):
39 return client.execute_command(
40 'get', {'project': resource_info['project_id'],
41 'instance': resource_info['database_id'].rsplit(':', 1)[-1]})
43 @staticmethod
44 def get_metric_resource_name(resource):
45 return "{}:{}".format(resource["project"], resource["name"])
47 @staticmethod
48 def get_label_params(resource, all_labels):
49 path_param_re = re.compile('.*?/projects/(.*?)/instances/(.*)')
50 project, instance = path_param_re.match(
51 resource['selfLink']).groups()
52 return {
53 'project': project, 'instance': instance,
54 'body': {
55 'settings': {
56 'userLabels': all_labels
57 }
58 }
59 }
61 def augment(self, resources):
62 for r in resources:
63 if 'userLabels' in r['settings']:
64 r['labels'] = r['settings']['userLabels']
65 return resources
68SqlInstance.filter_registry.register('offhour', OffHour)
69SqlInstance.filter_registry.register('onhour', OnHour)
72class SqlInstanceAction(MethodAction):
74 def get_resource_params(self, model, resource):
75 project, instance = self.path_param_re.match(
76 resource['selfLink']).groups()
77 return {'project': project, 'instance': instance}
80@SqlInstance.action_registry.register('delete')
81class SqlInstanceDelete(SqlInstanceAction):
83 schema = type_schema('delete', force={'type': 'boolean'})
84 method_spec = {'op': 'delete'}
85 path_param_re = re.compile(
86 '.*?/projects/(.*?)/instances/(.*)')
88 def process(self, resources):
89 if self.data.get('force'):
90 self.disable_protection(resources)
91 super().process(resources)
93 def disable_protection(self, resources):
94 deletion_protected = [
95 r for r in resources if r['settings'].get('deletionProtectionEnabled')]
96 disable_protection = SqlInstanceEnableDeletion({}, self.manager)
97 disable_protection.process(deletion_protected)
100@SqlInstance.action_registry.register('stop')
101class SqlInstanceStop(MethodAction):
103 schema = type_schema('stop')
104 method_spec = {'op': 'patch'}
105 path_param_re = re.compile('.*?/projects/(.*?)/instances/(.*)')
106 method_perm = 'update'
108 def get_resource_params(self, model, resource):
109 project, instance = self.path_param_re.match(
110 resource['selfLink']).groups()
111 return {'project': project,
112 'instance': instance,
113 'body': {'settings': {'activationPolicy': 'NEVER'}}}
116@SqlInstance.action_registry.register('start')
117class SqlInstanceStart(MethodAction):
119 schema = type_schema('start')
120 method_spec = {'op': 'patch'}
121 path_param_re = re.compile('.*?/projects/(.*?)/instances/(.*)')
122 method_perm = 'update'
124 def get_resource_params(self, model, resource):
125 project, instance = self.path_param_re.match(
126 resource['selfLink']).groups()
127 return {'project': project,
128 'instance': instance,
129 'body': {'settings': {'activationPolicy': 'ALWAYS'}}}
132@SqlInstance.action_registry.register('set-deletion-protection')
133class SqlInstanceEnableDeletion(MethodAction):
135 schema = type_schema(
136 'set-deletion-protection',
137 value={'type': 'boolean'})
138 method_spec = {'op': 'patch'}
139 path_param_re = re.compile('.*?/projects/(.*?)/instances/(.*)')
140 method_perm = 'update'
142 def get_resource_params(self, model, resource):
143 project, instance = self.path_param_re.match(
144 resource['selfLink']).groups()
145 return {
146 'project': project,
147 'instance': instance,
148 'body': {
149 'settings': {
150 'deletionProtectionEnabled': str(self.data.get('value', True)).lower()
151 }
152 }
153 }
155@SqlInstance.action_registry.register('set-high-availability')
156class SqlInstanceHighAvailability(MethodAction):
158 schema = type_schema(
159 'set-high-availability',
160 value={'type': 'boolean', 'required' : True})
161 method_spec = {'op': 'patch'}
162 path_param_re = re.compile('.*?/projects/(.*?)/instances/(.*)')
163 method_perm = 'update'
165 def get_resource_params(self, model, resource):
166 if self.data['value'] is False :
167 availabilityType = 'ZONAL'
168 else:
169 availabilityType = 'REGIONAL'
171 project, instance = self.path_param_re.match(
172 resource['selfLink']).groups()
173 return {
174 'project': project,
175 'instance': instance,
176 'body': {
177 'settings': {
178 'availabilityType': availabilityType
179 }
180 }
181 }
184class SQLInstanceChildTypeInfo(ChildTypeInfo):
185 service = 'sqladmin'
186 version = 'v1beta4'
187 parent_spec = {
188 'resource': 'sql-instance',
189 'child_enum_params': [
190 ('name', 'instance')
191 ]
192 }
193 perm_service = 'cloudsql'
195 @classmethod
196 def _get_location(cls, resource):
197 return super()._get_location(cls.get_parent(resource))
199 @classmethod
200 def _get_urn_id(cls, resource):
201 return f"{resource['instance']}/{resource[cls.id]}"
204@resources.register('sql-user')
205class SqlUser(ChildResourceManager):
207 class resource_type(SQLInstanceChildTypeInfo):
208 component = 'users'
209 enum_spec = ('list', 'items[]', None)
210 name = id = 'name'
211 default_report_fields = ["name", "project", "instance"]
212 urn_component = "user"
215class SqlInstanceChildWithSelfLink(ChildResourceManager):
216 """A ChildResourceManager for resources that reference SqlInstance in selfLink.
217 """
219 def _get_parent_resource_info(self, child_instance):
220 """
221 :param child_instance: a dictionary to get parent parameters from
222 :return: project_id and database_id extracted from child_instance
223 """
224 return {'project_id': re.match('.*?/projects/(.*?)/instances/.*',
225 child_instance['selfLink']).group(1),
226 'database_id': child_instance['instance']}
229@resources.register('sql-backup-run')
230class SqlBackupRun(SqlInstanceChildWithSelfLink):
231 """GCP Resource
232 https://cloud.google.com/sql/docs/mysql/admin-api/rest/v1beta4/backupRuns
233 """
234 class resource_type(SQLInstanceChildTypeInfo):
235 component = 'backupRuns'
236 enum_spec = ('list', 'items[]', None)
237 get_requires_event = True
238 name = id = 'id'
239 default_report_fields = [
240 name, "status", "instance", "location", "enqueuedTime", "startTime", "endTime"]
241 urn_component = "backup-run"
243 @staticmethod
244 def get(client, event):
245 project = jmespath_search('protoPayload.response.targetProject', event)
246 instance = jmespath_search('protoPayload.response.targetId', event)
247 insert_time = jmespath_search('protoPayload.response.insertTime', event)
248 parameters = {'project': project,
249 'instance': instance,
250 'id': SqlBackupRun.resource_type._from_insert_time_to_id(insert_time)}
251 return client.execute_command('get', parameters)
253 @staticmethod
254 def _from_insert_time_to_id(insert_time):
255 """
256 Backup Run id is not available in a log record directly.
257 Fortunately, as it is an integer timestamp representation,
258 it can be retrieved by converting raw insert_time value.
260 :param insert_time: a UTC ISO formatted date time string
261 :return: an integer number of microseconds since unix epoch
262 """
263 delta = parse(insert_time).replace(tzinfo=None) - datetime.utcfromtimestamp(0)
264 return int(delta.total_seconds()) * 1000 + int(delta.microseconds / 1000)
267@resources.register('sql-ssl-cert')
268class SqlSslCert(SqlInstanceChildWithSelfLink):
269 """GCP Resource
270 https://cloud.google.com/sql/docs/mysql/admin-api/rest/v1beta4/sslCerts
271 """
272 class resource_type(SQLInstanceChildTypeInfo):
273 component = 'sslCerts'
274 enum_spec = ('list', 'items[]', None)
275 get_requires_event = True
276 id = 'sha1Fingerprint'
277 name = "commonName"
278 default_report_fields = [
279 id, name, "instance", "expirationTime"]
280 urn_component = "ssl-cert"
282 @staticmethod
283 def get(client, event):
284 self_link = jmespath_search('protoPayload.response.clientCert.certInfo.selfLink', event)
285 self_link_re = '.*?/projects/(.*?)/instances/(.*?)/sslCerts/(.*)'
286 project, instance, sha_1_fingerprint = re.match(self_link_re, self_link).groups()
287 parameters = {'project': project,
288 'instance': instance,
289 'sha1Fingerprint': sha_1_fingerprint}
290 return client.execute_command('get', parameters)