Evaluate variable in Jenkinsfile - single quotes within single quotes - jenkins

I am executing the following in a Jenkinsfile:
sh('''
terraform apply 'var some_list=["foo","bar"]'
''')
Now, I would like to place ["foo","bar"] in a variable and feed that to terraform instead, so I do:
sh('''
export MYVAR=["foo","bar"]
terraform apply 'var some_list=${MYVAR}'
''')
This however, does not work. ${MYVAR} is interpreted as a literal string instead of evaluating it as a variable.
I could do this:
sh('''
export MYVAR=["foo","bar"]
terraform apply var some_list=${MYVAR}
''')
In this case, ${MYVAR} is correctly intepreted, but then Terraform has trouble interpreting the parameter as a list, so the single quotes are needed.
One could perhaps use double quotes in stead , i.e. sh("""...""") and use Groovy evaluation, but I have several other variables where exactly the opposite problem happens. What I am really looking for is a way to use single quotes within single quotes and have the variable still be evaluated.
Does anyone know how I could achieve this?
EDIT:
By the way terraform apply 'var some_list=${MYVAR}', terraform apply 'var some_list=\${MYVAR}' and terraform apply \'var some_list=${MYVAR}\' all give the exact same result.

So, after more trial and error, I finally found that this will work:
sh('''
export MYVAR=["foo","bar"]
terraform apply 'var some_list='${MYVAR}''
''')
i.e. I have to close the inner single quotes before ${MYVAR} and open them again directly thereafter

Related

Using an environment variable as a map for common tags in a locals block

I've run into a specific problem while trying to automate a tagging process in terraform. I've set an environment variable that is essentially a list of all the tags we'd be using for all resources provisioned in the apply. It looks like this...
export TF_VAR_taglist='{JiraEpic = "ETOS-56","AssignedResearcherPri" = "Isaac",AssignedResearcherSec = "Matt"}'
After setting the environment variable I added a variable called "taglist" in the variables.tf file that grabs the aforementioned environment variable. It looks like this...
variable "taglist"{}
Lastly, I have another locals.tf file where i set a common_tags variable. Like so...
locals { common_tags ="${var.taglist}" }
When i terraform apply, the build fails while trying to map the tags properly. This is the error i receive...
Error: Incorrect attribute value type
on kube_master_worker_nodes_ec2.tf line 9, in resource "aws_instance" "master":
9: tags = local.common_tags
|----------------
| local.common_tags is "{JiraEpic = \"ETOS-56\",AssignedResearcherPri = \"Isaac \",AssignedResearcherSec = \"Matt\"}"
Inappropriate value for attribute "tags": map of string required.
I then decided to define the type of the variable as map(string in the variables.tf file like this
variable "taglist"{ type = map(string) }
I had hoped that this would allow terraform to recognize this variable as a map of strings and not just a string literal, but I was wrong, and these are the errors I get when that definition is applied.
Error: Missing attribute separator
on <value for var.taglist> line 1:
(source code not available)
Expected a newline or comma to mark the beginning of the next attribute.
Error: No value for required variable
on variables.tf line 11:
11: variable "taglist"{
The root module input variable "taglist" is not set, and has no default value.
Use a -var or -var-file command line argument to provide a value for this
variable.
I'm really stuck on this, and I feel like I'm close. Can anyone provide some insight into this and how I should go about solving it?
I want to first thank Martin Atkins for giving me the idea of using colons instead of equal signs in my environment variable, because that was the ONLY issue. The variable was not properly represented as a JSON object so terraform was interpreting it as a string.
I changed
export TF_VAR_taglist='{JiraEpic = "ETOS-56","AssignedResearcherPri" = "Isaac",AssignedResearcherSec = "Matt"}'
to this
export TF_VAR_taglist='{"JiraEpic":"ETOS-56","AssignedResearcherPri":"Isaac", "AssignedResearcherSec":"Matt"}'
The build purrs like a kitten on catnip now.
Terraform uses the type constraint of a variable to decide how to interpret a string representation of its value. By default, Terraform will assume the value expects a primitive type such as a string or number, because that's the most typical case for variables set via the command line or environment variables.
Since your tag list is a list you need Terraform to interpret it as a map expression rather than as a string. You can tell Terraform to do that by telling Terraform which type of value you expect:
variable "taglist" {
type = map(string)
}
You can read more about this in the Terraform documentation section Complex-typed Values.
You then need to make sure that the value in the environment variable is a valid object expression in order to avoid a syntax error. If you're setting the environment variable from the shell command line then you need to be mindful of escaping/quoting to ensure that Terraform will see the value with all of the quotes intact, and without any extra metacharacters.
The result is often hard to read clearly, which is why the Terraform documentation recommends using a .tfvars file to set complex-typed variables, instead of the -var command line option or environment variables. However, since you are using automation you might find it easier to generate a .tfvars.json file instead, which uses standard JSON format and is therefore easier to generate using JSON libraries available in most programming languages. Here's the .tfvars.json equivalent of the value you showed in your question:
{
"taglist": {
"JiraEpic": "ETOS-56",
"AssignedResearcherPri": "Isaac",
"AssignedResearcherSec": "Matt"
}
}
Note that subjectively I'd find it pretty confusing to have a variable whose name ends in list when it actually expects a map. A more typical name for this variable would be just tags, though if it's useful to mention its type in order to distinguish it from other variables then I'd suggest tag_map instead, to make it less confusing.

Injecting variable from jenkins into jenkins pipeline

I am using a password parameter option in jenkins pipeline job where i store a password and need to inject that into the environment of jenkins file
Here is the part of the jenkins file where i am trying to inject this PASS
pipeline {
agent any
environment {
USER= 'abcd'
PW= '${params.PASS}'
}
stages {
stage('staring tests') {
When i try echo-ing $PW, it just echoes ${params.PASS}.
Any pointers will be appreciated!!
In Groovy Strings are single quotes. They cannot be interpolated with variables. You would need to concatenate strings and values. i.e. PW='pass' + myVar
GStrings are double quotes. http://docs.groovy-lang.org/latest/html/api/groovy/lang/GString.html
So you would need to change it to PW="${params.PASS}" and this would interpolate the variable into the string.
However since your not doing any interpolation in that example, you don't need to use GStrings either. Whereever you need access to that value just call it directly echo params.PASS
You should not put a 'params' value into an environment variable. It won't work for you. The environment sections initialize only string variables, therefore, it initializes your PW with a pure string of ${params.PASS} since it does no 'calculations' for it.
Instead, in your pipeline, just use the params.PASS directly in your code.

Jenkins pass variable into groovy script

Hi I need to pass a variable from select into the groovy script and I haven't a clue how to do it in variable bindings, anyone has an idea how to do it?
I tried with:
version=version
version=$version
version=${version}
version="${version}"
If you are going to use ${ ... } Notation you should enclose it double quotes, i.e.:
versionVar = "${version}"
The other think that keeps bothering me is that you are using the same variable name. I haven't tried but I think that using the same name you could are trying to use the same variable.
Where is the 'version' variable came from?
If you are trying to use Environment variables, then you should try like,
version = env.version

Using git branch in environment variable in Jenkinsfile

I would like to customize one of environment variable depending on branch that is being build.
environment {
CUSTOM_ENV='xyz_${GIT_BRANCH}'
}
I'd like to get CUSTOM_ENV=xyz_dev for origin/dev and CUSTOM_ENV=xyz_master for origin/master. Not sure if its important, but its multibranch project in Jenkins.
I tried things like xyz_${GIT_BRANCH} or xyz_env.GIT_BRANCH, but none of this worked out.
If your shell happens to be compatible with ksh or bash then you can use the variable-expansion modifier ## to discard everything up to and including the final / character, leaving get just the part of ${GIT_BRANCH} that comes after that /. That would look like:
CUSTOM_ENV="xyz_${GIT_BRANCH##*/}"
Note the double-quotes " rather than the single-quotes ' you used in your question. Single-quotes prevent the evaluation of variables inside the quoted string, and that's definitely not what you want in this case.
If your shell does not understand the ## modifier then you'll have to use something like sed to get just the last part of ${GIT_BRANCH}. That would look like this:
CUSTOM_ENV="xyz_$(echo ${GIT_BRANCH} | sed -e 's#.*/##')"
When you are doing a substitution in jenkinsfile for a variable. It should always be in "". From environment directive , I guess you are using pipelines. So, you can leverage the groovy syntax to achieve string manipulation.
Something like,
environment {
GIT_BRANCH = 'orgin/master'.split('/')[1]
CUSTOM_ENV="xyz_${GIT_BRANCH}"
}

Using "$" in Groovy

I see { } are used for closures, and then I believe when a $ is put in front of braces, it is simply doing a variable substitution within a string. I can't find the documentation on how the $ works in the reference ... hard to search on it unfortunately, and the Groovy String documentation is lacking in introducing this. Can you please point me to the documentation and/or explain the "$" operator in Groovy -- how all it can be used? Does Grails extend it at all beyond Groovy?
In a GString (groovy string), any valid Groovy expression can be enclosed in the ${...} including method calls etc.
This is detailed in the following page.
Grails does not extend the usage of $ beyond Groovy. Here are two practical usages of $
String Interpolation
Within a GString you can use $ without {} to evaluate a property path, e.g.
def date = new Date()
println "The time is $date.time"
If you want to evaluate an expression which is more complex than a property path, you must use ${}, e.g.
println "The time is ${new Date().getTime()}"
Dynamic Code Execution
Dynamically accessing a property
def prop = "time"
new Date()."$prop"
Dynamically invoking a method
def prop = "toString"
new Date()."$prop"()
As pointed out in the comments this is really just a special case of string interpolation, because the following is also valid
new Date().'toString'()
$ is not an operator in Groovy. In string substitution it identifies variables within the string - there's no magic there. It's a common format used for inline variables in many template and programming languages.
All special Groovy operators are listed here: http://groovy-lang.org/operators.html
Work in side Jenkins File in pipeline
#!/usr/bin/env groovy
node{
stage ('print'){
def DestPath="D\$\\"
println("DestPath:${DestPath}")
}
}

Resources