How to check NIC is created before creating machine in terraform script - terraform

I am running Jenkins jobs to create a Azure instance and that will run terraform script to do this task.The terraform script will create NIC first and later it will create VM.Sometimes the NIC creation is taking too long in Azure environment and Vm creation steps are getting executed before NIC fully created.Is there any way so that Script should go to next step only when NIC creation is done fully.Can someone help?

What you will need to do is define the NIC as an explicit dependency on the VM in the Terraform. There are odd cases when you have to do it that way. So on the VM you just need to add the depends on property and the resource. If the resource is created outside of terraform you may have to use a datasource to load it in.
resource "azurerm_virtual_machine" "main" {
name = "${var.prefix}-vm"
depends_on = [azurerm_network_interface.main]
}
The docs:
https://www.terraform.io/docs/configuration/resources.html#depends_on-explicit-resource-dependencies

Related

Is Terraform Destroying Manually created resources?

I have created some resources in Azure using Terraform such as VNETS, VMs, NSGs etc. Let's assume if I create another VM in the same VNET which was created by Terraform, I want to know if I rerun the Terraform script, will the manually created VM gets destroyed since the manually created VM is not in the state file?
No, Terraform does not interfere with resources that are created outside of terraform. It only manages resources that are included in its state file.
However, if you make manual changes to resources that you created through terraform(for example VNET in your case), terraform would reset them to what is declared in terraform code on the next run/execution.

Destroying Rancher2_Cluster with terraform is failing due to aks resources in "deleting" state

We're facing an issue in terraform in combination with Rancher2 and AKS. We're using terraform to deploy a rancher2_cluster with an aks config also creating a new subnet.
while trying to destroy everything, we run into an issue, where the azurerm_subnet is still in use by the cluster node in azure. therefore it can't be deleted.
Message="Subnet subnet_name is in use by /subscriptions/xxx-xx-xx-xx-xxx/resourceGroups/MC_cluster-resource-group-name_location/providers/Microsoft.Network/networkInterfaces/aks-node-id-nic-0/ipConfigurations/ipconfig1 and cannot be deleted. In order to delete the subnet, delete all the resources within the subnet. See aka.ms/deletesubnet." Details=[]
If we run terraform destroy, after we checked that everything related to the aks cluster is destroyed on the azure side, the subnet gets deleted.
We tried using rancher2_sync. but it has no effect so far. Is there any other way to achieve the smooth deletion of every resource we have used?
As a last resort, I see the way of implementing a sleep before destroy, which wouldn't be that nice in my opinion
# This resource will destroy (at least) 30 seconds after null_resource.next
resource "null_resource" "previous" {}
resource "time_sleep" "wait_30_seconds" {
depends_on = [null_resource.previous]
destroy_duration = "30s"
}
# This resource will create (potentially immediately) after null_resource.previous
resource "null_resource" "next" {
depends_on = [time_sleep.wait_30_seconds]
}
#maes,
Can you please check out the following:
Verify the removal order, confirm that AKS deletion was never run before the vnet deletion.
If (1) is true, follow https://www.terraform.io/docs/cli/commands/graph.html to export and review the dependency graph. You should find a dependency from AKS to vnet.
If not, try depends_on following https://learn.hashicorp.com/tutorials/terraform/dependencies#manage-explicit-dependencies.

Terraform to destroy a particular resource

Can we destroy a particular resource.
For example : An azure sql database only, without affecting the sql server or any firewalls.
will the below work and what is the resource address.
terraform destroy -target xxx
yes terraform has that functionality to destroy selected resources, but first you have to detached the dependent resources from the target resource and then try this command terraform destroy -target RESOURCE_TYPE.NAME
Yes, you can destroy specific resources, one at a time.
Following the terraform azure sql example : https://www.terraform.io/docs/providers/azurerm/r/sql_database.html
When the resources are created, they are registered in the terraform state file.
You can list the resources in the state file :
$ terraform state list
azurerm_resource_group.test
azurerm_sql_database.test
azurerm_sql_server.test
You can then destroy the sql database only with this command :
$ terraform destroy -target=azurerm_sql_database.test

Terraform persistent and dynamic infrastructure parts?

I want to divide my infrastructure into two parts:
Persistent (firewalls, block storages, etc)
Dynamic (that will consume persistent resources from #1)
I want to be sure that persistent part never would be deleted and at the same time, there would be an option terraform destroy on the dynamic infrastructure part.
All resources you do not want to destroy you have to add the lifecycle policy: prevent_destroy
Have a look at the documenation: https://www.terraform.io/docs/configuration/resources.html#prevent_destroy
To fully prevent the destruction you would have to fine tune the permissions on the resources at your provider. However there is an easy way to divide your infrastructure.
Terraform offers a remote state data source which allows you to use output from a different project so you won't be able to destroy those resources while working with the dynamic part.
I have a bit of a different work around. The resources I do not want to delete with "terraform destroy" I create as "null_resource" using a provisioner with CLI. You can still use your variables in terraform as well.
for example (Create a resource group, but it is persistent due to null_resource)
resource "null_resource" "backend-config" {
provisioner "local-exec" {
command = <<EOT
az group create --location ${var.Location} --name ${var.Resource_group_name} --tags 'LineOfBusiness=${var.Lob}' 'Region=${var.Region}' 'Purpose="Terraform-Primary-Resource-Group-${var.Lob}'
EOT
interpreter = ["Powershell", "-Command"]
}
}
Now if you destroy the resources using terraform destroy. Any null_resource will remain intact.
I would solve this by having 2 Terraform deployments. You create the "static" resources once, and don't touch them. For extra safety, manually add a deletion lock to those resources (eg. I know you can do this in Azure, I assume other cloud providers have a similar solution).
Import these resources in your Dynamic Terraform deployment, using data blocks (not resources). Terraform will never attempt to delete resources you import using data blocks.

Terraform and Updates

Being able to capture infrastructure in a single Terraform file has obvious benefits. However, I am not clear in my mind how - once, for example, a virtual machine has been created - subsequent updates are handled.
So, to provide a specific scenario. Suppose that using Terraform we set up an Azure vm with SQL Server 2014. Then, after a month we decide that we should like to update that vm with the latest service pack for SQL Server 2014 that has just been released.
Is the recommended practice that we update the Terraform configuration file and re-apply it?
I have to disagree with the other two responses. Terraform can handle infrastructure updates just fine. The key thing to understand, however, is that Terraform largely follows an immutable infrastructure paradigm, which means that to "update" a resource, you delete the old resource and create a new one to replace it. This is much like functional programming, where variables are immutable, and to "update" something, you actually create a new variable.
The typical pattern with Terraform is to use it to deploy a server image, such as an Virtual Machine (VM) Image (e.g. an Amazon Machine Image (AMI)) or a Container Image (e.g. a Docker Image). When you want to "update" something, you create a new version of your image, deploy that onto a new server, and undeploy the old server.
Here's an example of how that works:
Imagine that you're building a Ruby on Rails app. You get the app working in dev and it's time to deploy to prod. The first step is to package the app as an AMI. You could do this using a tool like Packer. Now you have an AMI with id ami-1234.
Here is a Terraform template you could use to deploy this AMI on a server (an EC2 Instance) in AWS with an Elastic IP Address attached to it:
resource "aws_instance" "example" {
ami = "ami-1234"
instance_type = "t2.micro"
}
resource "aws_eip" "example" {
instance = "${aws_instance.example.id}"
}
When you run terraform apply, Terraform deploys the server, attaches an IP address to it, and now when users visit that IP, they will see v1 of your Rails app.
Some time later, you update your Rails app and want to deploy the new version, v2. To do that, you build a new AMI (i.e. you run Packer again) to get an ami with ID "ami-5678". You update your Terraform templates accordingly:
resource "aws_instance" "example" {
ami = "ami-5678"
instance_type = "t2.micro"
}
When you run terraform apply, Terraform undeploys the old server (which it can find because Terraform records the state of your infrastructure), deploys a new server with the new AMI, and now users will see v2 of your code at that same IP.
Of course, there is one problem here: in between the time when Terraform undeploys v1 and when it deploys v2, your users would see downtime. To work around that, you could use Terraform's create_before_destroy lifecycle setting:
resource "aws_instance" "example" {
ami = "ami-5678"
instance_type = "t2.micro"
lifecycle {
create_before_destroy = true
}
}
With create_before_destroy set to true, Terraform will create the replacement server first, switch the IP to it, and then remove the old server. This allows you to do zero-downtime deployment with immutable infrastructure (note: zero-downtime deployment works better with a load balancer that can do health checks than a simple IP address, especially if your server takes a long time to boot).
For more information on this, check out the book Terraform: Up & Running. The code samples for the book include an example of a zero-downtime deployment with a cluster of servers and a load balancer: https://github.com/brikis98/terraform-up-and-running-code
Terraform is an infrastructure provision tool, th configuration/deployment tools will be:
chef
saltstack
ansible
etc.,
As I am working with chef, so basically, I provision the server instance by terraform, then terraform (terraform provisioner) handles the control to chef for system configuration and deployment.
For the moment, terraform cannot delete the node/client in chef server, so after you terraform destroy, you need remove them by yourself.
Terraform isn't best placed for this sort of task. Terraform is an infrastructure management tool, not configuration management.
You should use tools such as chef, puppet, and ansible to deal with the configuration of the system.
If you must use terraform for this task; you could create a template_file resource and place in the configuration required to install the SQL server, and how to upgrade if a different version is presented. Reference: here
Put that code inside a provisioner under the null_resource resource. reference: here.
The trigger for this could be the variable containing the SQL version. So, when you present a different version of SQL it'll execute that provisioner on each instance to upgrade the versions.

Resources