Contents

Terraform copy/run scripts, and execute Commands

Run native OS commands and copy/run scripts

Website Visitors:

With terraform you can also run any native commands related to the operating system, or copy files from your local machine and run them. In this tutorial, we’ll show you all the ways on how to run native OS commands, copy and run scripts from your local machine to your instance.

Running commands

After the instance is deployed, you may want to run some commands, for example, to install a software on the instance. This is possible through user_data parameter in Terraform. Commands/script that you use in user_data parameter are like init scripts in AWS. They are executed at instance launch time. Let us show you some examples on how to use user_data parameter.

Using commands

With user_data parameter use all the commands in EOF block as shown below. After the instance is deployed, all the commands will be executed. In the below example, apache2 will be installed. If you open the public ip of your instance, it will show a web page which says “Created by Terraform”.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
resource "aws_instance" "TestInstance" {
  ami                    = "ami-xxxxxxxxxxx"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.testsubnet.id
  vpc_security_group_ids = [aws_security_group.testsecuritygroup.id]
  key_name               = var.aws_ssh_key_name
  availability_zone = data.aws_availability_zones.available.names[0]
  user_data = <<-EOF
    #! /bin/bash
    sudo apt-get update
    sudo apt-get install -y apache2
    sudo systemctl start apache2
    sudo systemctl enable apache2
    echo "<h1>Created by Terraform</h1>" | sudo tee /var/www/html/index.html
  EOF
}

Using script file

In the same folder where you have terraform’s tf script file, create a file called “installapache.sh” and copy below commands into it.

1
2
3
4
5
6
 #! /bin/bash
 sudo apt-get update
 sudo apt-get install -y apache2
 sudo systemctl start apache2
 sudo systemctl enable apache2
 echo "<h1>Created by Terraform</h1>" | sudo tee /var/www/html/index.html

Next, in your terraform’s tf script file, enter the code as shown below in user_data parameter. This will run the script file on the instance after it is deployed.

1
2
3
4
5
6
7
8
9
resource "aws_instance" "TestInstance" {
  ami                    = "ami-xxxxxxxxxxx"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.testsubnet.id
  vpc_security_group_ids = [aws_security_group.testsecuritygroup.id]
  key_name               = var.aws_ssh_key_name
  availability_zone = data.aws_availability_zones.available.names[0]
  user_data =  "${file("installapache.sh")}"
}

Using template_file

In this type, you have to declare user data template first and then use it when you deploy your instance.

1
2
3
data "template_file" "apache" {
template = "${file("installapache.sh")}"
}

When deploying the instance refer to the data template_file as:

1
2
3
4
5
6
7
8
9
resource "aws_instance" "TestInstance" {
  ami                    = "ami-xxxxxxxxxxx"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.testsubnet.id
  vpc_security_group_ids = [aws_security_group.testsecuritygroup.id]
  key_name               = var.aws_ssh_key_name
  availability_zone = data.aws_availability_zones.available.names[0]
  user_data =  "${data.template_file.apache.rendered}"
}

Make sure to create installapache.sh file in the same directory as you have your terraform files.

Copy file with Terraform

You can copy a script file from your local machine to the instance after it is deployed. You can achieve this with terraform provisioner. Create a script file in the same folder you have all your terraform files and run provisioner as shown below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
resource "aws_instance" "TestInstance" {
  ami                    = "ami-xxxxxxxxxxx"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.testsubnet.id
  vpc_security_group_ids = [aws_security_group.testsecuritygroup.id]
  key_name               = var.aws_ssh_key_name
  availability_zone = data.aws_availability_zones.available.names[0]
  provisioner "file" {
      source      = "apache.sh"
      destination = "/home/ubuntu/installjenkins.sh"

    connection {
      type        = "ssh"
      host        = self.public_ip
      user        = "ubuntu"
      private_key = "${file("KeyPair.pem")}"
    }
  }
}

This will copy apache.sh file from your local machine to your instance’s /home/ubuntu folder and rename it as installapache.sh.

Run script files

After copying a script file into your instance, you want to run it to fully automate the process. For running/executing a script file you should use remote-exec provisioner. The remote-exec provisioner invokes a script on a remote resource after it is created. This can be used to run a configuration management tool, bootstrap into a cluster, etc.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
resource "aws_instance" "TestInstance" {
  ami                    = "ami-xxxxxxxxxxx"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.testsubnet.id
  vpc_security_group_ids = [aws_security_group.testsecuritygroup.id]
  key_name               = var.aws_ssh_key_name
  availability_zone = data.aws_availability_zones.available.names[0]
  provisioner "file" {
      source      = "apache.sh"
      destination = "/home/ubuntu/installapache.sh"

    connection {
      type        = "ssh"
      host        = self.public_ip
      user        = "ubuntu"
      private_key = "${file("KeyPair.pem")}"
    }
  }
}

File provisioner in this script will copy apache.sh file from your local machine to the instance, rename it as installapache.sh.

Run scripts remotely

After copying file to the instance, you want to run the script file. Using remote-exec provisioner you will be able to run scripts. Below code will copy the script, add executable permission to the script and install apache.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
resource "aws_instance" "TestInstance" {
  ami                    = "ami-xxxxxxxxxxx"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.testsubnet.id
  vpc_security_group_ids = [aws_security_group.testsecuritygroup.id]
  key_name               = var.aws_ssh_key_name
  availability_zone = data.aws_availability_zones.available.names[0]
  provisioner "file" {
      source      = "apache.sh"
      destination = "/home/ubuntu/installapache.sh"

    connection {
      type        = "ssh"
      host        = self.public_ip
      user        = "ubuntu"
      private_key = "${file("KeyPair.pem")}"
    }
  }
  provisioner "remote-exec" {
    inline = [
      "chmod +x /home/ubuntu/installapache.sh",
      "sh /home/ubuntu/installapache.sh",
    ]
    connection {
      type        = "ssh"
      host        = self.public_ip
      user        = "ubuntu"
      private_key = "${file("KeyPair.pem")}"
    }
  }
}

Suggested Article

If you’d like to go through Terraform definitions, check it out here or browse other articles on Terraform here.

Conclusion

In this tutorial, we’ve explained how to run native OS commands and copy scripts using Terraform. We’ve also demonstrated examples for all the topics that are discussed. We hope you have learned something new in this article.

Please feel free to share your thoughts about this article in the comments section below.

Your inbox needs more DevOps articles.

Subscribe to get our latest content by email.