How to automate Terraform to run it at the spawn of an instance

76 views
Skip to first unread message

francesco spinelli

unread,
May 19, 2018, 10:06:12 AM5/19/18
to Terraform
Hi all!


First of all I will describe what I want to achieve and then ask you some questions regarding how  can I  do it.

Environment: I have a VPC and some instances created via the Amazon Console. Then I want to create a new instance inside that VPC, always through the Amazon console, install a software router on it and use terraform  on it to automatize some functions ( i.e create route tables so, for example, all the traffic goes through the software router interface).

Basically the role of Terraform should be that every time I start this software router  Terraform should allow  me to modify or adds route tables.

I know I can do these things easily via Amazon console, but I would like to centralize things on this software router.

To have this process done I have divided it in three part:

1) get through import command the VPC ids, subnets ids etc ( everything useful for my purpouse that have not been created via terraform)

2) write a terraform script  in which there are all the commands of the things I would like to change.

3) automatize it, letting this steps run  everytime the software router is started.


Hence, now I have several questions:

1) It's not very clear to me  how the process of Terraform automation works. Is it possible to automate Terraform in order that it executes commands after the starting of the software router instance? If yes, How can it be done? (feel free to share me useful links)

2) in the import command it's sounds to me that I have to put manually the IDs of the things I want to import in Terraform and it's not possible to automatize this process. Is that true or there ls a way to get those IDs automatically?

3) This was my idea of how getting the thing I want done. Do you have any suggestion regarding any improvements?

laxman Singh Rathore

unread,
May 19, 2018, 10:30:36 AM5/19/18
to terrafo...@googlegroups.com
Hi Francesco,

As per my understanding you want to import you existing VPC resource in you terraform state file.

1. through terraform import command that import your vpc resource in terraform state file.  after import terraform will track  manually  created resource.

2. why you want to create resource through console any specific reason ?  if you create resource through terraform this  step will omit resource import and automatically update your state file. also omit repeatable task through local and remote exec or through any provisioning tool.

3 if you want to update some parameter related to resource like RDS, DynamoDB, KMS  S3 etcthis infoamtion will help you in configura. you just need to update resource tf file and than execute plan, and apply command.

4. always use terraform plan -out plan.out  # to verify what changes will be apply and sate for roll back of resouce.

Hope this information help you in further configuration.

Regards,
Laxman Singh


--
This mailing list is governed under the HashiCorp Community Guidelines - https://www.hashicorp.com/community-guidelines.html. Behavior in violation of those guidelines may result in your removal from this mailing list.
 
GitHub Issues: https://github.com/hashicorp/terraform/issues
IRC: #terraform-tool on Freenode
---
You received this message because you are subscribed to the Google Groups "Terraform" group.
To unsubscribe from this group and stop receiving emails from it, send an email to terraform-tool+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/terraform-tool/2dc2c264-2c6a-4a19-983a-9d49c096af71%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Thanks & Regards
Laxman Singh Mandloi

Message has been deleted
Message has been deleted

ric...@groupon.com

unread,
May 24, 2018, 1:29:00 AM5/24/18
to Terraform
> 1) get through import command the VPC ids, subnets ids etc ( everything useful for my purpouse that have not been created via terraform)

You might want to look into using data sources instead of imports. For instance, tag your VPC in a certain way, and instead of importing it, reference it as:

data "aws_vpc" "my_vpc" {
  filter {
    name = "tag:your_tag_key"
    values = ["your_tag_value"]
  }
}

For the rest, it sounds like that's all dependent on how you want to invoke Terraform. If you're trying to say "I want to create an instance through the AWS console, and then I want to run Terraform on it afterwards" it seems like you can just do that manually. If you mean "I want to create an instance through the AWS console and have Terraform somehow automatically be invoked" then you probably have some building of your own to do. If I was doing this, the "easy" thing to do would be setup a script that does the software router install, then installs Terraform, pulls down your configs, and then runs Terraform against localhost. You could either bake that script (and/or the dependencies) into your AMI, or embed the steps in a UserData / cloud-init setup.

francesco spinelli

unread,
May 24, 2018, 11:31:28 AM5/24/18
to Terraform
Thanks for your answer!

your solution with the data sources is great! 

By the way, do you know if it's possible to retrieve those IDs (vpc, subnet..) automatically from the console? In other terms: in your solutions it seems to me that I have to write manually which are the tags of the VPC to get its ID. My question is if there is a way to automatize this step.

Bill Anderson

unread,
May 25, 2018, 11:44:26 AM5/25/18
to Terraform


On Saturday, May 19, 2018 at 9:06:12 AM UTC-5, francesco spinelli wrote:
Hi all!


First of all I will describe what I want to achieve and then ask you some questions regarding how  can I  do it.

Environment: I have a VPC and some instances created via the Amazon Console. Then I want to create a new instance inside that VPC, always through the Amazon console, install a software router on it and use terraform  on it to automatize some functions ( i.e create route tables so, for example, all the traffic goes through the software router interface).

This is the departure point. My first suggestion is to not use the AWS Console for launching it. This one thing makes what you want to do much more difficult than it has to be.
 

Basically the role of Terraform should be that every time I start this software router  Terraform should allow  me to modify or adds route tables.

I know I can do these things easily via Amazon console, but I would like to centralize things on this software router.

To have this process done I have divided it in three part:

1) get through import command the VPC ids, subnets ids etc ( everything useful for my purpouse that have not been created via terraform)

2) write a terraform script  in which there are all the commands of the things I would like to change.

3) automatize it, letting this steps run  everytime the software router is started.
 

Hence, now I have several questions:

1) It's not very clear to me  how the process of Terraform automation works. Is it possible to automate Terraform in order that it executes commands after the starting of the software router instance? If yes, How can it be done? (feel free to share me useful links)

The answer to this is to use Terraform to launch the EC2 instance you're running the software on rather than the Console. Terraform can run commands on the new instance to do what you want done on it, but only when invoked.

Without knowing the details, this is how I would recommend you solve this problem:

1. Create an AMI that has the software installed on it.
2. Write Terraform config (perhaps make it a module) that defines and launches an instance of that AMI, and executes the necessary commands and makes any changes to your AWS resources such as routing tables and security groups.
3. Use Terraform plan/apply to manage the setup.
4. Consider using s3 (or Consul if you have it already) for storing the Terraform state remotely, and put the different resources in different states (https://www.terraform.io/docs/providers/terraform/d/remote_state.html)

As far as importing existing resources, this isn't difficult and if you use Terraform to manage them only needed once. 

For executing commands on the instance, the Terraform bit you are looking for is the remote-exec provisioner (https://www.terraform.io/docs/provisioners/remote-exec.html). 

For example, lets assume a base directory of "terraform". We'll also assume for the example that you're using S3 to store state, using a bucket named "my.terraform.states". Inside the terraform directory create a directory called "networking". Inside the networking directory you store terraform configs for security groups, subnets, VPCs, etc..  Each directory under the terraform has its own remote state as defined in a "backend.tf" file that looks something like this:

terraform {
  backend "s3" {
    key        = "networking"
    encrypt    = true
    bucket     = "my.terraform.states.bucket.name"
    region     = "us-east-1"
  }
}

This will allow you to reference the resources defined at the root and exported herein in other states. In here you could have a "vpc.tf" file which defines your VPC, make sure it matches the existing one precisely. Then you import it as described at https://www.terraform.io/docs/providers/aws/r/vpc.html. Now that it is stored in the state file for networking you can reference it via remote states. You could then follow the same process for subnets, security groups, etc.. Some people like to put each resource type in its own state, but that is up to you.

Once you've translated your existing AWS networking resources into a defined terraform state under "terraform/networking", you can turn your attention to your "router" definition. Assuming you've got an AMI ID properly tagged, you can use a data source to automatically pull the current AMI ID other than coding it into your Terraform config. For details on that, see https://www.terraform.io/docs/providers/aws/d/ami.html. Let us assume you name this state "my_router", placed under "terraform" ("terraform/my_router/"). I prefer to define all of my data sources in "data.tf", so I'd put it in that file.

From there you define your router instance, we'll call it "my_router.tf". In there you use the ec2 instance resource. You use the data source for the AMI ID noted above to pull the AMI Id at plan/apply time, and define a remote state for "terraform/networking" in a "remotes.tf" file to reference what exists in that state. For example it might look like this:

data "terraform_remote_state" "networking" {
  backend = "s3"
  config {
    key        = "networking"
    encrypt    = true
    bucket     = "my.terraform.states.bucket.name"
    region     = "us-east-1"
  }
}

From there you can reference your network resources without hard-coding or additional importing or data filtering via "${data.terraform_remote_state.networking.SOMETHING}" where SOMETHING is the name of what you're after.

Your "my_router" definition might look something like this (https://www.terraform.io/docs/providers/aws/r/instance.html):

resource "aws_instance" "my_router" {
  ami           = "${data.aws_ami.my_router_image.id}"
  instance_type = "t2.micro"
  region = "${data.terraform_remote_state.networking.region}"
  provisioner "remote-exec" {
    inline = [
      "/usr/local/bin/some_script_here.sh}",
    ]
  }
}

Notice we pull the AMI Id from the data source, and the region from our networking state.
The provisioner is an example of executing shell commands on the image when you create the instance. Any alterations to existing network resources can be made via standard Terraform rules, and you can specify the security group(s) to spin the instance up with in Terraform automatically as you can reference your remote states to get current data.

Taking the time to import your existing resources once and then reference them via state will save you a lot of complexity and headache later on, and doesn't take much time at all. A critical difference between that and data sources is that by defining them as Terraform managed resources you'll benefit from terraform's dependency tree. Using a data source doesn't let you say "this resource needs that one" - instead if the resource doesn't exist the data source query says it didn't find a match and it won't necessarily show in the plan depending on what it is and where.

One final note on the my_router instance is on configuration files. If you need to configure the software at launch time using AWS resource data, and the software uses a config file for that, you can use the File provisioner (https://www.terraform.io/docs/provisioners/file.html) and possibly a template_file (https://www.terraform.io/docs/providers/template/d/file.html) to create that file using resources defined in your network state and/or data sources. For example, if you needed to modify an AWS route_table or a Route53 record, you could do that.

Anyway, I hope that gets you down the path you need. 

Cheers,
Bill


Reply all
Reply to author
Forward
0 new messages