GCP Terraform resource policy in compute module issues - google-cloud-platform

I am trying to add a start-stop schedule to our vm instances in our cloud repository (it is a terraform/terragrunt setup)
The example presented on the official site is this:
So since we use Terragrunt as a wrapper my module looks like this:
And for reference my variable block is this:
When i push the code it errors on step 0 in CloudBuild with the following error:
Error: Reference to undeclared input variable on main.tf line 116, in resource "google_compute_resource_policy" "hourly": 116: time_zone = var.time_zone
An input variable with the name "time_zone" has not been declared. This variable can be declared with a variable "time_zone" {}block.
I have tried placing this variable in different positions of the block but i keep getting the same error. Has anyone got any ideas?

This is now resolved. I want to thank #kornshell93 for pointing me in the right direction.
I ended up using the block as suggested but creating a new module and hitting that from a separate section within my vm instance block. I linked to the project as a dependency this way. The previous method via the main compute instance module kept failing on all other vm instances, almost like it was expecting this block on all of them.
resource "google_compute_resource_policy" "hourly" {
name = var.instance_schedule_policy.name
region = var.region
project = var.project
description = "Start and stop instances"
instance_schedule_policy {
vm_start_schedule {
schedule = var.instance_schedule_policy.vm_start_schedule
}
vm_stop_schedule {
schedule = var.instance_schedule_policy.vm_stop_schedule
}
time_zone = var.instance_schedule_policy.time_zone
}
}
And the vm instance block
inputs = {
#instance start/stop schedules
project = dependency.project.outputs.project_id
region = "europe-west2"
instance_schedule_policy = {
name = "start-stop"
vm_start_schedule = "30 07 * * *"
vm_stop_schedule = "00 18 * * *"
time_zone = "GMT"
}
}

Related

Terraform: Passing variables while importing module

After reading this https://developer.hashicorp.com/terraform/language/values/variables#assigning-values-to-root-module-variables, I was certain that there are 3 ways to set variable value.
Recently I came across code in one our projects which passes variables while importing module.
module "robot_shell" {
source = "./modules/xx_shell"
xx_resource_name_prefix = local.resource_name_prefix
cloudwatch_log_group_retention_days = 30
s3_expiration_days = 30
}
file in the module ./modules/xx_shell
resource "aws_s3_bucket_lifecycle_configuration" "dest" {
bucket = aws_s3_bucket.dest.bucket
rule {
id = "expire"
status = "Enabled"
expiration {
days = var.s3_expiration_days
}
}
}
variable definition variables.tf
variable "s3_expiration_days" {
type = number
description = "S3 bucket objects expiration days https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration#days"
}
Why does terraform documentation does not talk about it? Or is this a old way which is not used anymore?
Its a normal way to pass variables to modules as you described. This is described in TF docs in:
Add module configuration
The link that you provided in the question is about passing variables to root/parent module when you run plan/apply. But when you want to pass variables to sub-modules defined using module block, you pass them through module arguments.

Terraform update only a cloud function from a bunch

I have a Terraform project that allows to create multiple cloud functions.
I know that if I change the name of the google_storage_bucket_object related to the function itself, terraform will see the difference of the zip name and redeploy the cloud function.
My question is, there is a way to obtain the same behaviour, but only with the cloud functions that have been changed?
resource "google_storage_bucket_object" "zip_file" {
# Append file MD5 to force bucket to be recreated
name = "${local.filename}#${data.archive_file.source.output_md5}"
bucket = var.bucket.name
source = data.archive_file.source.output_path
}
# Create Java Cloud Function
resource "google_cloudfunctions_function" "java_function" {
name = var.function_name
runtime = var.runtime
available_memory_mb = var.memory
source_archive_bucket = var.bucket.name
source_archive_object = google_storage_bucket_object.zip_file.name
timeout = 120
entry_point = var.function_entry_point
event_trigger {
event_type = var.event_trigger.event_type
resource = var.event_trigger.resource
}
environment_variables = {
PROJECT_ID = var.env_project_id
SECRET_MAIL_PASSWORD = var.env_mail_password
}
timeouts {
create = "60m"
}
}
By appending MD5 every cloud functions will result in a different zip file name, so terraform will re-deploy every of them and I found that without the MD5, Terraform will not see any changes to deploy.
If I have changed some code only inside a function, how can I tell to Terraform to re-deploy only it (so for example to change only its zip file name)?
I hope my question is clear and I want to thank you everyone who tries to help me!

Terraform - How to output input variable?

I have a custom terraform module which create an AWS EC2 instance, so it's relying on the aws provider.
This terraform custom module is used as a base to describes the instance i want to create, but I also need some other information that will be reused later.
For example, i want to define a description to the VM as an input variable, but i don't need to use it at all to create my vm with the aws provider.
I just want this input variable to be sent directly as an output so it can be re-used later once terraform has done its job.
ex
What I have as input variable
variable "description" {
type = string
description = "Description of the instance"
}
what I wanna put as output variable
output "description" {
value = module.ec2_instance.description
}
What my main module is doing
module "ec2_instance" {
source = "./modules/aws_ec2"
ami_id = var.ami_id
instance_name = var.hostname
disk_size = var.disk_size
create_disk = var.create_disk
availability_zone = var.availability_zone
disk_type = var.disk_type
// I don't need the description variable for the module to work, and I don't wanna do anything with it here, i need it later as output
}
I feel stupid because i searched the web for an answer and can't find anything to do that.
Can you help ?
Thanks
EDIT: Added example of code
If you have an input variable declared like this:
variable "description" {
type = string
}
...then you can return its value as an output value like this, in the same module where you declared it:
output "description" {
value = var.description
}

terraform 12 count date_template not working

I'm upgrading to terraform 12 and have an asg module that references a root repository. As part of this, it uses a data.template_file resource to attach user data to the asg which is then put in to log files on the instances. The module looks as follows;
module "cef_fleet" {
source = "git::ssh://git#github.com/asg-repo.git?ref=terraform12"
user_data_rendered = data.template_file.init.rendered
instance_type = var.instance_type
ami = var.ami
etc ...
which as you can see calls the data resource;
data "template_file" "init" {
count = signum(var.cluster_size_max)
template = file("${path.module}/template-files/init.sh")
vars = {
account_name = var.account_name
aws_account_number = var.aws_account_number
this works fine in terraform 11 but when I changed to terraoform 12 and try to apply I get this error:
*Because data.template_file.init has "count" set, its attributes must be
accessed on specific instances.
For example, to correlate with indices of a referring resource, use:
data.template_file.init[count.index]*
if I change this in my module to user_data_rendered = data.template_file.init[count.index]
I then get this error;
The "count" object can be used only in "resource" and "data" blocks, and only
when the "count" argument is set.
I don't know what to do here. If I leave the .rendered in then it doesn't seem to recognise the [count.index] as I get the first error again. Has anyone any advice on what I need to do?

Terraform and DigitalOcean: assign volume to specific droplet created with count parameter

just started exploring terraform to spin up droplets and volumes on digital ocean.
My question is to know the right way to do the following:
create a certain number of droplet instances using count within digitalocean_dropletresource named ubuntu16
assign a digitalocean_volume only to one or a subset of previously created droplets.
How to do it?I was assuming to use droplets_id property on digitalocean_volume resource. Something like:
resource "digitalocean_volume" "foovolume" {
...
droplet_ids = ["${digitalocean_droplet.ubuntu16.0.id}"]
}
Validating it with terraform validate I got:
Error: digitalocean_volume.foovolume: "droplet_ids": this field cannot be set
Any advice? Thanks to any inputs on it.
Regards
The way the Terraform provider for DigtialOcean is currently implemented requires that you take the opposite approach. You can specify which volumes are attached to which Droplets by defining the volume_ids of the Droplet resource. For example:
resource "digitalocean_volume" "volume" {
region = "nyc3"
count = 3
name = "volume-${count.index + 1}"
size = 100
description = "an example volume"
}
resource "digitalocean_droplet" "web" {
count = 3
image = "ubuntu-17-10-x64"
name = "web-${count.index + 1}"
region = "nyc3"
size = "1gb"
volume_ids = ["${element(digitalocean_volume.volume.*.id, count.index)}"]
}
If you look at the docs for the volume resource, you'll see that droplet_ids is a "computed" field. This means that you are unable to set the field, and that its value is computed by Terraform via the provider's API.