Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compute_disk_snapshot Weekly Schedule Detects Drift on Every Plan/Apply #155

Closed
invalidbassist opened this issue Mar 18, 2021 · 7 comments
Closed

Comments

@invalidbassist
Copy link

invalidbassist commented Mar 18, 2021

Terraform Version

0.13.5
Tested with 0.13.6 and 0.14.8

Terraform Configuration Files

module "disk_snapshots" {
  source  = "../../../modules/compute_disk_snapshot"
  name    = "backup-policy-test"
  project = var.project_id
  region  = var.region

  snapshot_retention_policy = {
    max_retention_days    = 10
    on_source_disk_delete = "KEEP_AUTO_SNAPSHOTS"
  }

  snapshot_schedule = {
    daily_schedule = null
    hourly_schedule = null
    weekly_schedule = {
      day_of_weeks =  [{
        start_time   = "23:00"
        day          = "SATURDAY"
    }]
  }
  }

  snapshot_properties = {
    guest_flush       = true
    storage_locations = ["US"]
    labels            = null
  }

  module_depends_on = []
  disks             = var.instance_disk
}

Expected Behavior

Terraform should deploy the snapshot schedule and attach to disks declared in the variable - which it does. On subsequent terraform apply commands there should be no drift detected and the snapshot schedule policy and attachments should not prevent the apply from completing.

Unexpected Behavior

When deployed with appropriate variables the weekly snapshot schedule is successfully deployed; however, the next Terraform apply or plan detects a drift in the snapshot schedule like:

resource "google_compute_resource_policy" "snapshot_policy" {
      ~ id        = "projects/##PROJECT_ID##/regions/us-east4/resourcePolicies/ssms-instance-dev-cb-snapshot" -> (known after apply)
        name      = "ssms-instance-dev-cb-snapshot"
        project   = "##PROJECT_ID"
        region    = "https://www.googleapis.com/compute/v1/projects/##PROJECT_ID##/regions/us-east4"
      ~ self_link = "https://www.googleapis.com/compute/v1/projects/##PROJECT_ID##/regions/us-east4/resourcePolicies/ssms-instance-dev-cb-snapshot" -> (known after apply)

      ~ snapshot_schedule_policy {
            retention_policy {
                max_retention_days    = 10
                on_source_disk_delete = "KEEP_AUTO_SNAPSHOTS"
            }

          ~ schedule {

              ~ weekly_schedule {
                  - day_of_weeks { # forces replacement
                      - day        = "SATURDAY" -> null
                      - start_time = "23:00" -> null
                    }
                  + day_of_weeks { # forces replacement
                      + day        = "SATURDAY"
                      + start_time = "23:00"
                    }
                }
            }

            snapshot_properties {
                guest_flush       = true
                labels            = null
                storage_locations = [
                    "us",
                ]
            }
        }
    }

If running an apply, the snapshot schedule tries to edit the schedule but errors out:

Error: Error when reading or editing ResourcePolicy: googleapi: Error 400: The resource_policy resource 'projects/##PROJECT_ID##6/regions/us-east4/resourcePolicies/ssms-instance-dev-cb-snapshot' is already being used by 'projects/##PROJECT_ID##/zones/us-east4-b/disks/ssms-instance-dev-cb', resourceInUseByAnotherResource

Steps to recreate

  1. Deploy a snapshot schedule using the module and terraform apply
  2. Without editing terraform code run another terraform apply
@morgante
Copy link
Contributor

Are you using 23:00 or 6:00 as your start time? It looks inconsistent between your plan and config.

@invalidbassist
Copy link
Author

Are you using 23:00 or 6:00 as your start time? It looks inconsistent between your plan and config.

Good call, edited accordingly

@morgante
Copy link
Contributor

Which value are you actually using though? Because I notice that the plan was attempting to change 6:00 to 06:00` which might be the cause of your permadiff.

@morgante
Copy link
Contributor

Also it looks like an upstream issue: hashicorp/terraform-provider-google#8460

@invalidbassist
Copy link
Author

Which value are you actually using though? Because I notice that the plan was attempting to change 6:00 to 06:00` which might be the cause of your permadiff.

I noticed that during testing as well and updated first to 06:00 and then to 23:00 where I still experienced the permadiff issues.

@invalidbassist
Copy link
Author

I was able to resolve creating a module that uses the same snapshot_schedule variable format, but uses a different snapshot policy resource:

# Build the region into the proper format
locals {
  region = "https://www.googleapis.com/compute/v1/projects/${var.project_id}/regions/${var.region}"
}

# Build the weekly_schedule variables from the weekly_snapshot_schedule variable if it contains a weekly schedule
locals {
  weekly_schedule             = var.snapshot_schedule.weekly_schedule != null
  weekly_schedule_start_time  = var.snapshot_schedule.weekly_schedule == null ? "" : var.snapshot_schedule.weekly_schedule.day_of_weeks["start_time"]
  weekly_schedule_day         = var.snapshot_schedule.weekly_schedule == null ? "" : var.snapshot_schedule.weekly_schedule.day_of_weeks["day"]
}

resource "null_resource" "module_depends_on" {
  triggers = {
    value = length(var.module_depends_on)
  }
}

# If weekly_schedule is not needed, build the snapshot policy for day or hourly using dynamic blocks
resource "google_compute_resource_policy" "dynamic_snapshot_policy" {
  count   = local.weekly_schedule ? 0 : 1
  name    = "${var.name}-snapshot"
  project = var.project_id
  region  = local.region
  snapshot_schedule_policy {
    retention_policy {
      max_retention_days    = var.snapshot_retention_policy.max_retention_days
      on_source_disk_delete = var.snapshot_retention_policy.on_source_disk_delete
    }

    schedule {
      dynamic "daily_schedule" {
        for_each = var.snapshot_schedule.daily_schedule == null ? [] : [var.snapshot_schedule.daily_schedule]
        content {
          days_in_cycle = daily_schedule.value.days_in_cycle
          start_time    = daily_schedule.value.start_time
        }
      }

      dynamic "hourly_schedule" {
        for_each = var.snapshot_schedule.hourly_schedule == null ? [] : [var.snapshot_schedule.hourly_schedule]
        content {
          hours_in_cycle = hourly_schedule.value["hours_in_cycle"]
          start_time     = hourly_schedule.value["start_time"]
        }
      }

    }

    snapshot_properties {
      labels = {
        name = var.enable_vss ? "windows" : "linux"
      }
      storage_locations = ["us"]
      guest_flush       = var.enable_vss

    }
  }

  depends_on = [null_resource.module_depends_on]
}

# If weekly schedule is declared, build the snapshot policy using the local weekly variables
resource "google_compute_resource_policy" "weekly_snapshot_policy" {
  count   = local.weekly_schedule ? 1 : 0
  name    = "${var.name}-snapshot"
  project = var.project_id
  region  = local.region
  snapshot_schedule_policy {
    retention_policy {
      max_retention_days    = var.snapshot_retention_policy.max_retention_days
      on_source_disk_delete = var.snapshot_retention_policy.on_source_disk_delete
    }

    schedule {
      weekly_schedule {
        day_of_weeks {
          start_time = local.weekly_schedule_start_time
          day        = local.weekly_schedule_day
        }
      }
    }

    snapshot_properties {
      labels = {
        name = var.enable_vss ? "windows" : "linux"
      }
      storage_locations = ["us"]
      guest_flush       = var.enable_vss

    }
  }

  depends_on = [null_resource.module_depends_on]
}

# Determine which schedule resource should drive the attachement
locals {
  snapshot_policy_name = local.weekly_schedule ? google_compute_resource_policy.weekly_snapshot_policy[0].name : google_compute_resource_policy.dynamic_snapshot_policy[0].name
}

# Attach the policy to the disks from the disk variables
resource "google_compute_disk_resource_policy_attachment" "attachment" {
  for_each = toset(var.disks)
  name     = local.snapshot_policy_name
  project  = element(split("/", each.key), index(split("/", each.key), "projects", ) + 1, )
  disk     = element(split("/", each.key), index(split("/", each.key), "disks", ) + 1, )
  zone     = element(split("/", each.key), index(split("/", each.key), "zones", ) + 1, )

  depends_on = [null_resource.module_depends_on, google_compute_resource_policy.dynamic_snapshot_policy, google_compute_resource_policy.weekly_snapshot_policy ]
}

@invalidbassist
Copy link
Author

Confirmed that improperly formatted time was the cause of the issues despite my best efforts at reading plan outputs - closing issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants