what is the name assigned by terraform to reference this resource? - terraform

Could any please answer my question : whether it is a) azurerm_resource_group b) test c) dev
resource "azurerm_resource_group" "dev"
{
name = "test"
location = "canadacentral"
}

A block resource "azurerm_resource_group" "dev" declares a resource with the address azurerm_resource_group.dev in the current module, so azurerm_resource_group.dev is how you'd refer to this object from expressions elsewhere in the same module.
The name argument inside the block is part of the data sent to the Azure provider, so it's up to the Azure provider to decide how to make use of it. In this particular case, I believe the provider will send that value as part of its requests to the Azure API to create, update, or delete this object, and so it'll become the name of the object as far as the remote system is concerned, and not the name of the object as far as Terraform is concerned.

More easy to understand:
azurerm_resource_group is the official name that the Azure developer who created the code for the provider gave it.
dev is the name you have given to the resource and is the local name. This is used to refer to this resource from elsewhere in the same Terraform module, but has no significance outside that module's scope. This is called "Resource names". (https://developer.hashicorp.com/terraform/language/resources/syntax#resource-syntax)
test is the Name which should be used for this Resource Group. (https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group#name). But I think it is easier to see it in another resource. In the resource aws_ami, the name is the Region-unique name for the AMI.(https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ami#name)
So to summarize the answer is dev. Since even if you put it on, terraform uses it to reference.

Related

Terraform Import - Is the Resource Label critical?

Our terraform remote state file in Azure has been completely destroyed and we're now faced with the challenge of recreating the state file from scratch. My option is to use the Terraform import command, using the following simple syntax:
terraform import <Terraform Resource Name>.<Resource Label> <Azure Resource ID>
To import the existing resource group for example, I will create the following configuration in a main.tf file.
provider "azurerm" {
version="1.39.0"
}
# create resource group
resource "azurerm_resource_group" "rg"{
name = "rg-terraform"
location = "uksouth"
}
Now, the problem I have is as follows:
When the existing Azure resources were originally created, they were assigned names that used an extremely complex naming convention, with some characters even being randomly generated. To further compound matters, they were all unique and there are hundreds of them. All would have been rosy if they were assigned a simplistic name like "main", as is used commonly in a lot of Terraform examples, but unfortunately, that's not the case.
My question therefore, is this:
When putting together my main.tf configuration file to be used for the Import, is it an absolute requirement that my "Resource Label" (given in my Import command) has to match the original "Resource Label" name from when the resource was created?
If it is a mandatory requirement, is there any way I could retrieve the original "Resource Label" from Azure in the same way that I can for instance obtain the "Azure Resource ID" from the Azure Portal or even an Az CLI query?
How can I ensure any child resources such as Subnets are included in the Import, without having to trawl manually through the Azure Portal to identify each one of them?
No, absolutely not. Choose whatever you want.
No, Azure generally does not know about this label, it is something terraform internal.
Unfortunately you need to import each and every resource manually and separately.
Have you made absolutely sure the current state file is lost? The storage location was not versioned? Does no developer still have a local copy of the state file laying around?

Order of resource creation in Terraform template

I have created terraform template (azure) with two modules. One module is for the resource group. the other is for vnet (it handles the creation of NSG and route table as well along with their association with subnets).
When I run terraform apply, it is giving an error for the route table, as the resource group is not created yet. the order of creation is showing as route table is created first and then resource group.
Is there a way to set the order of creation? in the main.tf in the root folder, module resource group is called first and then vnet.
Reconsider the idea of creating RG and resources using two modules. Ask yourself a simple question: why?
If you are 100% sure it is the right approach then use depends_on:
module "rg1" {
source = "./rg_module"
...
}
module "net1" {
source = "./network_module"
....
depends_on = [module.rg1]
}
Another alternative would be to use implicit dependence:
-Have the root module where resource group is actually defined return an output:
output "rg_name" {
value = azurerm_resource_group.root_rg.name
}
-No modifications in resource group module which calls the root module
-While creating route table(module),use the output value from resource group module:
[Assuming the variable assignment in below module is providing input to its root source using the name resource_group_name]
resource_group_name =module.rg_module["<OPTIONAL KEY IF USING FOR EACH IN RG MODULE"].rg_name
This creates an internal dependence on the resource group.
Note that it is not possible to reference arguments(actually variables) from the resource group module unless output values were defined.
You must use -out option to save the plan to a file. Like:
terraform plan -out <plan_file>
It is always recommended to use -out and save the plan file. This will ensure that the order of creation is preserved across subsequent applies.

Terraform resource with the ID already exists

When Terraform run task executes in azure devops release pipeline I get an error "A resource with the ID already exists".
The resource exists in Azure but why it is complaining about the resource if this already exists. This should ignore this part. Please help what I need to add in my code that will fix this error!
Am I just using this bugging terraform tool for deploying azure resource? Terraform help is terrible!!!
resource "azurerm_resource_group" "test_project" {
name = "${var.project_name}-${var.environment}-rg"
location = "${var.location}"
tags = {
application = "${var.project_name}"
}
}
Terraform is designed to allow you to manage only a subset of your infrastructure with a particular Terraform configuration, in case either some objects are managed by another tool or in case you've decomposed your infrastructure to be managed by many separate configurations that cooperate to produce the desired result.
As part of that design, Terraform makes a distinction between an object existing in the remote system and that object being managed by the current Terraform configuration. Where technical constraints of an underlying API allow it, Terraform providers will avoid implicitly taking ownership of something that was not created by that specific Terraform configuration. The error message you saw here is the Azure provider's implementation of that, where it pre-checks to make sure the name you give it is unique so that it won't overwrite (and thus take implicit ownership of) an object created elsewhere.
To proceed here you have two main options, depending on your intended goal:
If this object was formerly managed by some other system and you now want to manage it exclusively with this Terraform configuration, you can tell Terraform to associate the existing object with the resource block you've written and thus behave as if that object were originally created by that resource block:
terraform import azurerm_resource_group.test_project /subscriptions/YOUR-SUBSCRIPTION-ID/resourceGroups/PROJECTNAME-ENVIRONMENTNAME-rg
After you run terraform import you must ensure that whatever was previously managing that object will no longer associate with it. This object is now owned by this Terraform configuration and must not be changed by any other system.
If this object is managed by some other system and you wish to continue managing it that way then you can instead use a data block to retrieve information about that existing object to use elsewhere in your configuration without Terraform taking ownership:
data "azurerm_resource_group" "example" {
name = "${var.project_name}-${var.environment}-rg"
}
If you needed the resource group's location name elsewhere in your module, for example, you could use data.azurerm_resource_group.example.location to access it. If you wanted to make any later changes to this resource group, you would continue to do that using whichever other system is considered the owner of it in your environment.
The main difference between these two approaches is how Terraform will record the object in state snapshots. terraform import causes Terraform to create a binding between the resource configuration you wrote and the remote object whose id you gave on the command line, which is henceforth indistinguishable to Terraform from it having created that object and recorded the binding itself in the first place. For a data resource, Terraform just reads the data about the existing object and saves a cache of it in the state so it can determine if the value has changed on a future run; it will never plan to make any modifications to an object used with a data block.
Try to delete the .terraform local folder to clean the cache, then run terraform init again and retry running the pipeline.
For my future self:
Today I stumbled across this same problem, because I renamed some resources, and terraform could not track them. I found out about terraform state mv ... which gives you the ability to rename resources in your state file, so that it can track remote resources. Really useful.

How terraform know which resource should it run first to spin up infrastructure?

I’m using terraform to spin up Aws-DMS. To spin up DMS, we need subnet groups, dms replication task, dms endpoints, dms replication instance. I’ve configured everything using terraform documentation. My question is how will terraform know which task to be completed first to spin up other dependency tasks?
Do we need to declare it somewhere in terraform or is terraform intelligent enough to run accordingly?
Terraform uses references in the configuration to infer ordering.
Consider the following example:
resource "aws_s3_bucket" "example" {
bucket = "terraform-dependencies-example"
acl = "private"
}
resource "aws_s3_bucket_object" "example" {
bucket = aws_s3_bucket.example.bucket # reference to aws_s3_bucket.example
key = "example"
content = "example"
}
In the above example, the aws_s3_bucket_object.example resource contains an expression that refers to aws_s3_bucket.example.bucket, and so Terraform can infer that aws_s3_bucket.example must be created before aws_s3_bucket_object.example.
These implicit dependencies created by references are the primary way to create ordering in Terraform. In some rare circumstances we need to represent dependencies that cannot be inferred by expressions, and so for those exceptional circumstances only we can add additional explicit dependencies using the depends_on meta argument.
One situation where that can occur is AWS IAM policies, where the graph created naturally by references will tend to have the following shape:
Due to AWS IAM's data model, we must first create a role and then assign a policy to it as a separate step, but the objects assuming that role (in this case, an AWS Lambda function just for example) only take a reference to the role itself, not to the policy. With the dependencies created implicitly by references then, the Lambda function could potentially be created before its role has the access it needs, causing errors if the function tries to take any actions before the policy is assigned.
To address this, we can use depends_on in the aws_lambda_function resource block to force that extra dependency and thus create the correct execution order:
resource "aws_iam_role" "example" {
# ...
}
resource "aws_iam_role_policy" "example" {
# ...
}
resource "aws_lambda_function" "exmaple" {
depends_on = [aws_iam_role_policy.example]
}
For more information on resource dependencies in Terraform, see Resource Dependencies in the Terraform documentation.
Terraform will automatically create the resources in an order that all dependencies can be fulfilled.
E.g.: If you set a security group id in your DMS definition as "${aws_security_group.my_sg.id}", Terraform recognizes this dependency and created the security group prior to the DMS resource.

Why do some resources have a name and a "name" attribute?

I am new to Terraform and trying to create some resources on Azure. To me it looks like there is some unnecessary duplication between the resource name and the attribute name in the definitions.
resource "azurerm_resource_group" "group_name" {
name = "group_name" # <-- repeated!
location = "${local.location}"
}
Is there a difference? Can I somehow set them to be the same in the spirit of this:
resource "azurerm_resource_group" "group_name" {
name = "${name}"
location = "${local.location}"
}
The two names here serve different purposes and have different scopes.
The name that appears in the block header is a local name used within a single Terraform module. It is useful when interpolating results from one resource into another, like ${azurerm_resource_group.group_name}. The remote API never sees this name; it is used only for internal references.
The name within the block is an attribute specific to the resource type itself -- azurerm_resource_group in this case. This name will be sent to the remote API and will be how the object is described within the AzureRM system itself.
In simple configurations within small organizations it is indeed possible that both of these names could match. In practice, the difference in scope between these names causes them to often vary. For example:
If there are multiple separate teams or applications sharing an AzureRM account, the name used with the API may need to be prefixed to avoid collisions with names created by other teams or applications, while the local name needs to be unique only within the module where it's defined.
In more complex usage with child modules, it's common to instantiate the same child module multiple times. In this case, the local name will be the same between all of the instances (because it's significant only within that instance) but the name used with the API will need to be adjusted for each instances so that they don't collide.
The resource name is the name you use to refer to the resource in Terraform context. The name parameter is the name given to the resource inside your provider's context. Resource don't have to have a name parameter, for example AWS Elastic IP resource doesn't have a name because AWS doesn't allow you to name them. Some of the resource like AWS Security group rule don't even translate one to one to resources you can name.

Resources