Terraform: Resource 'aws_instance' not found for variable 'aws_instance.id' - amazon-ec2

I have started using terraform to automate AWS resource provisioning for setting up k8s cluster. I am facing an issue when trying to refer aws_instance.id from aws_eip. Here are the useful details:
aditya#aditya-VirtualBox:~/Desktop/terraform-states$ terraform -v
Terraform v0.11.11
+ provider.aws v1.54.0
1) aws-eip.tf
resource "aws_eip" "nat" {
instance = "${aws_instance.xenial.id}"
vpc = true
depends_on = ["aws_internet_gateway.esya_igw"]
}
2) aws_inst.tf:
resource "aws_instance" "xenial" {
ami = "${var.aws_ami}"
instance_type = "t3.large"
ebs_optimized = true
monitoring = true
count = "8"
key_name = "${var.aws_key_name}"
tags{
Name = "KubeVMCluster${count.index + 1}"
}
}
Expected Behavior: AWS EIP must be able to refer to AWS Instance.
Current Behavior: We are getting this error:
aditya#aditya-VirtualBox:~/Desktop/terraform-states$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------
Error: Error running plan: 1 error(s) occurred:
* aws_eip.nat: 1 error(s) occurred:
* aws_eip.nat: Resource 'aws_instance.xenial' not found for variable 'aws_instance.xenial.id'
I have tried to find a solution by referring to similar kind of issues in Github and elsewhere, but to no avail. According to me, I don't find anything problematic with the declarative code.
I need help in resolving this issue.
Regards
Aditya

Related

Receiving error in AWS Secrets manager awscli for: Version "AWSCURRENT" not found when deployed via Terraform

Overview
Create a aws_secretsmanager_secret
Create a aws_secretsmanager_secret_version
Store a uniquely generated string as that above version
Use local-exec provisioner to store the actual secured string using bash
Reference that string using the secretsmanager resource in for example, an RDS instance deployment.
Objective
Keep all plain text strings out of remote-state residing in a S3 bucket
Use AWS Secrets Manager to store these strings
Set once, retrieve by calling the resource in Terraform
Problem
Error: Secrets Manager Secret
"arn:aws:secretsmanager:us-east-1:82374283744:secret:Example-rds-secret-fff42b69-30c1-df50-8e5c-f512464a4a11-pJvC5U"
Version "AWSCURRENT" not found
when running terraform apply
Question
Why isn't it moving the AWSCURRENT version automatically? Am I missing something? Is my bash command wrong? The value does not write to the secret_version, but it does reference it correctly.
Look in main.tf code, which actually performs the command:
provisioner "local-exec" {
command = "bash -c 'RDSSECRET=$(openssl rand -base64 16); aws secretsmanager put-secret-value --secret-id ${data.aws_secretsmanager_secret.secretsmanager-name.arn} --secret-string $RDSSECRET --version-stages AWSCURRENT --region ${var.aws_region} --profile ${var.aws-profile}'"
}
Code
main.tf
data "aws_secretsmanager_secret_version" "rds-secret" {
secret_id = aws_secretsmanager_secret.rds-secret.id
}
data "aws_secretsmanager_secret" "secretsmanager-name" {
arn = aws_secretsmanager_secret.rds-secret.arn
}
resource "random_password" "db_password" {
length = 56
special = true
min_special = 5
override_special = "!#$%^&*()-_=+[]{}<>:?"
keepers = {
pass_version = 1
}
}
resource "random_uuid" "secret-uuid" { }
resource "aws_secretsmanager_secret" "rds-secret" {
name = "DAL-${var.environment}-rds-secret-${random_uuid.secret-uuid.result}"
}
resource "aws_secretsmanager_secret_version" "rds-secret-version" {
secret_id = aws_secretsmanager_secret.rds-secret.id
secret_string = random_password.db_password.result
provisioner "local-exec" {
command = "bash -c 'RDSSECRET=$(openssl rand -base64 16); aws secretsmanager put-secret-value --secret-id ${data.aws_secretsmanager_secret.secretsmanager-name.arn} --secret-string $RDSSECRET --region ${var.aws_region} --profile ${var.aws-profile}'"
}
}
variables.tf
variable "aws-profile" {
description = "Local AWS Profile Name "
type = "string"
}
variable "aws_region" {
description = "aws region"
default="us-east-1"
type = "string"
}
variable "environment" {}
terraform.tfvars
aws_region="us-east-1"
aws-profile="Example-Environment"
environment="dev"
The error likely isn't occuring in your provisioner execution per se, because if you remove the provisioner block the error still occurs on apply--but confusingly only the first time after a destroy.
Removing the data "aws_secretsmanager_secret_version" "rds-secret" block as well "resolves" the error completely.
I'm guessing there is some sort of config delay issue here...but adding a 20 second delay provisioner to the aws_secretsmanager_secret.rds-secret resource block didn't help.
And the value from the data block can be successfully output on subsequent apply runs, so maybe it's not just timing.
Even if you resolve the above more basic issue, it's likely your provisioner will still be confusing things by modifying a resource that Terraform is trying to manage in the same run. I'm not sure there's a way to get around that except perhaps by splitting into two separate operations.
Update:
It turns out that on the first run the data sources are read before the aws_secretsmanager_secret_version resource is created. Just adding depends_on = [aws_secretsmanager_secret_version.rds-secret-version] to the data "aws_secretsmanager_secret_version" block resolves this fully and makes the interpolation for your provisioner work as well. I haven't tested the actual provisioner.
Also you may need to consider this (which I take to not always apply to 0.13):
NOTE: In Terraform 0.12 and earlier, due to the data resource behavior of deferring the read until the apply phase when depending on values that are not yet known, using depends_on with data resources will force the read to always be deferred to the apply phase, and therefore a configuration that uses depends_on with a data resource can never converge. Due to this behavior, we do not recommend using depends_on with data resources.

Error: Code="VMExtensionProvisioningError" JsonADDomainExtension

I have terraform script which make a domain join with the code below:
resource "azurerm_virtual_machine_extension" "join-domain" {
name = azurerm_virtual_machine.client.name
virtual_machine_id = azurerm_virtual_machine.client.id
// resource_group_name = var.resource_group_name
//virtual_machine_name = azurerm_virtual_machine.client.name
publisher = "Microsoft.Compute"
type = "JsonADDomainExtension"
type_handler_version = "1.3"
# NOTE: the `OUPath` field is intentionally blank, to put it in the Computers OU
settings = <<SETTINGS
{
"Name": "${var.active_directory_domain}",
"OUPath": "",
"User": "${var.active_directory_domain}\\${var.active_directory_username}",
"Restart": "true",
"Options": "3"
}
SETTINGS
protected_settings = <<SETTINGS
{
"Password": "${var.active_directory_password}"
}
SETTINGS
depends_on = ["null_resource.wait-for-domain-to-provision"]
}
After the code run, it gets the error below in Terraform:
Error: Code="VMExtensionProvisioningError" Message="VM has reported a failure when processing extension 'pocvde-client'. Error message: \"Exception(s) occured while joining Domain 'pocvde.local'\"\r\n\r\nMore information on troubleshooting is available at https://aka.ms/vmextensionwindowstroubleshoot "
on modules/windows-client/4-join-domain.tf line 1, in resource "azurerm_virtual_machine_extension" "join-domain":
1: resource "azurerm_virtual_machine_extension" "join-domain" {
I have checked the windows client logs in C:\WindowsAzure\Logs\Plugins\Microsoft.Compute.JsonADDomainExtension, i got the trace below:
2020-06-23T06:30:54.1176834Z [Info]: Get Domain/Workgroup Information
2020-06-23T06:30:54.1645880Z [Info]: Current domain: (), current workgroup: WORKGROUP, IsDomainJoin: True, Target Domain/Workgroup: pocvde.local.
2020-06-23T06:30:54.1802137Z [Info]: Domain Join Path.
2020-06-23T06:30:54.1802137Z [Info]: Current Domain name is empty/null. Try to get Local domain name.
2020-06-23T06:30:54.1958114Z [Info]: In AD Domain extension process, the local domain is: ''.
2020-06-23T06:30:54.1958114Z [Info]: Domain Join will be performed.
2020-06-23T06:30:54.3460994Z [Error]: Try join: domain='pocvde.local', ou='', user='pocvde.local\AdminAls', option='NetSetupJoinDomain, NetSetupAcctCreate' (#3:User Specified), errCode='1355'.
2020-06-23T06:30:54.3621879Z [Error]: Setting error code to 53 while joining domain
2020-06-23T06:30:54.4085771Z [Error]: Try join: domain='pocvde.local', ou='', user='pocvde.local\AdminAls', option='NetSetupJoinDomain' (#1:User Specified without NetSetupAcctCreate), errCode='1355'.
2020-06-23T06:30:54.4085771Z [Error]: Setting error code to 53 while joining domain
2020-06-23T06:30:54.4241709Z [Error]: Computer failed to join domain 'pocvde.local' from workgroup 'WORKGROUP'.
I have changed the client vm OS from DataCenter-16 to Windows 10, i got still same error. Increased the waiting time before domain join operation from 12 minutes to 24 minutes, nothing changed.
Do you have any idea?
I saw that the Domain Controller was not set correctly, after solving that domain join operation is done correctly and that solved my problem

terraform: lambda invocation during destroy

I have lambda invocation in our terraform-built environment:
data "aws_lambda_invocation" "this" {
count = var.invocation == "true" ? 1 : 0
function_name = aws_lambda_function.this.function_name
input = <<JSON
{
"Name": "Invocation"
}
JSON
}
The problem: the function is invoked not only during creation ("apply") but deletion ("destroy") too. How to invoke it during creation only? I thought about checking environment variables in the lambda (perhaps TF adds name of the process here or something like that) but I hope there's a better way.
Worth checking if you can use the -var 'lambda_xxx=execute' option while running the terraform command to check if the lambda code needs to be executed or not terraform docs
Using that variable lambda_xxx passed in via the command line while executing the command, you can check in the terraform code whether you want to run the lambda code or not.
Below code creates a waf only if the count is 1
resource "aws_waf_rule" "wafrule" {
depends_on = ["aws_waf_ipset.ipset"]
name = "${var.environment}-WAFRule"
metric_name = "${replace(var.environment, "-", "")}WAFRule"
count = "${var.is_waf_enabled == "true" ? 1 : 0}"
predicates {
data_id = "${aws_waf_ipset.ipset.id}"
negated = false
type = "IPMatch"
}
}
Variable declared in variables.tf file
variable "is_waf_enabled" {
type = "string"
default = "false"
description = "String value to indicate if WAF/API KEY is turned on or off (true/any_value)"
}
When you run the command any value other than true is considered false as we are just checking for string true.
Similarly you can do this for your lambda.
There are better alternative solutions for this problem now, which weren't available at the time the question was asked.
Lambda Invocation Resource in AWS provider: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_invocation
Lambda Based Resource in LambdaBased provider: https://registry.terraform.io/providers/thetradedesk/lambdabased/latest/docs/resources/lambdabased_resource
With the disclaimer that I'm the developer of the latter one: If the underlying problem is managing a resource through lambda functions, the lambda based resource has some good features tailored specifically to accomplish that with the obvious drawback of adding another provider dependency.

How to call resources name having variables

Have a look at the code first
resource "aws_instance" "ec2-lab-cis01-${var.aue2a}-rgs" {
ami = "ami-0356d62c1d9705bdf"
instance_type = "t3.small" #t3.small
key_name = "${var.key_pair}"
}
output "lab-cis01" {
value = ["Private IP = ${aws_instance.ec2-lab-cis01-${var.aue2a}-rgs.private_ip}"]
}
I have multiple servers, I want to use variables names in the names of resources. How can I do this? I can not also reference this ec2 name while creating route53 entries.
The error what VS Code is giving me is:
"expected "}" but found invalid sequence "$""
when I run the terraform init it gives me the following error
Error loading /test/test.tf: Error reading config for output lab-cis01: parse error at 1:47: expected "}" but found invalid sequence "$"

Variable substitution in terraform built-in functions

In Terraform, I do not manage to assign a private IP to my instances using the cidrhost built-in function.
I'm pretty sure I do not have the correct syntax but cannot figure out what is wrong.
# Get the list of subnet ids of my VPC
data "aws_subnet_ids" "org_subnet_ids" {
vpc_id = "${data.aws_vpc.org_vpc.id}"
}
# Get the list of subnets from the ids
data "aws_subnet" "org_subnets" {
count = "${length(data.aws_subnet_ids.org_subnet_ids.ids)}"
id = "${data.aws_subnet_ids.org_subnet_ids.ids[count.index]}"
}
# Create instances and assign each of them to a different subnet
resource "aws_instance" "manager" {
count = 3
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.small"
subnet_id = "${data.aws_subnet_ids.org_subnet_ids.ids[count.index]}"
private_ip = "${cidrhost(${data.aws_subnet.org_subnets.cidr_block[count.index]}, count.index + 1)}"
tags {
Name = "manager-${count.index + 1}"
}
}
"$ terraform plan" fails with the following error:
Error: Failed to load root config module: Error loading ./provisionning/aws/ec2.tf
Error reading config for aws_instance[manager]: parse error at 1:12: expected expression but found invalid sequence "$"
Any idea what I'm missing here ?

Resources