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

322 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 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 """ 

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

149 

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

151 

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

153 """ 

154 

155 schema = type_schema('stop') 

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

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

158 

159 

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

161class Suspend(InstanceAction): 

162 

163 schema = type_schema('suspend') 

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

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

166 

167 

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

169class Resume(InstanceAction): 

170 

171 schema = type_schema('resume') 

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

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

174 

175 

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

177class Delete(InstanceAction): 

178 

179 schema = type_schema('delete') 

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

181 

182 

183 

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

185class DetachDisks(MethodAction): 

186 """ 

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

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

189 

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

191 that are set to auto delete. 

192 

193 :Example: 

194 

195 .. code-block:: yaml 

196 

197 policies: 

198 - name: gcp-instance-detach-disks 

199 resource: gcp.instance 

200 filters: 

201 - type: value 

202 key: name 

203 value: instance-template-to-detahc 

204 actions: 

205 - type: detach-disks 

206 """ 

207 schema = type_schema('detach-disks') 

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

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

210 path_param_re = re.compile( 

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

212 

213 def validate(self): 

214 pass 

215 

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

217 for resource in resources: 

218 self.process_resource(client, resource) 

219 

220 def process_resource(self, client, resource): 

221 op_name = 'detachDisk' 

222 

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

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

225 

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

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

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

229 self.invoke_api(client, op_name, params) 

230 

231 

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

233class CreateMachineImage(MethodAction): 

234 """ 

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

236 Machine Image from instance. 

237 

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

239 

240 Inside format string there are defined variables: 

241 - `now`: current time 

242 - `instance`: whole instance resource 

243 

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

245 

246 :Example: 

247 

248 .. code-block:: yaml 

249 

250 policies: 

251 - name: gcp-create-machine-image 

252 resource: gcp.instance 

253 filters: 

254 - type: value 

255 key: name 

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

257 actions: 

258 - type: create-machine-image 

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

260 

261 """ 

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

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

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

265 

266 def get_resource_params(self, model, resource): 

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

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

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

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

271 

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

273 

274 def get_client(self, session, model): 

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

276 

277 

278@resources.register('image') 

279class Image(QueryResourceManager): 

280 

281 class resource_type(TypeInfo): 

282 service = 'compute' 

283 version = 'v1' 

284 component = 'images' 

285 name = id = 'name' 

286 default_report_fields = [ 

287 "name", "description", "sourceType", "status", "creationTimestamp", 

288 "diskSizeGb", "family"] 

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

290 urn_component = "image" 

291 labels = True 

292 

293 @staticmethod 

294 def get(client, resource_info): 

295 return client.execute_command( 

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

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

298 

299 @staticmethod 

300 def get_label_params(resource, all_labels): 

301 project, resource_id = re.match( 

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

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

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

305 'body': { 

306 'labels': all_labels, 

307 'labelFingerprint': resource['labelFingerprint'] 

308 }} 

309 

310 @classmethod 

311 def refresh(cls, client, resource): 

312 project, resource_id = re.match( 

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

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

315 return cls.get( 

316 client, 

317 { 

318 'project_id': project, 

319 'image_id': resource_id 

320 } 

321 ) 

322 

323 

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

325class ImageIamPolicyFilter(IamPolicyFilter): 

326 """ 

327 Overrides the base implementation to process images resources correctly. 

328 """ 

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

330 

331 def _verb_arguments(self, resource): 

332 project, _ = re.match( 

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

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

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

336 return verb_arguments 

337 

338 def process_resources(self, resources): 

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

340 value_filter._verb_arguments = self._verb_arguments 

341 return value_filter.process(resources) 

342 

343 

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

345class DeleteImage(MethodAction): 

346 

347 schema = type_schema('delete') 

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

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

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

351 

352 def get_resource_params(self, m, r): 

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

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

355 

356 

357@resources.register('disk') 

358class Disk(QueryResourceManager): 

359 

360 class resource_type(TypeInfo): 

361 service = 'compute' 

362 version = 'v1' 

363 component = 'disks' 

364 scope = 'zone' 

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

366 name = id = 'name' 

367 labels = True 

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

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

370 urn_component = "disk" 

371 urn_zonal = True 

372 

373 @staticmethod 

374 def get(client, resource_info): 

375 return client.execute_command( 

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

377 'zone': resource_info['zone'], 

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

379 

380 @staticmethod 

381 def get_label_params(resource, all_labels): 

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

383 project, zone, instance = path_param_re.match( 

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

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

386 'body': { 

387 'labels': all_labels, 

388 'labelFingerprint': resource['labelFingerprint'] 

389 }} 

390 

391 

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

393class DiskSnapshot(MethodAction): 

394 """ 

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

396 disk. 

397 

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

399 

400 Inside format string there are defined variables: 

401 - `now`: current time 

402 - `disk`: whole disk resource 

403 

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

405 

406 :Example: 

407 

408 .. code-block:: yaml 

409 

410 policies: 

411 - name: gcp-disk-snapshot 

412 resource: gcp.disk 

413 filters: 

414 - type: value 

415 key: name 

416 value: disk-7 

417 actions: 

418 - type: snapshot 

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

420 """ 

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

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

423 path_param_re = re.compile( 

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

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

426 

427 def get_resource_params(self, model, resource): 

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

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

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

431 

432 return { 

433 'project': project, 

434 'zone': zone, 

435 'disk': resourceId, 

436 'body': { 

437 'name': name, 

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

439 } 

440 } 

441 

442 

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

444class DiskDelete(MethodAction): 

445 

446 schema = type_schema('delete') 

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

448 path_param_re = re.compile( 

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

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

451 

452 def get_resource_params(self, m, r): 

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

454 return { 

455 'project': project, 

456 'zone': zone, 

457 'disk': resourceId, 

458 } 

459 

460 

461@resources.register('snapshot') 

462class Snapshot(QueryResourceManager): 

463 

464 class resource_type(TypeInfo): 

465 service = 'compute' 

466 version = 'v1' 

467 component = 'snapshots' 

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

469 name = id = 'name' 

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

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

472 urn_component = "snapshot" 

473 

474 @staticmethod 

475 def get(client, resource_info): 

476 return client.execute_command( 

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

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

479 

480 

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

482class DeleteSnapshot(MethodAction): 

483 

484 schema = type_schema('delete') 

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

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

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

488 

489 def get_resource_params(self, m, r): 

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

491 # Docs are wrong :-( 

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

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

494 

495 

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

497class InstanceTemplate(QueryResourceManager): 

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

499 class resource_type(TypeInfo): 

500 service = 'compute' 

501 version = 'v1' 

502 component = 'instanceTemplates' 

503 scope = 'zone' 

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

505 name = id = 'name' 

506 default_report_fields = [ 

507 name, "description", "creationTimestamp", 

508 "properties.machineType", "properties.description"] 

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

510 urn_component = "instance-template" 

511 

512 @staticmethod 

513 def get(client, resource_info): 

514 return client.execute_command( 

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

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

517 

518 

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

520class InstanceTemplateDelete(MethodAction): 

521 """ 

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

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

524 

525 :Example: 

526 

527 .. code-block:: yaml 

528 

529 policies: 

530 - name: gcp-instance-template-delete 

531 resource: gcp.instance-template 

532 filters: 

533 - type: value 

534 key: name 

535 value: instance-template-to-delete 

536 actions: 

537 - type: delete 

538 """ 

539 schema = type_schema('delete') 

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

541 

542 def get_resource_params(self, m, r): 

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

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

545 return {'project': project, 

546 'instanceTemplate': instance_template} 

547 

548 

549@resources.register('autoscaler') 

550class Autoscaler(QueryResourceManager): 

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

552 class resource_type(TypeInfo): 

553 service = 'compute' 

554 version = 'v1' 

555 component = 'autoscalers' 

556 name = id = 'name' 

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

558 default_report_fields = [ 

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

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

561 metric_key = "resource.labels.autoscaler_name" 

562 urn_component = "autoscaler" 

563 urn_zonal = True 

564 

565 @staticmethod 

566 def get(client, resource_info): 

567 project, zone, autoscaler = re.match( 

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

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

570 

571 return client.execute_command( 

572 'get', {'project': project, 

573 'zone': zone, 

574 'autoscaler': autoscaler}) 

575 

576 

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

578class AutoscalerSet(MethodAction): 

579 """ 

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

581 configuration parameters for the autoscaling algorithm. 

582 

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

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

585 

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

587 autoscaler should maintain. 

588 

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

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

591 

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

593 scale down to. 

594 

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

596 scale up to. 

597 

598 :Example: 

599 

600 .. code-block:: yaml 

601 

602 policies: 

603 - name: gcp-autoscaler-set 

604 resource: gcp.autoscaler 

605 filters: 

606 - type: value 

607 key: name 

608 value: instance-group-2 

609 actions: 

610 - type: set 

611 coolDownPeriodSec: 20 

612 cpuUtilization: 

613 utilizationTarget: 0.7 

614 loadBalancingUtilization: 

615 utilizationTarget: 0.7 

616 minNumReplicas: 1 

617 maxNumReplicas: 4 

618 """ 

619 schema = type_schema('set', 

620 **{ 

621 'coolDownPeriodSec': { 

622 'type': 'integer', 

623 'minimum': 15 

624 }, 

625 'cpuUtilization': { 

626 'type': 'object', 

627 'required': ['utilizationTarget'], 

628 'properties': { 

629 'utilizationTarget': { 

630 'type': 'number', 

631 'exclusiveMinimum': 0, 

632 'maximum': 1 

633 } 

634 }, 

635 }, 

636 'loadBalancingUtilization': { 

637 'type': 'object', 

638 'required': ['utilizationTarget'], 

639 'properties': { 

640 'utilizationTarget': { 

641 'type': 'number', 

642 'exclusiveMinimum': 0, 

643 'maximum': 1 

644 } 

645 } 

646 }, 

647 'maxNumReplicas': { 

648 'type': 'integer', 

649 'exclusiveMinimum': 0 

650 }, 

651 'minNumReplicas': { 

652 'type': 'integer', 

653 'exclusiveMinimum': 0 

654 } 

655 }) 

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

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

658 method_perm = 'update' 

659 

660 def get_resource_params(self, model, resource): 

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

662 body = {} 

663 

664 if 'coolDownPeriodSec' in self.data: 

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

666 

667 if 'cpuUtilization' in self.data: 

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

669 

670 if 'loadBalancingUtilization' in self.data: 

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

672 

673 if 'maxNumReplicas' in self.data: 

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

675 

676 if 'minNumReplicas' in self.data: 

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

678 

679 result = {'project': project, 

680 'zone': zone, 

681 'autoscaler': autoscaler, 

682 'body': { 

683 'autoscalingPolicy': body 

684 }} 

685 

686 return result 

687 

688 

689@resources.register('zone') 

690class Zone(QueryResourceManager): 

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

692 class resource_type(TypeInfo): 

693 service = 'compute' 

694 version = 'v1' 

695 component = 'zones' 

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

697 scope = 'project' 

698 name = id = 'name' 

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

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

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

702 

703 

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

705class Project(QueryResourceManager): 

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

707 class resource_type(TypeInfo): 

708 service = 'compute' 

709 version = 'v1' 

710 component = 'projects' 

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

712 name = id = 'name' 

713 default_report_fields = ["name"] 

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

715 

716 @staticmethod 

717 def get(client, resource_info): 

718 return client.execute_command( 

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

720 

721 

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

723class InstanceGroupManager(ChildResourceManager): 

724 

725 class resource_type(ChildTypeInfo): 

726 service = 'compute' 

727 version = 'v1' 

728 component = 'instanceGroupManagers' 

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

730 name = id = 'name' 

731 parent_spec = { 

732 'resource': 'zone', 

733 'child_enum_params': { 

734 ('name', 'zone')}, 

735 'use_child_query': False, 

736 } 

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