1# Copyright The Cloud Custodian Authors.
2# SPDX-License-Identifier: Apache-2.0
3from c7n.utils import type_schema, local_session
4from c7n_gcp.actions import MethodAction, SetIamPolicy
5from c7n_gcp.filters import IamPolicyFilter, TimeRangeFilter
6from c7n_gcp.provider import resources
7from c7n_gcp.query import QueryResourceManager, TypeInfo, ChildTypeInfo, ChildResourceManager
8
9
10@resources.register('spanner-instance')
11class SpannerInstance(QueryResourceManager):
12 """
13 https://cloud.google.com/spanner/docs/reference/rest/v1/projects.instances
14 """
15 class resource_type(TypeInfo):
16 service = 'spanner'
17 version = 'v1'
18 component = 'projects.instances'
19 enum_spec = ('list', 'instances[]', None)
20 scope_key = 'parent'
21 scope_template = 'projects/{}'
22 name = id = 'name'
23 default_report_fields = [
24 "name", "displayName", "nodeCount", "state", "config"]
25 labels = True
26 labels_op = 'patch'
27 asset_type = "spanner.googleapis.com/Instance"
28 metric_key = "resource.labels.instance_id"
29 urn_component = "instance"
30 urn_id_segments = (-1,) # Just use the last segment of the id in the URN
31
32 @staticmethod
33 def get(client, resource_info):
34 return client.execute_command(
35 'get', {'name': resource_info['resourceName']}
36 )
37
38 @staticmethod
39 def get_label_params(resource, all_labels):
40 return {'name': resource['name'],
41 'body': {
42 'instance': {
43 'labels': all_labels
44 },
45 'field_mask': ', '.join(['labels'])}}
46
47 @staticmethod
48 def get_metric_resource_name(resource):
49 # Extract instance name from the full resource name
50 return resource["name"].split("/")[-1]
51
52
53@resources.register('spanner-backup')
54class SpannerInstanceBackup(ChildResourceManager):
55 """GC resource: https://cloud.google.com/spanner/docs/reference/rest/v1/projects.instances.backups"""
56 class resource_type(ChildTypeInfo):
57 service = 'spanner'
58 version = 'v1'
59 component = 'projects.instances.backups'
60 enum_spec = ('list', 'backups[]', None)
61 scope = 'parent'
62 name = id = 'name'
63 parent_spec = {
64 'resource': 'spanner-instance',
65 'child_enum_params': {
66 ('instances', 'parent')},
67 'use_child_query': True,
68 }
69 default_report_fields = ['name', 'expireTime']
70 permissions = ('spanner.backups.list',)
71 asset_type = 'spanner.googleapis.com/Backup'
72 allow_metrics_filters = False
73
74 def _get_child_enum_args(self, parent_instance):
75 return {
76 'parent': 'projects/{}/instances/{}'.format(
77 local_session(self.session_factory).get_default_project(),
78 parent_instance['displayName'],
79 )
80 }
81
82
83@SpannerInstanceBackup.filter_registry.register('time-range')
84class SpannerInstanceBackupTimeRangeFilter(TimeRangeFilter):
85 """Filters spanner instance backups based on a time range
86
87 .. code-block:: yaml
88
89 policies:
90 - name: spanner_backup_expiration_time_30_days_or_more
91 description: |
92 Cloud Spanner backup is created with an expiration date of 29 days or less
93 resource: gcp.spanner-backup
94 filters:
95 - type: time-range
96 value: 29
97 """
98 permissions = ('spanner.backups.list',)
99 create_time_field_name = 'createTime'
100 expire_time_field_name = 'expireTime'
101
102
103@SpannerInstanceBackup.filter_registry.register('iam-policy')
104class SpannerInstanceBackupIamPolicyFilter(IamPolicyFilter):
105 """
106 Overrides the base implementation to process spanner instance backup resources correctly.
107 """
108 permissions = ('spanner.backups.getIamPolicy',)
109
110
111@SpannerInstance.filter_registry.register('iam-policy')
112class SpannerInstanceIamPolicyFilter(IamPolicyFilter):
113 """
114 Overrides the base implementation to process spanner instance resources correctly.
115 """
116 permissions = ('spanner.instances.getIamPolicy',)
117
118
119@SpannerInstance.action_registry.register('delete')
120class SpannerInstanceDelete(MethodAction):
121 """The action is used for spanner instances delete.
122
123 GCP action is https://cloud.google.com/spanner/docs/reference/rest/v1/projects.instances/delete
124
125 :Example:
126
127 .. code-block:: yaml
128
129 policies:
130 - name: gcp-spanner-instances-delete
131 resource: gcp.spanner-instance
132 filters:
133 - type: value
134 key: nodeCount
135 op: gte
136 value: 2
137 actions:
138 - type: delete
139 """
140 schema = type_schema('delete')
141 method_spec = {'op': 'delete'}
142
143 def get_resource_params(self, model, resource):
144 return {'name': resource['name']}
145
146
147@SpannerInstance.action_registry.register('set')
148class SpannerInstancePatch(MethodAction):
149 """The action is used for spanner instances nodeCount patch.
150
151 GCP action is https://cloud.google.com/spanner/docs/reference/rest/v1/projects.instances/patch
152
153 :Example:
154
155 .. code-block:: yaml
156
157 policies:
158 - name: gcp-spanner-instances-change-node-count
159 resource: gcp.spanner-instance
160 filters:
161 - type: value
162 key: nodeCount
163 op: gte
164 value: 2
165 actions:
166 - type: set
167 nodeCount: 1
168 """
169 schema = type_schema('set', required=['nodeCount'],
170 **{'nodeCount': {'type': 'number'}})
171 method_spec = {'op': 'patch'}
172 method_perm = 'update'
173
174 def get_resource_params(self, model, resource):
175 result = {'name': resource['name'],
176 'body': {
177 'instance': {
178 'nodeCount': self.data['nodeCount']
179 },
180 'field_mask': ', '.join(['nodeCount'])}
181 }
182 return result
183
184
185SpannerInstance.action_registry.register('set-iam-policy', SetIamPolicy)
186
187
188@resources.register('spanner-database-instance')
189class SpannerDatabaseInstance(ChildResourceManager):
190 """GCP resource:
191 https://cloud.google.com/spanner/docs/reference/rest/v1/projects.instances.databases
192 """
193 def _get_parent_resource_info(self, child_instance):
194 resource_name = None
195 if child_instance['name'] is not None:
196 resource_names = child_instance['name'].split('/databases')
197 if len(resource_names) > 0:
198 resource_name = resource_names[0]
199 return {
200 'resourceName': resource_name
201 }
202
203 class resource_type(ChildTypeInfo):
204 service = 'spanner'
205 version = 'v1'
206 component = 'projects.instances.databases'
207 enum_spec = ('list', 'databases[]', None)
208 name = id = 'name'
209 scope = None
210 parent_spec = {
211 'resource': 'spanner-instance',
212 'child_enum_params': [
213 ('name', 'parent')
214 ]
215 }
216 default_report_fields = ["name", "state", "createTime"]
217 asset_type = "spanner.googleapis.com/Database"
218 urn_component = "database"
219 urn_id_segments = (3, 5)
220 allow_metrics_filters = False
221
222 @staticmethod
223 def get(client, resource_info):
224 return client.execute_command(
225 'get', {
226 'name': resource_info['resourceName']}
227 )
228
229
230@SpannerDatabaseInstance.filter_registry.register('iam-policy')
231class SpannerDatabaseInstanceIamPolicyFilter(IamPolicyFilter):
232 """
233 Overrides the base implementation to process spanner database resources correctly.
234 """
235 permissions = ('spanner.databases.getIamPolicy',)
236
237
238SpannerDatabaseInstance.action_registry.register('set-iam-policy', SetIamPolicy)
239
240
241@SpannerDatabaseInstance.action_registry.register('delete')
242class SpannerDatabaseInstanceDropDatabase(MethodAction):
243 """The action is used for databases deleting.
244
245 GCP action is https://cloud.google.com/spanner/docs
246 /reference/rest/v1/projects.instances.databases/dropDatabase.
247
248 :Example:
249
250 .. code-block:: yaml
251
252 policies:
253 - name: gcp-spanner-instance-databases-delete
254 resource: gcp.spanner-database-instance
255 filters:
256 - type: value
257 key: name
258 op: contains
259 value: dev
260 actions:
261 - type: delete
262 """
263 schema = type_schema('dropDatabase', **{'type': {'enum': ['delete']}})
264 method_spec = {'op': 'dropDatabase'}
265 method_perm = 'drop'
266
267 def get_resource_params(self, model, resource):
268 return {'database': resource['name']}