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

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@SqlInstance.action_registry.register('set-high-availability') 

156class SqlInstanceHighAvailability(MethodAction): 

157 

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' 

164 

165 def get_resource_params(self, model, resource): 

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

167 availabilityType = 'ZONAL' 

168 else: 

169 availabilityType = 'REGIONAL' 

170 

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 } 

182 

183 

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' 

194 

195 @classmethod 

196 def _get_location(cls, resource): 

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

198 

199 @classmethod 

200 def _get_urn_id(cls, resource): 

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

202 

203 

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

205class SqlUser(ChildResourceManager): 

206 

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" 

213 

214 

215class SqlInstanceChildWithSelfLink(ChildResourceManager): 

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

217 """ 

218 

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

227 

228 

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" 

242 

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) 

252 

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. 

259 

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) 

265 

266 

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" 

281 

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)