Ansible variable from packer script - ansible

I have one variable in ansible script like
- host:{{host}}
I want to send {{host}} variable value from packer script. I want to send {{host}} value using packer build or using packer variable. Is there anyway do it?

Using an ansible provisioner in packer allows you to use both ansible_env_vars and extra_arguments.
See doco: https://www.packer.io/plugins/provisioners/ansible/ansible#configuration-reference
So we generally used extra_arguments to pass in ansible variables over the command line
{
"type": "ansible",
"playbook_file": "./my_playbook}",
"extra_arguments": "-vvv --extra-vars 'host={{user `host`}}"
}

Below a simple example:
...
variable "gitlab_version" {
type = string
default = "15.1.6"
}
...
build {
name = local.build_name
provisioner "ansible" {
...
playbook_file = "./ansible/playbook.yml"
extra_arguments = ["--extra-vars", "gitlab_version=${var.gitlab_version}"]
...
}
}
It works as it's a simple interpolation

Related

How to pass shell variable to ansible playbook command

I have this Jenkins pipeline where I need to run ansiblePlaybook() command with inventory file. Inventory file does contain date (current date) part (my-instance-ips-(mm-dd-yyyy)). Here, I am facing issue in creating currentDate variable and pass into pipeline script
Jenkins File:
pipeline {
agent any
stages {
stage ( 'Executing shell script' ) {
steps {
script {
sh """
currentDate = "\$(date +'%m-%d-%Y')"
inventory_file = "my-instance-ips-{$currentDate}.yml"
ansiblePlaybook (
playbook: 'task.yml',
inventory: $inventory_file,
installation: 'ansible-2.6.5','
-e "DATE = $currentDate")
"""
}
}
}
}
}
Error Message:
groovy.lang.MissingPropertyException: No such property: currentDate for class: groovy.lang.Bindin
Could someone help me out to create current date in pipeline script and the same should pass over to ansible playbook command?
Looks like you are invoking ansible plugin. If that is what you are trying to achive, then your ansible playbook call should not be inside sh step.
You need to get the command's output first then invoke ansible plugin.
import java.time.format.DateTimeFormatter
pipeline {
agent any
stages {
stage ( 'Executing shell script' ) {
steps {
script {
/* currentDate = sh (
script: "date +'%m-%d-%Y'"
returnStatus: true
).trim()
*/
cDate = java.time.LocalDate.now()
currentDate = cDate.format(DateTimeFormatter.ofPattern("MM-dd-yyyy"))
inventory_file = "my-instance-ips-${currentDate}.yml"
println inventory_file
ansiblePlaybook ([
playbook: 'task.yml',
// credentialsId: 'xxxx',
disableHostKeyChecking: true,
inventory: "${inventory_file}",
extraVars: [
DATE: "${currentDate}"
]
])
}
}
}
}
}

How to run ansible script from terraform

Hi below is my requirement.
Using terraform script i create a linux vm and post that using ansible play book i install some softwares. so i have this scripts separately with me and it is working fine.
What i want to do is that as soon as the terraform script creates the vm i want to invoke ansible script from the terraform script and install the softwares from ansible script.
I tried the below code but it did not work
provisioner "remote-exec" {
inline = ["sudo dnf -y install python"]
connection {
type = "ssh"
user = "fedora"
private_key = "${file(var.ssh_key_private)}"
}
}
provisioner "local-exec" {
command = "ansible-playbook -u fedora -i '${self.public_ip},' --private-key ${var.ssh_key_private} provision.yml"
}
So here i am not sure how the ansible get installed in the vm currently i am doing it manually and how thisansible script will get invoked from terraform
Error: Unknown root level key: provisioner
provisioner can only be used within a resource, e.g.:
resource "aws_instance" "web" {
# ...
provisioner "remote-exec" {
inline = ["sudo dnf -y install python"]
connection {
type = "ssh"
user = "fedora"
private_key = "${file(var.ssh_key_private)}"
}
}
provisioner "local-exec" {
command = "ansible-playbook -u fedora -i '${self.public_ip},' --private-key ${var.ssh_key_private} provision.yml"
}
}

Terraform template_cloudinit_config multiple part execution order is wrong

I am using the terraform to build my ec2-instances as part of instance bootstrap, added cloud-init config to run multiple userdata scripts. but the content_type = "text/x-shellscript" always executed first. I verified the cat /var/log/cloud-init-output.log file. it shows the shell script is invoked first. How do I config the shell script to run at last?
data "template_cloudinit_config" "myapp_cloudinit_config" {
gzip = false
base64_encode = false
# Main cloud-config configuration file.
part {
content_type = "text/cloud-config"
content = "${data.template_file.base_bootstrap_file.rendered}"
merge_type = "list(append)+dict(recurse_array)+str()"
}
part {
content_type = "text/cloud-config"
content = "${module.template_file_appsec_init.appsec_user_data_rendered}"
merge_type = "list(append)+dict(recurse_array)+str()"
}
part {
content_type = "text/x-shellscript"
content = "${module.template_file_beat_init.beat_user_data_rendered}"
}
}
Shell script looks like below
module " template_file_beat_init" {
source = "url" #the source url contains the zip file which includes the below shell script
}
#!/bin/sh
deploy_the_app() {
//invoke ansible playbook execution
}
deploy_the_app
Cloud provider: AWS
OS : RHEL 8.3
cloud-init --version: /usr/bin/cloud-init 19.4
Terraform v0.11.8

How can I run a shell script on multiple VMWare vm's created by terraform module?

I am using this module to spin up multiple vm's on my vmware cluster, https://registry.terraform.io/modules/Terraform-VMWare-Modules/vm/vsphere/1.6.0, and I want to run a shell script on all of the vms after using a null resource. With what i currently have, it complains that the host was not given a string, which makes sense. Here is my null resource:
# main.tf
module "jenkins-linuxvm-centos7" {
source = "Terraform-VMWare-Modules/vm/vsphere"
...
}
resource "null_resource" "vm" {
triggers = {
vm_ips = join(",", module.jenkins-linuxvm-centos7.Linux-ip)
}
# export TF_VAR_root_password=<pass>
connection {
type = "ssh"
host = module.jenkins-linuxvm-centos7.Linux-ip
user = "root"
password = var.vm_root_password
port = "22"
agent = false
}
provisioner "file" {
source = "resize_disk.sh"
destination = "/tmp/resize_disk.sh"
}
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/resize_disk.sh",
"/tmp/resize_disk.sh"
]
}
}
Do I need to use a dynamic block somehow? Or how can I modify host = module.jenkins-linuxvm-centos7.Linux-ip to include all the hosts I want to run it on?
You have to run it in a For_Each loop... Below is an example code where i am looping against the sql_var map variable. you will have to do it against the output of IPs --> module.jenkins-linuxvm-centos7.Linux-ip... you will be able to reference the IP of each machine as something like each.value i guess. I dont know how your output looks like, so guessing. If you are new to loops, here is one nice tuto.
https://blog.boltops.com/2020/10/04/terraform-hcl-loops-with-count-and-for-each
resource "null_resource" "instance" {
for_each = var.sql_var
provisioner "local-exec" {
command = "echo ${each.key} >> hello.txt"
}
}

Terraform execute script before lambda creation

I have a terraform configuration that correctly creates a lambda function on aws with a zip file provided.
My problem is that I always have to package the lambda first (I use serverless package method for this), so I would like to execute a script that package my function and move the zip to the right directory before terraform creates the lambda function.
Is that possible? Maybe using a combination of null_resource and local-exec?
You already proposed the best answer :)
When you add a depends_on = ["null_resource.serverless_execution"] to your lambda resource, you can ensure, that packaging will be done before uploading the zip file.
Example:
resource "null_resource" "serverless_execution" {
provisioner "local-exec" {
command = "serverless package ..."
}
}
resource "aws_lambda_function" "update_lambda" {
depends_on = ["null_resource.serverless_execution"]
filename = "${path.module}/path/to/package.zip"
[...]
}
https://www.terraform.io/docs/provisioners/local-exec.html
The answer is already given, but I was looking for a way to install NPM modules on the fly, zip and then deploy Lambda function along with timeout if your lambda function size is large. So here is my finding may help someone else.
#Install NPM module before creating ZIP
resource "null_resource" "npm" {
provisioner "local-exec" {
command = "cd ../lambda-functions/loadbalancer-to-es/ && npm install --prod=only"
}
}
# Zip the Lamda function on the fly
data "archive_file" "source" {
type = "zip"
source_dir = "../lambda-functions/loadbalancer-to-es"
output_path = "../lambda-functions/loadbalancer-to-es.zip"
depends_on = ["null_resource.npm"]
}
# Created AWS Lamdba Function: Memory Size, NodeJS version, handler, endpoint, doctype and environment settings
resource "aws_lambda_function" "elb_logs_to_elasticsearch" {
filename = "${data.archive_file.source.output_path}"
function_name = "someprefix-alb-logs-to-elk"
description = "elb-logs-to-elasticsearch"
memory_size = 1024
timeout = 900
timeouts {
create = "30m"
}
runtime = "nodejs8.10"
role = "${aws_iam_role.role.arn}"
source_code_hash = "${base64sha256(data.archive_file.source.output_path)}"
handler = "index.handler"
# source_code_hash = "${base64sha256(file("/elb-logs-to-elasticsearch.zip"))}"
environment {
variables = {
ELK_ENDPOINT = "someprefix-elk.dns.co"
ELK_INDEX = "test-web-server-"
ELK_REGION = "us-west-2"
ELK_DOCKTYPE = "elb-access-logs"
}
}
}

Resources