Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/c7n_gcp/resources/sql.py: 73%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

158 statements  

1# Copyright The Cloud Custodian Authors. 

2# SPDX-License-Identifier: Apache-2.0 

3 

4import re 

5 

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 

15 

16 

17@resources.register('sql-instance') 

18class SqlInstance(QueryResourceManager): 

19 

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" 

36 

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]}) 

42 

43 @staticmethod 

44 def get_metric_resource_name(resource): 

45 return "{}:{}".format(resource["project"], resource["name"]) 

46 

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 } 

60 

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 

66 

67 

68SqlInstance.filter_registry.register('offhour', OffHour) 

69SqlInstance.filter_registry.register('onhour', OnHour) 

70 

71 

72class SqlInstanceAction(MethodAction): 

73 

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} 

78 

79 

80@SqlInstance.action_registry.register('delete') 

81class SqlInstanceDelete(SqlInstanceAction): 

82 

83 schema = type_schema('delete', force={'type': 'boolean'}) 

84 method_spec = {'op': 'delete'} 

85 path_param_re = re.compile( 

86 '.*?/projects/(.*?)/instances/(.*)') 

87 

88 def process(self, resources): 

89 if self.data.get('force'): 

90 self.disable_protection(resources) 

91 super().process(resources) 

92 

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) 

98 

99 

100@SqlInstance.action_registry.register('stop') 

101class SqlInstanceStop(MethodAction): 

102 

103 schema = type_schema('stop') 

104 method_spec = {'op': 'patch'} 

105 path_param_re = re.compile('.*?/projects/(.*?)/instances/(.*)') 

106 method_perm = 'update' 

107 

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'}}} 

114 

115 

116@SqlInstance.action_registry.register('start') 

117class SqlInstanceStart(MethodAction): 

118 

119 schema = type_schema('start') 

120 method_spec = {'op': 'patch'} 

121 path_param_re = re.compile('.*?/projects/(.*?)/instances/(.*)') 

122 method_perm = 'update' 

123 

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'}}} 

130 

131 

132@SqlInstance.action_registry.register('set-deletion-protection') 

133class SqlInstanceEnableDeletion(MethodAction): 

134 

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' 

141 

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 } 

154 

155 

156@SqlInstance.action_registry.register('set-high-availability') 

157class SqlInstanceHighAvailability(MethodAction): 

158 

159 schema = type_schema( 

160 'set-high-availability', 

161 value={'type': 'boolean', 'required': True}) 

162 method_spec = {'op': 'patch'} 

163 path_param_re = re.compile('.*?/projects/(.*?)/instances/(.*)') 

164 method_perm = 'update' 

165 

166 def get_resource_params(self, model, resource): 

167 if self.data['value'] is False: 

168 availabilityType = 'ZONAL' 

169 else: 

170 availabilityType = 'REGIONAL' 

171 

172 project, instance = self.path_param_re.match( 

173 resource['selfLink']).groups() 

174 return { 

175 'project': project, 

176 'instance': instance, 

177 'body': { 

178 'settings': { 

179 'availabilityType': availabilityType 

180 } 

181 } 

182 } 

183 

184 

185class SQLInstanceChildTypeInfo(ChildTypeInfo): 

186 service = 'sqladmin' 

187 version = 'v1beta4' 

188 parent_spec = { 

189 'resource': 'sql-instance', 

190 'child_enum_params': [ 

191 ('name', 'instance') 

192 ] 

193 } 

194 perm_service = 'cloudsql' 

195 

196 @classmethod 

197 def _get_location(cls, resource): 

198 return super()._get_location(cls.get_parent(resource)) 

199 

200 @classmethod 

201 def _get_urn_id(cls, resource): 

202 return f"{resource['instance']}/{resource[cls.id]}" 

203 

204 

205@resources.register('sql-user') 

206class SqlUser(ChildResourceManager): 

207 

208 class resource_type(SQLInstanceChildTypeInfo): 

209 component = 'users' 

210 enum_spec = ('list', 'items[]', None) 

211 name = id = 'name' 

212 default_report_fields = ["name", "project", "instance"] 

213 urn_component = "user" 

214 

215 

216class SqlInstanceChildWithSelfLink(ChildResourceManager): 

217 """A ChildResourceManager for resources that reference SqlInstance in selfLink. 

218 """ 

219 

220 def _get_parent_resource_info(self, child_instance): 

221 """ 

222 :param child_instance: a dictionary to get parent parameters from 

223 :return: project_id and database_id extracted from child_instance 

224 """ 

225 return {'project_id': re.match('.*?/projects/(.*?)/instances/.*', 

226 child_instance['selfLink']).group(1), 

227 'database_id': child_instance['instance']} 

228 

229 

230@resources.register('sql-backup-run') 

231class SqlBackupRun(SqlInstanceChildWithSelfLink): 

232 """GCP Resource 

233 https://cloud.google.com/sql/docs/mysql/admin-api/rest/v1beta4/backupRuns 

234 """ 

235 class resource_type(SQLInstanceChildTypeInfo): 

236 component = 'backupRuns' 

237 enum_spec = ('list', 'items[]', None) 

238 get_requires_event = True 

239 name = id = 'id' 

240 default_report_fields = [ 

241 name, "status", "instance", "location", "enqueuedTime", "startTime", "endTime"] 

242 urn_component = "backup-run" 

243 

244 @staticmethod 

245 def get(client, event): 

246 project = jmespath_search('protoPayload.response.targetProject', event) 

247 instance = jmespath_search('protoPayload.response.targetId', event) 

248 insert_time = jmespath_search('protoPayload.response.insertTime', event) 

249 parameters = {'project': project, 

250 'instance': instance, 

251 'id': SqlBackupRun.resource_type._from_insert_time_to_id(insert_time)} 

252 return client.execute_command('get', parameters) 

253 

254 @staticmethod 

255 def _from_insert_time_to_id(insert_time): 

256 """ 

257 Backup Run id is not available in a log record directly. 

258 Fortunately, as it is an integer timestamp representation, 

259 it can be retrieved by converting raw insert_time value. 

260 

261 :param insert_time: a UTC ISO formatted date time string 

262 :return: an integer number of microseconds since unix epoch 

263 """ 

264 delta = parse(insert_time).replace(tzinfo=None) - datetime.utcfromtimestamp(0) 

265 return int(delta.total_seconds()) * 1000 + int(delta.microseconds / 1000) 

266 

267 

268@resources.register('sql-ssl-cert') 

269class SqlSslCert(SqlInstanceChildWithSelfLink): 

270 """GCP Resource 

271 https://cloud.google.com/sql/docs/mysql/admin-api/rest/v1beta4/sslCerts 

272 """ 

273 class resource_type(SQLInstanceChildTypeInfo): 

274 component = 'sslCerts' 

275 enum_spec = ('list', 'items[]', None) 

276 get_requires_event = True 

277 id = 'sha1Fingerprint' 

278 name = "commonName" 

279 default_report_fields = [ 

280 id, name, "instance", "expirationTime"] 

281 urn_component = "ssl-cert" 

282 

283 @staticmethod 

284 def get(client, event): 

285 self_link = jmespath_search('protoPayload.response.clientCert.certInfo.selfLink', event) 

286 self_link_re = '.*?/projects/(.*?)/instances/(.*?)/sslCerts/(.*)' 

287 project, instance, sha_1_fingerprint = re.match(self_link_re, self_link).groups() 

288 parameters = {'project': project, 

289 'instance': instance, 

290 'sha1Fingerprint': sha_1_fingerprint} 

291 return client.execute_command('get', parameters)