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

Passing list variables from TerraTest go files to Terraform #200

Closed
MichaelSmyth0184 opened this issue Nov 27, 2018 · 11 comments
Closed

Passing list variables from TerraTest go files to Terraform #200

MichaelSmyth0184 opened this issue Nov 27, 2018 · 11 comments
Labels

Comments

@MichaelSmyth0184
Copy link

MichaelSmyth0184 commented Nov 27, 2018

I have currently been using TerraTest for testing my Terraform IAC.
Works fine, but in none of the examples I can see how we would pass a list of values, lets say subnet CIDR blocks or a list of Security group ID's from our Go Terratest file to Terraform, as those values expect a list variable type.

Could you also share any information around the httpHelper script? I have been using your examples to base my test files on, but cannot seem get my script working on my own applications such as Jenkins running on port 8080 which was launched using a gold AMI in aws.

I can navigate to the Application on my browser, and curl information from it from my machine where I am running the tests, but still does not seem to work.

There is also logs when I run the test showing the HTML layout, but I think it might be something to do with the InstanceText in which I am passing to the test which makes it fail.

http_helper.HttpGetWithRetry(t, instanceURL, 200, instanceText, maxRetries, timeBetweenRetries)

Thanks,

Michael

@brikis98
Copy link
Member

Works fine, but in none of the examples I can see how we would pass a list of values, lets say subnet CIDR blocks or a list of Security group ID's from our Go Terratest file to Terraform, as those values expect a list variable type.

Just pass a list :)

myList := []string{"foo", "bar", "baz"}

terraformOptions := &terraform.Options{
  // The path to where our Terraform code is located
  TerraformDir: "../my-module",

  // Variables to pass to our Terraform code using -var options
  Vars: map[string]interface{}{
    "my_list": myList,
  },
}

I have been using your examples to base my test files on, but cannot seem get my script working on my own applications such as Jenkins running on port 8080 which was launched using a gold AMI in aws.

What error do you get? Can you share your log output?

@MichaelSmyth0184
Copy link
Author

MichaelSmyth0184 commented Nov 28, 2018

Hi,

I think it might be something to do with the body of the http GET as I am trying to test if my sonarqube is up and working and I do get a Response status: 200 along with all the HTML of sonar, but the test stills fails.

TestPrestaHttpResponse``` 2018-11-28T11:44:55Z retry.go:69: HTTP GET to URL
http://3.121.38.141:9000
TestPrestaHttpResponse 2018-11-28T11:44:55Z
http_helper.go:27: Making an HTTP GET call to URL
http://3.121.38.141:9000
TestPrestaHttpResponse
2018-11-28T11:44:55Z
retry.go:81:
HTTP GET to URL http://3.121.38.141:9000
returned an error: Validation failed for URL http://3.121.38.141:9000. Response staus: 200. Response body: <meta http-equiv="content-type" content="text/html;
charset=UTF-8charset="UTF-8"/>

The example on the Terratest github with the basic HTML webpage saying "Hello, World!" works grand as it has a basic with some text! But for other applications where the HTML has alot going on I cannot seem to get the test to Pass.

@brikis98
Copy link
Member

If you need custom validation, use HttpGetWithRetryWithCustomValidation instead. It lets you pass in a function to check the status code and body of the response any way you want (e.g., via strings.Contains instead of simple equality).

@MichaelSmyth0184
Copy link
Author

@brikis98 Thank you, got both working now!!!

Many thanks,

Michael

@brikis98
Copy link
Member

Great to hear!

@MatthiasScholz
Copy link

MatthiasScholz commented Jan 4, 2021

Sorry for opening up this conversation, but just for completeness it seems this issue is correlated with:

Just recently I ran into this issue trying to write a test using a list as input. Maybe the connection is helpful for others.

@rishabhanand26
Copy link

i tried passing a list to my variable like this :

Vars: map[string]interface{}{
			"subnet_ids": terraform.Output(t, vpcOpts, "subnet_ids"), // where my subnet is the list received from the output of other module
		},

while this been implemented, i still face issue as when it passes the subnet_ids as the variable it is treated as a string of single unit, for ex. "[subnet-XXXX subnet-YYYY]" is a string and not a list while the output from the module was a list and not a string.

is there any way out to take the subnet value from the output as a list and not as string .

@brikis98
Copy link
Member

Most likely, Terratest is passing the value as a list, but you need to set the type on the subnet_ids input variable to list(string) so that Terraform knows to parse it as a list.

@dimaunx
Copy link

dimaunx commented Mar 2, 2021

I'm am having similar issue as @rishabhanand26 ,

The destination terraform module variable is configured as list(string):

variable "private_subnets" {
  description = "Cluster private subnets"
  type        = list(string)
}

I pass the variable in a test stage as follows:

"private_subnets":  terraform.Output(t, awsNetworkOpts, "private_subnets")

Getting an error:

 Error Trace:	apply.go:15
        	        aws_infra_test.go:98
        	        test_structure.go:25
        	        aws_infra_test.go:51
 Error:      	Received unexpected error:
        	     FatalError{Underlying: error while running command: exit status 1; 
        	     Error: Missing item separator
        	     
        	       on <value for var.private_subnets> line 1:
        	       (source code not available)
        	     
        	     Expected a comma to mark the beginning of the next item.
        	     
        	     
        	     Error: No value for required variable
        	     
        	       on variables.tf line 14:
        	       14: variable "private_subnets" {
        	     
        	     The root module input variable "private_subnets" is not set, and has no
        	     default value. Use a -var or -var-file command line argument to provide a
        	     value for this variable.
        	     }

The actual output from the source module looks as follows:
Outputs:
private_subnets = [
"subnet-xxx",
"subnet-xxx",
]

The var that is passed to the destination module is -var private_subnets=[subnet-xxx subnet-xxx]
Seems like the output always is passed as string, if i pass a list it works.

For me the workaround was to use the https://github.com/Jeffail/gabs library.

awsNetworkOpts := test_structure.LoadTerraformOptions(t, awsNetworkModulePath)
jsonParsed, err := gabs.ParseJSON([]byte(terraform.OutputJson(t, awsNetworkOpts, "")))
if err != nil {
	t.Error(err)
}

obj, err := jsonParsed.JSONPointer("/private_subnets/value")
if err != nil {
	t.Error(err)
}

var privateSubnets []string
for _, child := range obj.Children() {
	privateSubnets = append(privateSubnets, child.Data().(string))
}

vars := map[string]interface{}{"private_subnets": privateSubnets}

To view the output in json format just fmt.Println(jsonParsed).

Hope it helps someone.

@brikis98
Copy link
Member

brikis98 commented Mar 8, 2021

I pass the variable in a test stage as follows:

"private_subnets":  terraform.Output(t, awsNetworkOpts, "private_subnets")

That's your problem right there: terraform.Output returns a string. Use terraform.OutputList instead.

@dimaunx
Copy link

dimaunx commented Mar 8, 2021

I pass the variable in a test stage as follows:

"private_subnets":  terraform.Output(t, awsNetworkOpts, "private_subnets")

That's your problem right there: terraform.Output returns a string. Use terraform.OutputList instead.

Thank you very much!

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

No branches or pull requests

5 participants