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

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

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

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@Instance.action_registry.register('detach-disks') 

184class DetachDisks(MethodAction): 

185 """ 

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

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

188 

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

190 that are set to auto delete. 

191 

192 :Example: 

193 

194 .. code-block:: yaml 

195 

196 policies: 

197 - name: gcp-instance-detach-disks 

198 resource: gcp.instance 

199 filters: 

200 - type: value 

201 key: name 

202 value: instance-template-to-detahc 

203 actions: 

204 - type: detach-disks 

205 """ 

206 schema = type_schema('detach-disks') 

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

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

209 path_param_re = re.compile( 

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

211 

212 def validate(self): 

213 pass 

214 

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

216 for resource in resources: 

217 self.process_resource(client, resource) 

218 

219 def process_resource(self, client, resource): 

220 op_name = 'detachDisk' 

221 

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

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

224 

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

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

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

228 self.invoke_api(client, op_name, params) 

229 

230 

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

232class CreateMachineImage(MethodAction): 

233 """ 

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

235 Machine Image from instance. 

236 

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

238 

239 Inside format string there are defined variables: 

240 - `now`: current time 

241 - `instance`: whole instance resource 

242 

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

244 

245 :Example: 

246 

247 .. code-block:: yaml 

248 

249 policies: 

250 - name: gcp-create-machine-image 

251 resource: gcp.instance 

252 filters: 

253 - type: value 

254 key: name 

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

256 actions: 

257 - type: create-machine-image 

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

259 

260 """ 

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

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

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

264 

265 def get_resource_params(self, model, resource): 

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

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

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

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

270 

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

272 

273 def get_client(self, session, model): 

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

275 

276 

277@resources.register('image') 

278class Image(QueryResourceManager): 

279 

280 class resource_type(TypeInfo): 

281 service = 'compute' 

282 version = 'v1' 

283 component = 'images' 

284 name = id = 'name' 

285 default_report_fields = [ 

286 "name", "description", "sourceType", "status", "creationTimestamp", 

287 "diskSizeGb", "family"] 

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

289 urn_component = "image" 

290 labels = True 

291 

292 @staticmethod 

293 def get(client, resource_info): 

294 return client.execute_command( 

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

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

297 

298 @staticmethod 

299 def get_label_params(resource, all_labels): 

300 project, resource_id = re.match( 

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

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

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

304 'body': { 

305 'labels': all_labels, 

306 'labelFingerprint': resource['labelFingerprint'] 

307 }} 

308 

309 @classmethod 

310 def refresh(cls, client, resource): 

311 project, resource_id = re.match( 

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

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

314 return cls.get( 

315 client, 

316 { 

317 'project_id': project, 

318 'image_id': resource_id 

319 } 

320 ) 

321 

322 

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

324class ImageIamPolicyFilter(IamPolicyFilter): 

325 """ 

326 Overrides the base implementation to process images resources correctly. 

327 """ 

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

329 

330 def _verb_arguments(self, resource): 

331 project, _ = re.match( 

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

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

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

335 return verb_arguments 

336 

337 def process_resources(self, resources): 

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

339 value_filter._verb_arguments = self._verb_arguments 

340 return value_filter.process(resources) 

341 

342 

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

344class DeleteImage(MethodAction): 

345 

346 schema = type_schema('delete') 

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

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

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

350 

351 def get_resource_params(self, m, r): 

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

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

354 

355 

356@resources.register('disk') 

357class Disk(QueryResourceManager): 

358 

359 class resource_type(TypeInfo): 

360 service = 'compute' 

361 version = 'v1' 

362 component = 'disks' 

363 scope = 'zone' 

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

365 name = id = 'name' 

366 labels = True 

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

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

369 urn_component = "disk" 

370 urn_zonal = True 

371 

372 @staticmethod 

373 def get(client, resource_info): 

374 return client.execute_command( 

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

376 'zone': resource_info['zone'], 

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

378 

379 @staticmethod 

380 def get_label_params(resource, all_labels): 

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

382 project, zone, instance = path_param_re.match( 

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

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

385 'body': { 

386 'labels': all_labels, 

387 'labelFingerprint': resource['labelFingerprint'] 

388 }} 

389 

390 

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

392class DiskSnapshot(MethodAction): 

393 """ 

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

395 disk. 

396 

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

398 

399 Inside format string there are defined variables: 

400 - `now`: current time 

401 - `disk`: whole disk resource 

402 

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

404 

405 :Example: 

406 

407 .. code-block:: yaml 

408 

409 policies: 

410 - name: gcp-disk-snapshot 

411 resource: gcp.disk 

412 filters: 

413 - type: value 

414 key: name 

415 value: disk-7 

416 actions: 

417 - type: snapshot 

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

419 """ 

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

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

422 path_param_re = re.compile( 

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

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

425 

426 def get_resource_params(self, model, resource): 

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

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

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

430 

431 return { 

432 'project': project, 

433 'zone': zone, 

434 'disk': resourceId, 

435 'body': { 

436 'name': name, 

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

438 } 

439 } 

440 

441 

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

443class DiskDelete(MethodAction): 

444 

445 schema = type_schema('delete') 

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

447 path_param_re = re.compile( 

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

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

450 

451 def get_resource_params(self, m, r): 

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

453 return { 

454 'project': project, 

455 'zone': zone, 

456 'disk': resourceId, 

457 } 

458 

459 

460@resources.register('snapshot') 

461class Snapshot(QueryResourceManager): 

462 

463 class resource_type(TypeInfo): 

464 service = 'compute' 

465 version = 'v1' 

466 component = 'snapshots' 

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

468 name = id = 'name' 

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

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

471 urn_component = "snapshot" 

472 

473 @staticmethod 

474 def get(client, resource_info): 

475 return client.execute_command( 

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

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

478 

479 

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

481class DeleteSnapshot(MethodAction): 

482 

483 schema = type_schema('delete') 

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

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

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

487 

488 def get_resource_params(self, m, r): 

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

490 # Docs are wrong :-( 

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

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

493 

494 

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

496class InstanceTemplate(QueryResourceManager): 

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

498 class resource_type(TypeInfo): 

499 service = 'compute' 

500 version = 'v1' 

501 component = 'instanceTemplates' 

502 scope = 'zone' 

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

504 name = id = 'name' 

505 default_report_fields = [ 

506 name, "description", "creationTimestamp", 

507 "properties.machineType", "properties.description"] 

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

509 urn_component = "instance-template" 

510 

511 @staticmethod 

512 def get(client, resource_info): 

513 return client.execute_command( 

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

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

516 

517 

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

519class InstanceTemplateDelete(MethodAction): 

520 """ 

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

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

523 

524 :Example: 

525 

526 .. code-block:: yaml 

527 

528 policies: 

529 - name: gcp-instance-template-delete 

530 resource: gcp.instance-template 

531 filters: 

532 - type: value 

533 key: name 

534 value: instance-template-to-delete 

535 actions: 

536 - type: delete 

537 """ 

538 schema = type_schema('delete') 

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

540 

541 def get_resource_params(self, m, r): 

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

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

544 return {'project': project, 

545 'instanceTemplate': instance_template} 

546 

547 

548@resources.register('autoscaler') 

549class Autoscaler(QueryResourceManager): 

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

551 class resource_type(TypeInfo): 

552 service = 'compute' 

553 version = 'v1' 

554 component = 'autoscalers' 

555 name = id = 'name' 

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

557 default_report_fields = [ 

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

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

560 metric_key = "resource.labels.autoscaler_name" 

561 urn_component = "autoscaler" 

562 urn_zonal = True 

563 

564 @staticmethod 

565 def get(client, resource_info): 

566 project, zone, autoscaler = re.match( 

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

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

569 

570 return client.execute_command( 

571 'get', {'project': project, 

572 'zone': zone, 

573 'autoscaler': autoscaler}) 

574 

575 

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

577class AutoscalerSet(MethodAction): 

578 """ 

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

580 configuration parameters for the autoscaling algorithm. 

581 

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

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

584 

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

586 autoscaler should maintain. 

587 

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

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

590 

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

592 scale down to. 

593 

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

595 scale up to. 

596 

597 :Example: 

598 

599 .. code-block:: yaml 

600 

601 policies: 

602 - name: gcp-autoscaler-set 

603 resource: gcp.autoscaler 

604 filters: 

605 - type: value 

606 key: name 

607 value: instance-group-2 

608 actions: 

609 - type: set 

610 coolDownPeriodSec: 20 

611 cpuUtilization: 

612 utilizationTarget: 0.7 

613 loadBalancingUtilization: 

614 utilizationTarget: 0.7 

615 minNumReplicas: 1 

616 maxNumReplicas: 4 

617 """ 

618 schema = type_schema('set', 

619 **{ 

620 'coolDownPeriodSec': { 

621 'type': 'integer', 

622 'minimum': 15 

623 }, 

624 'cpuUtilization': { 

625 'type': 'object', 

626 'required': ['utilizationTarget'], 

627 'properties': { 

628 'utilizationTarget': { 

629 'type': 'number', 

630 'exclusiveMinimum': 0, 

631 'maximum': 1 

632 } 

633 }, 

634 }, 

635 'loadBalancingUtilization': { 

636 'type': 'object', 

637 'required': ['utilizationTarget'], 

638 'properties': { 

639 'utilizationTarget': { 

640 'type': 'number', 

641 'exclusiveMinimum': 0, 

642 'maximum': 1 

643 } 

644 } 

645 }, 

646 'maxNumReplicas': { 

647 'type': 'integer', 

648 'exclusiveMinimum': 0 

649 }, 

650 'minNumReplicas': { 

651 'type': 'integer', 

652 'exclusiveMinimum': 0 

653 } 

654 }) 

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

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

657 method_perm = 'update' 

658 

659 def get_resource_params(self, model, resource): 

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

661 body = {} 

662 

663 if 'coolDownPeriodSec' in self.data: 

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

665 

666 if 'cpuUtilization' in self.data: 

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

668 

669 if 'loadBalancingUtilization' in self.data: 

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

671 

672 if 'maxNumReplicas' in self.data: 

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

674 

675 if 'minNumReplicas' in self.data: 

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

677 

678 result = {'project': project, 

679 'zone': zone, 

680 'autoscaler': autoscaler, 

681 'body': { 

682 'autoscalingPolicy': body 

683 }} 

684 

685 return result 

686 

687 

688@resources.register('zone') 

689class Zone(QueryResourceManager): 

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

691 class resource_type(TypeInfo): 

692 service = 'compute' 

693 version = 'v1' 

694 component = 'zones' 

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

696 scope = 'project' 

697 name = id = 'name' 

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

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

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

701 

702 

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

704class Project(QueryResourceManager): 

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

706 class resource_type(TypeInfo): 

707 service = 'compute' 

708 version = 'v1' 

709 component = 'projects' 

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

711 name = id = 'name' 

712 default_report_fields = ["name"] 

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

714 

715 @staticmethod 

716 def get(client, resource_info): 

717 return client.execute_command( 

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

719 

720 

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

722class InstanceGroupManager(ChildResourceManager): 

723 

724 class resource_type(ChildTypeInfo): 

725 service = 'compute' 

726 version = 'v1' 

727 component = 'instanceGroupManagers' 

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

729 name = id = 'name' 

730 parent_spec = { 

731 'resource': 'zone', 

732 'child_enum_params': { 

733 ('name', 'zone')}, 

734 'use_child_query': False, 

735 } 

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