Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/c7n_gcp/resources/compute.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

328 statements  

1# Copyright The Cloud Custodian Authors. 

2# SPDX-License-Identifier: Apache-2.0 

3 

4import re 

5 

6from datetime import datetime 

7 

8from c7n.utils import local_session, type_schema 

9 

10from c7n_gcp.actions import MethodAction 

11from c7n_gcp.filters import IamPolicyFilter 

12from c7n_gcp.filters.iampolicy import IamPolicyValueFilter 

13from c7n_gcp.provider import resources 

14from c7n_gcp.query import QueryResourceManager, TypeInfo, ChildResourceManager, ChildTypeInfo 

15 

16from c7n.filters.core import ValueFilter 

17from c7n.filters.offhours import OffHour, OnHour 

18 

19 

20@resources.register('instance') 

21class Instance(QueryResourceManager): 

22 

23 class resource_type(TypeInfo): 

24 service = 'compute' 

25 version = 'v1' 

26 component = 'instances' 

27 enum_spec = ('aggregatedList', 'items.*.instances[]', None) 

28 scope = 'project' 

29 name = id = 'name' 

30 labels = True 

31 default_report_fields = ['name', 'status', 'creationTimestamp', 'machineType', 'zone'] 

32 asset_type = "compute.googleapis.com/Instance" 

33 scc_type = "google.compute.Instance" 

34 metric_key = 'metric.labels.instance_name' 

35 urn_component = "instance" 

36 urn_zonal = True 

37 

38 @staticmethod 

39 def get(client, resource_info): 

40 # The api docs for compute instance get are wrong, 

41 # they spell instance as resourceId 

42 return client.execute_command( 

43 'get', {'project': resource_info['project_id'], 

44 'zone': resource_info['zone'], 

45 'instance': resource_info[ 

46 'resourceName'].rsplit('/', 1)[-1]}) 

47 

48 @staticmethod 

49 def get_label_params(resource, all_labels): 

50 project, zone, instance = re.match( 

51 '.*?/projects/(.*?)/zones/(.*?)/instances/(.*)', 

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

53 return {'project': project, 'zone': zone, 'instance': instance, 

54 'body': { 

55 'labels': all_labels, 

56 'labelFingerprint': resource['labelFingerprint'] 

57 }} 

58 

59 @classmethod 

60 def refresh(cls, client, resource): 

61 project, zone, name = re.match( 

62 '.*?/projects/(.*?)/zones/(.*?)/instances/(.*)', 

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

64 return cls.get( 

65 client, 

66 { 

67 'project_id': project, 

68 'zone': zone, 

69 'resourceName': name 

70 } 

71 ) 

72 

73 

74Instance.filter_registry.register('offhour', OffHour) 

75Instance.filter_registry.register('onhour', OnHour) 

76 

77 

78@Instance.filter_registry.register('effective-firewall') 

79class EffectiveFirewall(ValueFilter): 

80 """Filters instances by their effective firewall rules. 

81 See `getEffectiveFirewalls 

82 <https://cloud.google.com/compute/docs/reference/rest/v1/instances/getEffectiveFirewalls>`_ 

83 for valid fields. 

84 

85 :example: 

86 

87 Filter all instances that have a firewall rule that allows public 

88 acess 

89 

90 .. code-block:: yaml 

91 

92 policies: 

93 - name: find-publicly-accessable-instances 

94 resource: gcp.instance 

95 filters: 

96 - type: effective-firewall 

97 key: firewalls[*].sourceRanges[] 

98 op: contains 

99 value: "0.0.0.0/0" 

100 """ 

101 

102 schema = type_schema('effective-firewall', rinherit=ValueFilter.schema) 

103 permissions = ('compute.instances.getEffectiveFirewalls',) 

104 

105 def get_resource_params(self, resource): 

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

107 project, zone = path_param_re.match(resource['selfLink']).groups() 

108 return {'project': project, 'zone': zone, 'instance': resource["name"]} 

109 

110 def process_resource(self, client, resource): 

111 params = self.get_resource_params(resource) 

112 effective_firewalls = [] 

113 for interface in resource["networkInterfaces"]: 

114 effective_firewalls.append(client.execute_command( 

115 'getEffectiveFirewalls', {"networkInterface": interface["name"], **params})) 

116 return super(EffectiveFirewall, self).process(effective_firewalls, None) 

117 

118 def get_client(self, session, model): 

119 return session.client( 

120 model.service, model.version, model.component) 

121 

122 def process(self, resources, event=None): 

123 model = self.manager.get_model() 

124 session = local_session(self.manager.session_factory) 

125 client = self.get_client(session, model) 

126 return [r for r in resources if self.process_resource(client, r)] 

127 

128 

129class InstanceAction(MethodAction): 

130 

131 def get_resource_params(self, model, resource): 

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

133 project, zone, instance = path_param_re.match(resource['selfLink']).groups() 

134 return {'project': project, 'zone': zone, 'instance': instance} 

135 

136 

137@Instance.action_registry.register('start') 

138class Start(InstanceAction): 

139 

140 schema = type_schema('start') 

141 method_spec = {'op': 'start'} 

142 attr_filter = ('status', ('TERMINATED',)) 

143 

144 

145@Instance.action_registry.register('stop') 

146class Stop(InstanceAction): 

147 """Caution: `stop` in GCP is closer to terminate in terms of effect. 

148 

149 The `discard_local_ssd` specifies if local SSD should be discarded 

150 or not while stopping the instance. The default behavior from 

151 Google Cloud console is to keep the local SSD. Default 

152 `discard_local_ssd` is False. 

153 https://cloud.google.com/compute/docs/instances/stop-start-instance#stop-vm-local-ssd 

154 

155 `suspend` is closer to stop in other providers. 

156 

157 See https://cloud.google.com/compute/docs/instances/instance-life-cycle 

158 

159 """ 

160 

161 schema = type_schema('stop', discard_local_ssd={'type': 'boolean'}) 

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

163 attr_filter = ('status', ('RUNNING',)) 

164 

165 def get_resource_params(self, model, resource): 

166 params = super().get_resource_params(model, resource) 

167 

168 # support stopping instance with local SSD, it requires to pass an additional param to 

169 # the stop request to discard local SSD (true/false) 

170 discard_local_ssd = self.data.get('discard_local_ssd', False) 

171 params['discardLocalSsd'] = discard_local_ssd 

172 

173 return params 

174 

175 

176@Instance.action_registry.register('suspend') 

177class Suspend(InstanceAction): 

178 

179 schema = type_schema('suspend') 

180 method_spec = {'op': 'suspend'} 

181 attr_filter = ('status', ('RUNNING',)) 

182 

183 

184@Instance.action_registry.register('resume') 

185class Resume(InstanceAction): 

186 

187 schema = type_schema('resume') 

188 method_spec = {'op': 'resume'} 

189 attr_filter = ('status', ('SUSPENDED',)) 

190 

191 

192@Instance.action_registry.register('delete') 

193class Delete(InstanceAction): 

194 

195 schema = type_schema('delete') 

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

197 

198 

199@Instance.action_registry.register('detach-disks') 

200class DetachDisks(MethodAction): 

201 """ 

202 `Detaches <https://cloud.google.com/compute/docs/reference/rest/v1/instances/detachDisk>`_ 

203 all disks from instance. The action does not specify any parameters. 

204 

205 It may be useful to be used before deleting instances to not delete disks 

206 that are set to auto delete. 

207 

208 :Example: 

209 

210 .. code-block:: yaml 

211 

212 policies: 

213 - name: gcp-instance-detach-disks 

214 resource: gcp.instance 

215 filters: 

216 - type: value 

217 key: name 

218 value: instance-template-to-detahc 

219 actions: 

220 - type: detach-disks 

221 """ 

222 schema = type_schema('detach-disks') 

223 attr_filter = ('status', ('TERMINATED',)) 

224 method_spec = {'op': 'detachDisk'} 

225 path_param_re = re.compile( 

226 '.*?/projects/(.*?)/zones/(.*?)/instances/(.*)') 

227 

228 def validate(self): 

229 pass 

230 

231 def process_resource_set(self, client, model, resources): 

232 for resource in resources: 

233 self.process_resource(client, resource) 

234 

235 def process_resource(self, client, resource): 

236 op_name = 'detachDisk' 

237 

238 project, zone, instance = self.path_param_re.match( 

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

240 

241 base_params = {'project': project, 'zone': zone, 'instance': instance} 

242 for disk in resource.get('disks', []): 

243 params = dict(base_params, deviceName=disk['deviceName']) 

244 self.invoke_api(client, op_name, params) 

245 

246 

247@Instance.action_registry.register('create-machine-image') 

248class CreateMachineImage(MethodAction): 

249 """ 

250 `Creates <https://cloud.google.com/compute/docs/reference/rest/beta/machineImages/insert>`_ 

251 Machine Image from instance. 

252 

253 The `name_format` specifies name of image in python `format string <https://pyformat.info/>` 

254 

255 Inside format string there are defined variables: 

256 - `now`: current time 

257 - `instance`: whole instance resource 

258 

259 Default name format is `{instance[name]}` 

260 

261 :Example: 

262 

263 .. code-block:: yaml 

264 

265 policies: 

266 - name: gcp-create-machine-image 

267 resource: gcp.instance 

268 filters: 

269 - type: value 

270 key: name 

271 value: instance-create-to-make-image 

272 actions: 

273 - type: create-machine-image 

274 name_format: "{instance[name]:.50}-{now:%Y-%m-%d}" 

275 

276 """ 

277 schema = type_schema('create-machine-image', name_format={'type': 'string'}) 

278 method_spec = {'op': 'insert'} 

279 permissions = ('compute.machineImages.create',) 

280 

281 def get_resource_params(self, model, resource): 

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

283 project, _, _ = path_param_re.match(resource['selfLink']).groups() 

284 name_format = self.data.get('name_format', '{instance[name]}') 

285 name = name_format.format(instance=resource, now=datetime.now()) 

286 

287 return {'project': project, 'sourceInstance': resource['selfLink'], 'body': {'name': name}} 

288 

289 def get_client(self, session, model): 

290 return session.client(model.service, "beta", "machineImages") 

291 

292 

293@resources.register('image') 

294class Image(QueryResourceManager): 

295 

296 class resource_type(TypeInfo): 

297 service = 'compute' 

298 version = 'v1' 

299 component = 'images' 

300 name = id = 'name' 

301 default_report_fields = [ 

302 "name", "description", "sourceType", "status", "creationTimestamp", 

303 "diskSizeGb", "family"] 

304 asset_type = "compute.googleapis.com/Image" 

305 urn_component = "image" 

306 labels = True 

307 

308 @staticmethod 

309 def get(client, resource_info): 

310 return client.execute_command( 

311 'get', {'project': resource_info['project_id'], 

312 'image': resource_info['image_id']}) 

313 

314 @staticmethod 

315 def get_label_params(resource, all_labels): 

316 project, resource_id = re.match( 

317 '.*?/projects/(.*?)/global/images/(.*)', 

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

319 return {'project': project, 'resource': resource_id, 

320 'body': { 

321 'labels': all_labels, 

322 'labelFingerprint': resource['labelFingerprint'] 

323 }} 

324 

325 @classmethod 

326 def refresh(cls, client, resource): 

327 project, resource_id = re.match( 

328 '.*?/projects/(.*?)/global/images/(.*)', 

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

330 return cls.get( 

331 client, 

332 { 

333 'project_id': project, 

334 'image_id': resource_id 

335 } 

336 ) 

337 

338 

339@Image.filter_registry.register('iam-policy') 

340class ImageIamPolicyFilter(IamPolicyFilter): 

341 """ 

342 Overrides the base implementation to process images resources correctly. 

343 """ 

344 permissions = ('compute.images.getIamPolicy',) 

345 

346 def _verb_arguments(self, resource): 

347 project, _ = re.match( 

348 '.*?/projects/(.*?)/global/images/(.*)', 

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

350 verb_arguments = {'resource': resource[self.manager.resource_type.id], 'project': project} 

351 return verb_arguments 

352 

353 def process_resources(self, resources): 

354 value_filter = IamPolicyValueFilter(self.data['doc'], self.manager) 

355 value_filter._verb_arguments = self._verb_arguments 

356 return value_filter.process(resources) 

357 

358 

359@Image.action_registry.register('delete') 

360class DeleteImage(MethodAction): 

361 

362 schema = type_schema('delete') 

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

364 attr_filter = ('status', ('READY')) 

365 path_param_re = re.compile('.*?/projects/(.*?)/global/images/(.*)') 

366 

367 def get_resource_params(self, m, r): 

368 project, image_id = self.path_param_re.match(r['selfLink']).groups() 

369 return {'project': project, 'image': image_id} 

370 

371 

372@resources.register('disk') 

373class Disk(QueryResourceManager): 

374 

375 class resource_type(TypeInfo): 

376 service = 'compute' 

377 version = 'v1' 

378 component = 'disks' 

379 scope = 'zone' 

380 enum_spec = ('aggregatedList', 'items.*.disks[]', None) 

381 name = id = 'name' 

382 labels = True 

383 default_report_fields = ["name", "sizeGb", "status", "zone"] 

384 asset_type = "compute.googleapis.com/Disk" 

385 urn_component = "disk" 

386 urn_zonal = True 

387 

388 @staticmethod 

389 def get(client, resource_info): 

390 return client.execute_command( 

391 'get', {'project': resource_info['project_id'], 

392 'zone': resource_info['zone'], 

393 'disk': resource_info['disk_id']}) 

394 

395 @staticmethod 

396 def get_label_params(resource, all_labels): 

397 path_param_re = re.compile('.*?/projects/(.*?)/zones/(.*?)/disks/(.*)') 

398 project, zone, instance = path_param_re.match( 

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

400 return {'project': project, 'zone': zone, 'resource': instance, 

401 'body': { 

402 'labels': all_labels, 

403 'labelFingerprint': resource['labelFingerprint'] 

404 }} 

405 

406 

407@Disk.action_registry.register('snapshot') 

408class DiskSnapshot(MethodAction): 

409 """ 

410 `Snapshots <https://cloud.google.com/compute/docs/reference/rest/v1/disks/createSnapshot>`_ 

411 disk. 

412 

413 The `name_format` specifies name of snapshot in python `format string <https://pyformat.info/>` 

414 

415 Inside format string there are defined variables: 

416 - `now`: current time 

417 - `disk`: whole disk resource 

418 

419 Default name format is `{disk.name}` 

420 

421 :Example: 

422 

423 .. code-block:: yaml 

424 

425 policies: 

426 - name: gcp-disk-snapshot 

427 resource: gcp.disk 

428 filters: 

429 - type: value 

430 key: name 

431 value: disk-7 

432 actions: 

433 - type: snapshot 

434 name_format: "{disk[name]:.50}-{now:%Y-%m-%d}" 

435 """ 

436 schema = type_schema('snapshot', name_format={'type': 'string'}) 

437 method_spec = {'op': 'createSnapshot'} 

438 path_param_re = re.compile( 

439 '.*?/projects/(.*?)/zones/(.*?)/disks/(.*)') 

440 attr_filter = ('status', ('RUNNING', 'READY')) 

441 

442 def get_resource_params(self, model, resource): 

443 project, zone, resourceId = self.path_param_re.match(resource['selfLink']).groups() 

444 name_format = self.data.get('name_format', '{disk[name]}') 

445 name = name_format.format(disk=resource, now=datetime.now()) 

446 

447 return { 

448 'project': project, 

449 'zone': zone, 

450 'disk': resourceId, 

451 'body': { 

452 'name': name, 

453 'labels': resource.get('labels', {}), 

454 } 

455 } 

456 

457 

458@Disk.action_registry.register('delete') 

459class DiskDelete(MethodAction): 

460 

461 schema = type_schema('delete') 

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

463 path_param_re = re.compile( 

464 '.*?/projects/(.*?)/zones/(.*?)/disks/(.*)') 

465 attr_filter = ('status', ('RUNNING', 'READY')) 

466 

467 def get_resource_params(self, m, r): 

468 project, zone, resourceId = self.path_param_re.match(r['selfLink']).groups() 

469 return { 

470 'project': project, 

471 'zone': zone, 

472 'disk': resourceId, 

473 } 

474 

475 

476@resources.register('snapshot') 

477class Snapshot(QueryResourceManager): 

478 

479 class resource_type(TypeInfo): 

480 service = 'compute' 

481 version = 'v1' 

482 component = 'snapshots' 

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

484 name = id = 'name' 

485 default_report_fields = ["name", "status", "diskSizeGb", "creationTimestamp"] 

486 asset_type = "compute.googleapis.com/Snapshot" 

487 urn_component = "snapshot" 

488 

489 @staticmethod 

490 def get(client, resource_info): 

491 return client.execute_command( 

492 'get', {'project': resource_info['project_id'], 

493 'snapshot': resource_info['snapshot_id']}) 

494 

495 

496@Snapshot.action_registry.register('delete') 

497class DeleteSnapshot(MethodAction): 

498 

499 schema = type_schema('delete') 

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

501 attr_filter = ('status', ('READY', 'UPLOADING')) 

502 path_param_re = re.compile('.*?/projects/(.*?)/global/snapshots/(.*)') 

503 

504 def get_resource_params(self, m, r): 

505 project, snapshot_id = self.path_param_re.match(r['selfLink']).groups() 

506 # Docs are wrong :-( 

507 # https://cloud.google.com/compute/docs/reference/rest/v1/snapshots/delete 

508 return {'project': project, 'snapshot': snapshot_id} 

509 

510 

511@resources.register('instance-template') 

512class InstanceTemplate(QueryResourceManager): 

513 """GCP resource: https://cloud.google.com/compute/docs/reference/rest/v1/instanceTemplates""" 

514 class resource_type(TypeInfo): 

515 service = 'compute' 

516 version = 'v1' 

517 component = 'instanceTemplates' 

518 scope = 'zone' 

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

520 name = id = 'name' 

521 default_report_fields = [ 

522 name, "description", "creationTimestamp", 

523 "properties.machineType", "properties.description"] 

524 asset_type = "compute.googleapis.com/InstanceTemplate" 

525 urn_component = "instance-template" 

526 

527 @staticmethod 

528 def get(client, resource_info): 

529 return client.execute_command( 

530 'get', {'project': resource_info['project_id'], 

531 'instanceTemplate': resource_info['instance_template_name']}) 

532 

533 

534@InstanceTemplate.action_registry.register('delete') 

535class InstanceTemplateDelete(MethodAction): 

536 """ 

537 `Deletes <https://cloud.google.com/compute/docs/reference/rest/v1/instanceTemplates/delete>`_ 

538 an Instance Template. The action does not specify any parameters. 

539 

540 :Example: 

541 

542 .. code-block:: yaml 

543 

544 policies: 

545 - name: gcp-instance-template-delete 

546 resource: gcp.instance-template 

547 filters: 

548 - type: value 

549 key: name 

550 value: instance-template-to-delete 

551 actions: 

552 - type: delete 

553 """ 

554 schema = type_schema('delete') 

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

556 

557 def get_resource_params(self, m, r): 

558 project, instance_template = re.match('.*/projects/(.*?)/.*/instanceTemplates/(.*)', 

559 r['selfLink']).groups() 

560 return {'project': project, 

561 'instanceTemplate': instance_template} 

562 

563 

564@resources.register('autoscaler') 

565class Autoscaler(QueryResourceManager): 

566 """GCP resource: https://cloud.google.com/compute/docs/reference/rest/v1/autoscalers""" 

567 class resource_type(TypeInfo): 

568 service = 'compute' 

569 version = 'v1' 

570 component = 'autoscalers' 

571 name = id = 'name' 

572 enum_spec = ('aggregatedList', 'items.*.autoscalers[]', None) 

573 default_report_fields = [ 

574 "name", "description", "status", "target", "recommendedSize"] 

575 asset_type = "compute.googleapis.com/Autoscaler" 

576 metric_key = "resource.labels.autoscaler_name" 

577 urn_component = "autoscaler" 

578 urn_zonal = True 

579 

580 @staticmethod 

581 def get(client, resource_info): 

582 project, zone, autoscaler = re.match( 

583 'projects/(.*?)/zones/(.*?)/autoscalers/(.*)', 

584 resource_info['resourceName']).groups() 

585 

586 return client.execute_command( 

587 'get', {'project': project, 

588 'zone': zone, 

589 'autoscaler': autoscaler}) 

590 

591 

592@Autoscaler.action_registry.register('set') 

593class AutoscalerSet(MethodAction): 

594 """ 

595 `Patches <https://cloud.google.com/compute/docs/reference/rest/v1/autoscalers/patch>`_ 

596 configuration parameters for the autoscaling algorithm. 

597 

598 The `coolDownPeriodSec` specifies the number of seconds that the autoscaler 

599 should wait before it starts collecting information from a new instance. 

600 

601 The `cpuUtilization.utilizationTarget` specifies the target CPU utilization that the 

602 autoscaler should maintain. 

603 

604 The `loadBalancingUtilization.utilizationTarget` specifies fraction of backend capacity 

605 utilization (set in HTTP(S) load balancing configuration) that autoscaler should maintain. 

606 

607 The `minNumReplicas` specifies the minimum number of replicas that the autoscaler can 

608 scale down to. 

609 

610 The `maxNumReplicas` specifies the maximum number of instances that the autoscaler can 

611 scale up to. 

612 

613 :Example: 

614 

615 .. code-block:: yaml 

616 

617 policies: 

618 - name: gcp-autoscaler-set 

619 resource: gcp.autoscaler 

620 filters: 

621 - type: value 

622 key: name 

623 value: instance-group-2 

624 actions: 

625 - type: set 

626 coolDownPeriodSec: 20 

627 cpuUtilization: 

628 utilizationTarget: 0.7 

629 loadBalancingUtilization: 

630 utilizationTarget: 0.7 

631 minNumReplicas: 1 

632 maxNumReplicas: 4 

633 """ 

634 schema = type_schema('set', 

635 **{ 

636 'coolDownPeriodSec': { 

637 'type': 'integer', 

638 'minimum': 15 

639 }, 

640 'cpuUtilization': { 

641 'type': 'object', 

642 'required': ['utilizationTarget'], 

643 'properties': { 

644 'utilizationTarget': { 

645 'type': 'number', 

646 'exclusiveMinimum': 0, 

647 'maximum': 1 

648 } 

649 }, 

650 }, 

651 'loadBalancingUtilization': { 

652 'type': 'object', 

653 'required': ['utilizationTarget'], 

654 'properties': { 

655 'utilizationTarget': { 

656 'type': 'number', 

657 'exclusiveMinimum': 0, 

658 'maximum': 1 

659 } 

660 } 

661 }, 

662 'maxNumReplicas': { 

663 'type': 'integer', 

664 'exclusiveMinimum': 0 

665 }, 

666 'minNumReplicas': { 

667 'type': 'integer', 

668 'exclusiveMinimum': 0 

669 } 

670 }) 

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

672 path_param_re = re.compile('.*?/projects/(.*?)/zones/(.*?)/autoscalers/(.*)') 

673 method_perm = 'update' 

674 

675 def get_resource_params(self, model, resource): 

676 project, zone, autoscaler = self.path_param_re.match(resource['selfLink']).groups() 

677 body = {} 

678 

679 if 'coolDownPeriodSec' in self.data: 

680 body['coolDownPeriodSec'] = self.data['coolDownPeriodSec'] 

681 

682 if 'cpuUtilization' in self.data: 

683 body['cpuUtilization'] = self.data['cpuUtilization'] 

684 

685 if 'loadBalancingUtilization' in self.data: 

686 body['loadBalancingUtilization'] = self.data['loadBalancingUtilization'] 

687 

688 if 'maxNumReplicas' in self.data: 

689 body['maxNumReplicas'] = self.data['maxNumReplicas'] 

690 

691 if 'minNumReplicas' in self.data: 

692 body['minNumReplicas'] = self.data['minNumReplicas'] 

693 

694 result = {'project': project, 

695 'zone': zone, 

696 'autoscaler': autoscaler, 

697 'body': { 

698 'autoscalingPolicy': body 

699 }} 

700 

701 return result 

702 

703 

704@resources.register('zone') 

705class Zone(QueryResourceManager): 

706 """GC resource: https://cloud.google.com/compute/docs/reference/rest/v1/zones""" 

707 class resource_type(TypeInfo): 

708 service = 'compute' 

709 version = 'v1' 

710 component = 'zones' 

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

712 scope = 'project' 

713 name = id = 'name' 

714 default_report_fields = ['id', 'name', 'dnsName', 'creationTime', 'visibility'] 

715 asset_type = "compute.googleapis.com/compute" 

716 scc_type = "google.cloud.dns.ManagedZone" 

717 

718 

719@resources.register('compute-project') 

720class Project(QueryResourceManager): 

721 """GCP resource: https://cloud.google.com/compute/docs/reference/rest/v1/projects""" 

722 class resource_type(TypeInfo): 

723 service = 'compute' 

724 version = 'v1' 

725 component = 'projects' 

726 enum_spec = ('get', '[@]', None) 

727 name = id = 'name' 

728 default_report_fields = ["name"] 

729 asset_type = 'compute.googleapis.com/Project' 

730 

731 @staticmethod 

732 def get(client, resource_info): 

733 return client.execute_command( 

734 'get', {'project': resource_info['project_id']}) 

735 

736 

737@resources.register('instance-group-manager') 

738class InstanceGroupManager(ChildResourceManager): 

739 

740 class resource_type(ChildTypeInfo): 

741 service = 'compute' 

742 version = 'v1' 

743 component = 'instanceGroupManagers' 

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

745 name = id = 'name' 

746 parent_spec = { 

747 'resource': 'zone', 

748 'child_enum_params': { 

749 ('name', 'zone')}, 

750 'use_child_query': False, 

751 } 

752 default_report_fields = ['id', 'name', 'dnsName', 'creationTime', 'visibility']