diff --git a/modules/compute-vm/README.md b/modules/compute-vm/README.md
index 1e22e8ddd..826912544 100644
--- a/modules/compute-vm/README.md
+++ b/modules/compute-vm/README.md
@@ -25,6 +25,8 @@ In both modes, an optional service account can be created and assigned to either
- [Disk encryption with Cloud KMS](#disk-encryption-with-cloud-kms)
- [Instance template](#instance-template)
- [Instance group](#instance-group)
+- [Instance Schedule](#instance-schedule)
+- [Snapshot Schedules](#snapshot-schedules)
### Instance using defaults
@@ -500,40 +502,132 @@ module "instance-group" {
}
# tftest modules=1 resources=2 inventory=group.yaml
```
+
+### Instance Schedule
+
+Instance start and stop schedules can be defined via an existing or auto-created resource policy.
+
+To use an existing policy pass its id to the `instance_schedule` variable:
+
+```hcl
+module "instance" {
+ source = "./fabric/modules/compute-vm"
+ project_id = "my-project"
+ zone = "europe-west1-b"
+ name = "schedule-test"
+ network_interfaces = [{
+ network = var.vpc.self_link
+ subnetwork = var.subnet.self_link
+ }]
+ boot_disk = {
+ image = "projects/cos-cloud/global/images/family/cos-stable"
+ }
+ instance_schedule = {
+ resource_policy_id = "projects/my-project/regions/europe-west1/resourcePolicies/test"
+ }
+}
+# tftest modules=1 resources=1 inventory=instance-schedule-id.yaml
+```
+
+To create a new policy set its configuration in the `instance_schedule` variable. When removing the policy follow a two-step process by first setting `active = false` in the schedule configuration, which will unattach the policy, then removing the variable so the policy is destroyed.
+
+```hcl
+module "instance" {
+ source = "./fabric/modules/compute-vm"
+ project_id = "my-project"
+ zone = "europe-west1-b"
+ name = "schedule-test"
+ network_interfaces = [{
+ network = var.vpc.self_link
+ subnetwork = var.subnet.self_link
+ }]
+ boot_disk = {
+ image = "projects/cos-cloud/global/images/family/cos-stable"
+ }
+ instance_schedule = {
+ create_config = {
+ vm_start = "0 8 * * *"
+ vm_stop = "0 17 * * *"
+ }
+ }
+}
+# tftest modules=1 resources=2 inventory=instance-schedule-create.yaml
+```
+
+### Snapshot Schedules
+
+Snapshot policies can be attached to disks with optional creation managed by the module.
+
+```hcl
+module "instance" {
+ source = "./fabric/modules/compute-vm"
+ project_id = "my-project"
+ zone = "europe-west1-b"
+ name = "schedule-test"
+ network_interfaces = [{
+ network = var.vpc.self_link
+ subnetwork = var.subnet.self_link
+ }]
+ boot_disk = {
+ image = "projects/cos-cloud/global/images/family/cos-stable"
+ snapshot_schedule = "boot"
+ }
+ attached_disks = [
+ {
+ name = "disk-1"
+ size = 10
+ snapshot_schedule = "generic-vm"
+ }
+ ]
+ snapshot_schedules = {
+ boot = {
+ schedule = {
+ daily = {
+ days_in_cycle = 1
+ start_time = "03:00"
+ }
+ }
+ }
+ }
+}
+# tftest modules=1 resources=5 inventory=snapshot-schedule-create.yaml
+```
## Variables
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L182) | Instance name. | string | ✓ | |
-| [network_interfaces](variables.tf#L187) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({…})) | ✓ | |
-| [project_id](variables.tf#L224) | Project id. | string | ✓ | |
-| [zone](variables.tf#L283) | Compute zone. | string | ✓ | |
+| [name](variables.tf#L219) | Instance name. | string | ✓ | |
+| [network_interfaces](variables.tf#L224) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({…})) | ✓ | |
+| [project_id](variables.tf#L261) | Project id. | string | ✓ | |
+| [zone](variables.tf#L363) | Compute zone. | string | ✓ | |
| [attached_disk_defaults](variables.tf#L17) | Defaults for attached disks options. | object({…}) | | {…} |
-| [attached_disks](variables.tf#L38) | Additional disks, if options is null defaults will be used in its place. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null. | list(object({…})) | | [] |
-| [boot_disk](variables.tf#L82) | Boot disk properties. | object({…}) | | {…} |
-| [can_ip_forward](variables.tf#L99) | Enable IP forwarding. | bool | | false |
-| [confidential_compute](variables.tf#L105) | Enable Confidential Compute for these instances. | bool | | false |
-| [create_template](variables.tf#L111) | Create instance template instead of instances. | bool | | false |
-| [description](variables.tf#L116) | Description of a Compute Instance. | string | | "Managed by the compute-vm Terraform module." |
-| [enable_display](variables.tf#L122) | Enable virtual display on the instances. | bool | | false |
-| [encryption](variables.tf#L128) | Encryption options. Only one of kms_key_self_link and disk_encryption_key_raw may be set. If needed, you can specify to encrypt or not the boot disk. | object({…}) | | null |
-| [group](variables.tf#L138) | Define this variable to create an instance group for instances. Disabled for template use. | object({…}) | | null |
-| [hostname](variables.tf#L146) | Instance FQDN name. | string | | null |
-| [iam](variables.tf#L152) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
-| [instance_type](variables.tf#L158) | Instance type. | string | | "f1-micro" |
-| [labels](variables.tf#L164) | Instance labels. | map(string) | | {} |
-| [metadata](variables.tf#L170) | Instance metadata. | map(string) | | {} |
-| [min_cpu_platform](variables.tf#L176) | Minimum CPU platform. | string | | null |
-| [options](variables.tf#L202) | Instance options. | object({…}) | | {…} |
-| [scratch_disks](variables.tf#L229) | Scratch disks configuration. | object({…}) | | {…} |
-| [service_account](variables.tf#L241) | Service account email. Unused if service account is auto-created. | string | | null |
-| [service_account_create](variables.tf#L247) | Auto-create service account. | bool | | false |
-| [service_account_scopes](variables.tf#L255) | Scopes applied to service account. | list(string) | | [] |
-| [shielded_config](variables.tf#L261) | Shielded VM configuration of the instances. | object({…}) | | null |
-| [tag_bindings](variables.tf#L271) | Tag bindings for this instance, in key => tag value id format. | map(string) | | null |
-| [tags](variables.tf#L277) | Instance network tags for firewall rule targets. | list(string) | | [] |
+| [attached_disks](variables.tf#L38) | Additional disks, if options is null defaults will be used in its place. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null. | list(object({…})) | | [] |
+| [boot_disk](variables.tf#L83) | Boot disk properties. | object({…}) | | {…} |
+| [can_ip_forward](variables.tf#L101) | Enable IP forwarding. | bool | | false |
+| [confidential_compute](variables.tf#L107) | Enable Confidential Compute for these instances. | bool | | false |
+| [create_template](variables.tf#L113) | Create instance template instead of instances. | bool | | false |
+| [description](variables.tf#L118) | Description of a Compute Instance. | string | | "Managed by the compute-vm Terraform module." |
+| [enable_display](variables.tf#L124) | Enable virtual display on the instances. | bool | | false |
+| [encryption](variables.tf#L130) | Encryption options. Only one of kms_key_self_link and disk_encryption_key_raw may be set. If needed, you can specify to encrypt or not the boot disk. | object({…}) | | null |
+| [group](variables.tf#L140) | Define this variable to create an instance group for instances. Disabled for template use. | object({…}) | | null |
+| [hostname](variables.tf#L148) | Instance FQDN name. | string | | null |
+| [iam](variables.tf#L154) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
+| [instance_schedule](variables.tf#L160) | Assign or create and assign an instance schedule policy. Either resource policy id or create_config must be specified if not null. Set active to null to dtach a policy from vm before destroying. | object({…}) | | null |
+| [instance_type](variables.tf#L195) | Instance type. | string | | "f1-micro" |
+| [labels](variables.tf#L201) | Instance labels. | map(string) | | {} |
+| [metadata](variables.tf#L207) | Instance metadata. | map(string) | | {} |
+| [min_cpu_platform](variables.tf#L213) | Minimum CPU platform. | string | | null |
+| [options](variables.tf#L239) | Instance options. | object({…}) | | {…} |
+| [scratch_disks](variables.tf#L266) | Scratch disks configuration. | object({…}) | | {…} |
+| [service_account](variables.tf#L278) | Service account email. Unused if service account is auto-created. | string | | null |
+| [service_account_create](variables.tf#L284) | Auto-create service account. | bool | | false |
+| [service_account_scopes](variables.tf#L292) | Scopes applied to service account. | list(string) | | [] |
+| [shielded_config](variables.tf#L298) | Shielded VM configuration of the instances. | object({…}) | | null |
+| [snapshot_schedules](variables.tf#L308) | Snapshot schedule resource policies that can be attached to disks. | map(object({…})) | | {} |
+| [tag_bindings](variables.tf#L351) | Tag bindings for this instance, in key => tag value id format. | map(string) | | null |
+| [tags](variables.tf#L357) | Instance network tags for firewall rule targets. | list(string) | | [] |
## Outputs
diff --git a/modules/compute-vm/main.tf b/modules/compute-vm/main.tf
index cf0077e52..0172ebb05 100644
--- a/modules/compute-vm/main.tf
+++ b/modules/compute-vm/main.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -133,13 +133,18 @@ resource "google_compute_instance" "default" {
enable_display = var.enable_display
labels = var.labels
metadata = var.metadata
+ resource_policies = local.ischedule_attach
dynamic "attached_disk" {
for_each = local.attached_disks_zonal
iterator = config
content {
- device_name = config.value.device_name != null ? config.value.device_name : config.value.name
- mode = config.value.options.mode
+ device_name = (
+ config.value.device_name != null
+ ? config.value.device_name
+ : config.value.name
+ )
+ mode = config.value.options.mode
source = (
config.value.source_type == "attach"
? config.value.source
@@ -152,8 +157,12 @@ resource "google_compute_instance" "default" {
for_each = local.attached_disks_regional
iterator = config
content {
- device_name = config.value.device_name != null ? config.value.device_name : config.value.name
- mode = config.value.options.mode
+ device_name = (
+ config.value.device_name != null
+ ? config.value.device_name
+ : config.value.name
+ )
+ mode = config.value.options.mode
source = (
config.value.source_type == "attach"
? config.value.source
diff --git a/modules/compute-vm/resource-policies.tf b/modules/compute-vm/resource-policies.tf
new file mode 100644
index 000000000..1aaf6eccf
--- /dev/null
+++ b/modules/compute-vm/resource-policies.tf
@@ -0,0 +1,174 @@
+/**
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+# tfdoc:file:description Resource policies.
+
+locals {
+ ischedule = try(var.instance_schedule.create_config, null)
+ ischedule_attach = var.instance_schedule == null ? null : (
+ var.instance_schedule.create_config != null
+ # created policy with optional attach to allow policy destroy
+ ? (
+ var.instance_schedule.create_config.active
+ ? [google_compute_resource_policy.schedule.0.id]
+ : null
+ )
+ # externally managed policy
+ : [var.instance_schedule.resource_policy_id]
+ )
+}
+
+resource "google_compute_resource_policy" "schedule" {
+ count = local.ischedule != null ? 1 : 0
+ project = var.project_id
+ region = substr(var.zone, 0, length(var.zone) - 2)
+ name = var.name
+ description = coalesce(
+ local.ischedule.description, "Schedule policy for ${var.name}."
+ )
+ instance_schedule_policy {
+ expiration_time = local.ischedule.expiration_time
+ start_time = local.ischedule.start_time
+ time_zone = local.ischedule.timezone
+ dynamic "vm_start_schedule" {
+ for_each = local.ischedule.vm_start != null ? [""] : []
+ content {
+ schedule = local.ischedule.vm_start
+ }
+ }
+ dynamic "vm_stop_schedule" {
+ for_each = local.ischedule.vm_stop != null ? [""] : []
+ content {
+ schedule = local.ischedule.vm_stop
+ }
+ }
+ }
+}
+
+resource "google_compute_resource_policy" "snapshot" {
+ for_each = var.snapshot_schedules
+ project = var.project_id
+ region = substr(var.zone, 0, length(var.zone) - 2)
+ name = "${var.name}-${each.key}"
+ description = coalesce(
+ each.value.description, "Schedule policy ${each.key} for ${var.name}."
+ )
+ snapshot_schedule_policy {
+ schedule {
+ dynamic "daily_schedule" {
+ for_each = each.value.schedule.daily != null ? [""] : []
+ content {
+ days_in_cycle = each.value.schedule.daily.days_in_cycle
+ start_time = each.value.schedule.daily.start_time
+ }
+ }
+ dynamic "hourly_schedule" {
+ for_each = each.value.schedule.hourly != null ? [""] : []
+ content {
+ hours_in_cycle = each.value.schedule.hourly.hours_in_cycle
+ start_time = each.value.schedule.hourly.start_time
+ }
+ }
+ dynamic "weekly_schedule" {
+ for_each = each.value.schedule.weekly != null ? [""] : []
+ content {
+ dynamic "day_of_weeks" {
+ for_each = each.value.schedule.weekly
+ content {
+ day = day_of_weeks.value.day
+ start_time = day_of_weeks.value.start_time
+ }
+ }
+ }
+ }
+ }
+ dynamic "retention_policy" {
+ for_each = each.value.retention_policy != null ? [""] : []
+ content {
+ max_retention_days = each.value.retention_policy.max_retention_days
+ on_source_disk_delete = (
+ each.value.retention_policy.on_source_disk_delete_keep == false
+ ? "APPLY_RETENTION_POLICY"
+ : "KEEP_AUTO_SNAPSHOTS"
+ )
+ }
+ }
+ dynamic "snapshot_properties" {
+ for_each = each.value.snapshot_properties != null ? [""] : []
+ content {
+ labels = each.value.snapshot_properties.labels
+ storage_locations = each.value.snapshot_properties.storage_locations
+ guest_flush = each.value.snapshot_properties.guest_flush
+ }
+ }
+ }
+}
+
+resource "google_compute_disk_resource_policy_attachment" "boot" {
+ count = var.boot_disk.snapshot_schedule != null ? 1 : 0
+ project = var.project_id
+ zone = var.zone
+ name = try(
+ google_compute_resource_policy.snapshot[var.boot_disk.snapshot_schedule].name,
+ var.boot_disk.snapshot_schedule
+ )
+ disk = var.name
+ depends_on = [google_compute_instance.default]
+}
+
+resource "google_compute_disk_resource_policy_attachment" "attached" {
+ for_each = {
+ for k, v in local.attached_disks_zonal :
+ k => v if v.snapshot_schedule != null
+ }
+ project = var.project_id
+ zone = var.zone
+ name = try(
+ google_compute_resource_policy.snapshot[each.value.snapshot_schedule].name,
+ each.value.snapshot_schedule
+ )
+ disk = (
+ each.value.source_type == "attach"
+ ? each.value.source
+ : google_compute_disk.disks[each.key].name
+ )
+ depends_on = [
+ google_compute_instance.default,
+ google_compute_disk.disks
+ ]
+}
+
+resource "google_compute_region_disk_resource_policy_attachment" "attached" {
+ for_each = {
+ for k, v in local.attached_disks_regional :
+ k => v if v.snapshot_schedule != null
+ }
+ project = var.project_id
+ region = substr(var.zone, 0, length(var.zone) - 2)
+ name = try(
+ google_compute_resource_policy.snapshot[each.value.snapshot_schedule].name,
+ each.value.snapshot_schedule
+ )
+ disk = (
+ each.value.source_type == "attach"
+ ? each.value.source
+ : google_compute_region_disk.disks[each.key].name
+ )
+ depends_on = [
+ google_compute_instance.default,
+ google_compute_region_disk.disks
+ ]
+}
diff --git a/modules/compute-vm/tags.tf b/modules/compute-vm/tags.tf
index a9001323e..95be8318f 100644
--- a/modules/compute-vm/tags.tf
+++ b/modules/compute-vm/tags.tf
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+# tfdoc:file:description Tag bindings.
+
resource "google_tags_tag_binding" "binding" {
for_each = var.create_template ? {} : coalesce(var.tag_bindings, {})
parent = "//compute.googleapis.com/${google_compute_instance.default.0.id}"
diff --git a/modules/compute-vm/variables.tf b/modules/compute-vm/variables.tf
index 8ec1e7163..f76cf7e2f 100644
--- a/modules/compute-vm/variables.tf
+++ b/modules/compute-vm/variables.tf
@@ -38,11 +38,12 @@ variable "attached_disk_defaults" {
variable "attached_disks" {
description = "Additional disks, if options is null defaults will be used in its place. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null."
type = list(object({
- name = string
- device_name = optional(string)
- size = string
- source = optional(string)
- source_type = optional(string)
+ name = string
+ device_name = optional(string)
+ size = string
+ snapshot_schedule = optional(string)
+ source = optional(string)
+ source_type = optional(string)
options = optional(
object({
auto_delete = optional(bool, false)
@@ -82,8 +83,9 @@ variable "attached_disks" {
variable "boot_disk" {
description = "Boot disk properties."
type = object({
- auto_delete = optional(bool, true)
- source = optional(string)
+ auto_delete = optional(bool, true)
+ snapshot_schedule = optional(string)
+ source = optional(string)
initialize_params = optional(object({
image = optional(string, "projects/debian-cloud/global/images/family/debian-11")
size = optional(number, 10)
@@ -155,6 +157,41 @@ variable "iam" {
default = {}
}
+variable "instance_schedule" {
+ description = "Assign or create and assign an instance schedule policy. Either resource policy id or create_config must be specified if not null. Set active to null to dtach a policy from vm before destroying."
+ type = object({
+ resource_policy_id = optional(string)
+ create_config = optional(object({
+ active = optional(bool, true)
+ description = optional(string)
+ expiration_time = optional(string)
+ start_time = optional(string)
+ timezone = optional(string, "UTC")
+ vm_start = optional(string)
+ vm_stop = optional(string)
+ }))
+ })
+ default = null
+ validation {
+ condition = (
+ var.instance_schedule == null ||
+ try(var.instance_schedule.resource_policy_id, null) != null ||
+ try(var.instance_schedule.create_config, null) != null
+ )
+ error_message = "A resource policy name or configuration must be specified when not null."
+ }
+ validation {
+ condition = (
+ try(var.instance_schedule.create_config, null) == null ||
+ length(compact([
+ try(var.instance_schedule.create_config.vm_start, null),
+ try(var.instance_schedule.create_config.vm_stop, null)
+ ])) > 0
+ )
+ error_message = "A resource policy configuration must contain at least one schedule."
+ }
+}
+
variable "instance_type" {
description = "Instance type."
type = string
@@ -268,6 +305,49 @@ variable "shielded_config" {
default = null
}
+variable "snapshot_schedules" {
+ description = "Snapshot schedule resource policies that can be attached to disks."
+ type = map(object({
+ schedule = object({
+ daily = optional(object({
+ days_in_cycle = number
+ start_time = string
+ }))
+ hourly = optional(object({
+ hours_in_cycle = number
+ start_time = string
+ }))
+ weekly = optional(list(object({
+ day = string
+ start_time = string
+ })))
+ })
+ description = optional(string)
+ retention_policy = optional(object({
+ max_retention_days = number
+ on_source_disk_delete_keep = optional(bool)
+ }))
+ snapshot_properties = optional(object({
+ chain_name = optional(string)
+ guest_flush = optional(bool)
+ labels = optional(map(string))
+ storage_locations = optional(list(string))
+ }))
+ }))
+ nullable = false
+ default = {}
+ validation {
+ condition = alltrue([
+ for k, v in var.snapshot_schedules : (
+ (v.schedule.daily != null ? 1 : 0) +
+ (v.schedule.hourly != null ? 1 : 0) +
+ (v.schedule.weekly != null ? 1 : 0)
+ ) == 1
+ ])
+ error_message = "Schedule must contain exactly one of daily, hourly, or weekly schedule."
+ }
+}
+
variable "tag_bindings" {
description = "Tag bindings for this instance, in key => tag value id format."
type = map(string)
diff --git a/tests/modules/compute_vm/examples/instance-schedule-create.yaml b/tests/modules/compute_vm/examples/instance-schedule-create.yaml
new file mode 100644
index 000000000..26917c45e
--- /dev/null
+++ b/tests/modules/compute_vm/examples/instance-schedule-create.yaml
@@ -0,0 +1,31 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+values:
+ module.instance.google_compute_resource_policy.schedule[0]:
+ description: Schedule policy for schedule-test.
+ instance_schedule_policy:
+ - expiration_time: null
+ start_time: null
+ time_zone: UTC
+ vm_start_schedule:
+ - schedule: 0 8 * * *
+ vm_stop_schedule:
+ - schedule: 0 17 * * *
+ name: schedule-test
+ region: europe-west1
+
+counts:
+ google_compute_instance: 1
+ google_compute_resource_policy: 1
diff --git a/tests/modules/compute_vm/examples/instance-schedule-id.yaml b/tests/modules/compute_vm/examples/instance-schedule-id.yaml
new file mode 100644
index 000000000..409e9ddb0
--- /dev/null
+++ b/tests/modules/compute_vm/examples/instance-schedule-id.yaml
@@ -0,0 +1,21 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+values:
+ module.instance.google_compute_instance.default[0]:
+ resource_policies:
+ - projects/my-project/regions/europe-west1/resourcePolicies/test
+
+counts:
+ google_compute_instance: 1
diff --git a/tests/modules/compute_vm/examples/snapshot-schedule-create.yaml b/tests/modules/compute_vm/examples/snapshot-schedule-create.yaml
new file mode 100644
index 000000000..daf659c6c
--- /dev/null
+++ b/tests/modules/compute_vm/examples/snapshot-schedule-create.yaml
@@ -0,0 +1,19 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+counts:
+ google_compute_disk: 1
+ google_compute_disk_resource_policy_attachment: 2
+ google_compute_instance: 1
+ google_compute_resource_policy: 1