How to pass multi-line string data to Terratest terraform.Options.Vars field? - terraform

I'm testing a Terraform module using Terratest. One of the input variables to the module is supposed to be the contents of a config file (so that the templatefile function can be used). This module under test is intended to be used as the source for other modules and thus I don't have too much flexibility to change it around.
The basic structure of the inputs for this module in Go for terratest is this
terraformOptions: &terraform.Options{
Vars: map[string]interface{}{
"sidecars": map[string]interface{}{
"envoy": map[string]interface{}{
"config_data": envoyConfigString,
...
The config_data field is the one causing issues. Right now I'm reading the file data in using Go's ioutil.ReadFile and converting it to a string. However, when the terratest runs the tests I get the following errors
│ Error: Invalid multi-line string
│
│ on line 1:
│ (source code not available)
│
│ Quoted strings may not be split over multiple lines. To produce a
│ multi-line string, either use the \n escape to represent a newline
│ character or use the "heredoc" multi-line template syntax.
╵
╷
│ Error: Unterminated template string
│
│ on line 1:
│ (source code not available)
│
│ No closing marker was found for the string.
How to I pass multi-line file data through the Vars field?

Related

Terraform not declaring tfvars

I am new to Terraform and I am writing a script. Following is my directory structure
folder
---.terraform
---..terraform.lock.hcl
---main.tf
---terraform.tfvars
---variables.tf
Following is my content on terraform.tfvars.
environment = "development"
Following is my content on main.tf.
tags = {
environment = var.environment
}
But the values are not updating. Following is the error:
╷
│ Warning: Value for undeclared variable
│
│ The root module does not declare a variable named "environment" but a value was found in file "terraform.tfvars". If you meant to use this value, add a "variable" block to the configuration.
│
│ To silence these warnings, use TF_VAR_... environment variables to provide certain "global" settings to all configurations in your organization. To reduce the verbosity of these warnings, use the
│ -compact-warnings option.
╵
╷
│ Warning: Value for undeclared variable
│
│ The root module does not declare a variable named "admin_username" but a value was found in file "terraform.tfvars". If you meant to use this value, add a "variable" block to the configuration.
│
│ To silence these warnings, use TF_VAR_... environment variables to provide certain "global" settings to all configurations in your organization. To reduce the verbosity of these warnings, use the
│ -compact-warnings option.
╵
╷
│ Warning: Values for undeclared variables
│
│ In addition to the other similar warnings shown, 1 other variable(s) defined without being declared.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on main.tf line 22, in resource "azurerm_resource_group" "tf_example_rg":
│ 22: environment = var.environment
│
│ An input variable with the name "environment" has not been declared. This variable can be declared with a variable "environment" {} block.
As I am using terraform.tfvars I don't need to give the filename on CLI. I think I am doing everything right but it's yet not working.
You have to actually declare your variable using variable block. For example:
variable "environment" {}
If you have such declarations, you have to double check the spelling and locations of them.
#AunZaidi , As stated in the error messages terraform can not find the defined variables.
The root module does not declare a variable named "environment" but a value was found in file "terraform.tfvars". If you meant to use this value, add a "variable" block to the configuration.
I would recommend you to take a look at the terraform-azure-tutorials to get acquainted with the basics.
you can solve your issue by just defining a new variable using syntax
variable "environment" {
type = string
description = "(optional) Environment for the deployment"
}
Refer to https://developer.hashicorp.com/terraform/language/values/variables#arguments for definitions of the arguments used in terraform variables.
Also one of the recommended practices is to use a dedicated file variables.tf for all the variables inputs required in your terraform code.

How to import Route53 record that contains underscores

I have an existing Route53 record that I'm attempting to import. Example of the record: 50200._dkey.mydomain.com
I create the resource like so:
resource "aws_route53_record" "50200_dkey_txt" {
zone_id = aws_route53_zone.mydomain_com.zone_id
name = "50200._dkey.mydomain.com"
type = "TXT"
ttl = "300"
records = ["text_record_contents"]
}
Then, I run the import:
terraform import module.route53.aws_route53_record.50200_dkey_txt Z0N3ID0FZ0NE_50200._dkey.mydomain.com_TXT
I'm greeted with the following error:
╷
│ Error: Attribute name required
│
│ on <import-address> line 1:
│ 1: module.route53.aws_route53_record.50200_dkey_txt
│
│ Dot must be followed by attribute name.
╵
I'm assuming the underscore in the record is the culprit. If I'm correct in assuming so, is there a way to escape the underscore character or format it in such way to make terraform read it in literal form? I attempted to wrap it in single quotes, but received the same error.
Terraform does not allow a resource name that starts with a digit, because when referring to resources elsewhere in the module and on the command line Terraform (similar to many other languages) treats a digit as the start of a number, rather than as the start of a name.
Normally Terraform would catch this when parsing your configuration, but I think because you are using terraform import as your first command to run here it's the command line parsing that is coming first, and therefore unfortunately raising a less helpful error.
This is what other Terraform commands would've shown, due to the configuration being invalid:
╷
│ Error: Invalid resource name
│
│ on example.tf line 1, in resource "aws_route53_record" "50200_dkey":
│ 1: resource "aws_route53_record" "50200_dkey" {
│
│ A name must start with a letter or underscore and may contain only letters,
│ digits, underscores, and dashes.
╵
The solution then is to change the resource name to be a valid name, such as by adding some letters to the start of it as a prefix:
resource "aws_route53_record" "txt_50200_dkey" {
# ...
}
Then when you run terraform import you should specify the new resource name, but you should be able to keep the same remote identifier (the second argument) so that Terraform will bind the given remote object to the given local address:
terraform import "module.route53.aws_route53_record.txt_50200_dkey" "Z0N3ID0FZ0NE_50200._dkey.mydomain.com_TXT"
(I'm actually not sure how aws_route53_record in particular interprets its "remote ID" strings, so I've just copied what you tried verbatim here. With the invalid resource name fixed this may expose a new error about the ID string, but I probably won't know the answer to that one if so. 😬)
The import command is slightly off. It should be:
terraform import module.route53.aws_route53_record.50200_dkey Z0N3ID0FZ0NE_50200._dkey.mydomain.com_TXT
Note the form for the namespace is <optional module>.<optional module declared name>.<resource type>.<resource name>["<optional iterator key>"].

Terraform - Variable defined in "*.auto.tfvars" file, but still cannot be discovered

I have the following directory Structure:
.
├── ./first_terraform.tf
├── ./modules
│   └── ./modules/ssh_keys
│   ├── ./modules/ssh_keys/main.tf
│   ├── ./modules/ssh_keys/outputs.tf
│   └── ./modules/ssh_keys/variables.tf
├── ./terraform.auto.tfvars
├── ./variables.tf
I am trying to pass a variable ssh_key to my child module defined as main.tf inside ./modules/ssh_keys/main.tf
resource "aws_key_pair" "id_rsa_ec2" {
key_name = "id_rsa_ec2"
public_key = file(var.ssh_key)
}
I also have this variable defined both at root and child level variables.tf file. For the value, I have set it in terraform.auto.tfvars as below
# SSH Key
ssh_key = "~/.ssh/haha_key.pub"
I also have a variable defined in root level and child level variables.tf file:
variable "ssh_key" {
type = string
description = "ssh key for EC2 login and checks"
}
My root terraform configuration has this module declared as:
module "ssh_keys" {
source = "./modules/ssh_keys"
}
I first did a terraform init -upgrade on my root level. Then ran terraform refresh and got hit by the following error.
Error: Missing required argument
on first_terraform.tf line 69, in module "ssh_keys":
69: module "ssh_keys" {
The argument "ssh_key" is required, but no definition was found.
Just for reference, line 69 in my root level configuration is where the module declaration has been made. I don't know what I have done wrong here. It seems I have all the variables declared, so am I missing some relationship between root/child module variable passing etc.?
Any help is appreciated! Thanks
I Think I know what I did wrong.
Terraform Modules - as per the documentation requires parents to pass on variables as part of invocation. For example:
module "foo" {
source = "./modules/foo"
var1 = value
var2 = value
}
The above var1, var2 can come from either auto.tfvars file, environment variables (recommended) or even command line -var-file calls. In fact, this is what Terraform calls "Calling a Child Module" here
Once I did that, everything worked like a charm! I hope I did find the correct way of doing things.

Terraform modules: correct references of variables?

I'm writing a terraform script to create an EKS cluster with its worker nodes on AWS. First time doing it so I'm a bit confused.
Here is the folder organisation:
├─── Int AWS Account
│ ├─── variables.tf
│ ├─── eks-cluster.tf (refers the modules)
│ ├─── others
│
├─── Prod AWS Account
│ ├─── (will be the same than Int with different settings in variables)
│
├─── ReadMe.md
│
├─── data sources
│
├─── Modules
│ ├─── cluster.tf
│ ├─── worker-nodes.tf
│ ├─── worker-nodes-sg.tf
I am a bit confused regarding how to use and pass variables. Right now, what I'm doing is that I refer to ${var.name} in the module folder, in the eks-cluster.tf, I either put a direct value name = blabla (mostly avoiding it), or refer to the variable again and have a variable file in the account folder.
Is that correct?
I'm not sure if I get your question correctly but in general you would want to keep your module files with variables only, as modules are intended to be generic so you can easily include them in different environments.
When including the module in eks_cluster_int.tf or eks_cluster_prod.tf you would then pass the values for all variables defined in the module itself. This way you can use the environment specific values in the same module.
module "cluster" {
source = "..."
var1 = value1 # directly passing value
var2 = ${var.int_specific_var} # can be defined in variables.tf of environment
...
}
Does this answer your question?

how do you write text on the status line with the filename, row and col number with vimscript?

Is there a way to programmatically write on the bar below vim windows? I'm referring to the bar which displays the filename, cursor row + column, and the percentage of the document above the bottom of the window.
It is called the status line.
You can get more information by typing :help statusline.
This is the one I used which includes line and column at the bottom right.
set statusline=%f%m%r%h\ [%L]\ [%{&ff}]\ %y%=[%p%%]\ [line:%05l,col:%02v]
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ └─ column number
│ │ │ │ │ │ │ │ └─── line number
│ │ │ │ │ │ │ └── percentage in file
│ │ │ │ │ │ └── file type
│ │ │ │ │ └── file format (dos/unix)
│ │ │ │ └── total number of line in file
│ │ │ └── help flag
│ │ └── read only flag
│ └── modified flag : [+] if modified, [-] if not modifiable
└── relative`
The rendering is not ideal but the options, which are starting with the %sign, are described from left to right as you go down. They are all described in help.
This is a pretty static configuration, if you are willing to use a vim-plugin, there are some like vim-airline that provides more advanced features like git integration.
The information in that bar is set in the option statusline. You can set this from within a script by using let &statusline = just as you would any other vim option.
See :help statusline for more information.
This is my take on this problem.
I set laststatus to turn off the "dedicated" status line and just use the command line area for the status (using rulerformat instead of statusline) if there's only one window.
set laststatus=1
set statusline=%F\ %(%w%h%r%m%)%=%2v:%4l/%4L\ 0x%02B
set rulerformat=%25(%w%h%r%<%m%=%2v:%4l/%4L\ 0x%02B%)
The status line displays the filename (with path) then a space and puts optional indicators for [Preview], [help], [RO], and [+] (if the file is modified) depending on the file status. The single-window version leaves out the filename. In both, I then pad with spaces so the rest is right-justified, put two characters for the cursor column, then list the line number and total number of lines then the hex ASCII code for the character under the cursor.
There are a bunch of interesting examples in the help file, as others have said, check out :help statusline.

Resources