Quantcast
Channel: Terraform - HashiCorp Discuss
Viewing all 11407 articles
Browse latest View live

Managing multiple environments in terraform

$
0
0

I have a repo and in the root I have three directories for qa, stage and prod for each environment to create infrastructure in respective environment.
And I want to keep the code DRY (Don’t repeat yourself).

NOTE: In each directory qa, stage and prod we are calling the child modules which are in the remote and not placing the child module configuration at the root of the module.

I have a providers.tf file which is a globally common where all the providers are defined and each have alias. But, I want to place the provideres.tf file in the root of the repo instead of placing the SAME file in all the three qa, stage and prod directories.

Is it possible to place the common globally defined Providers.tf file in the root of the repo and build the infrastructure in all the environments? Also, we are trying to stick with the vanilla terraform instead using the terragrunt. Is it possible?

1 post - 1 participant

Read full topic


Quick Cash Loan App Customer Care Helpline Number 63OO192283 Toll Free 6300192283 Call Now.iii

$
0
0

Quick Cash Loan App Customer Care Helpline Number 63OO192283 Toll Free 6300192283 Call Now.Quick Cash Loan App Customer Care Helpline Number 63OO192283 Toll Free 6300192283 Call Now.Quick Cash Loan App Customer Care Helpline Number 63OO192283 Toll Free 6300192283 Call Now.

2 posts - 1 participant

Read full topic

Delete az vm was created with count terraform module

$
0
0

Hello,

I have deployed a vm(s) azure using terraform module with count.

So, i have create a 5 vm azure (count =5) and i deleted the second vm from the portal and then from the tfstate that was stored in storage account.

But when, i run my pipeline after that, the second vm will be recreated and added again to my tfstate.

How can i delete the second vm from the count terraform code please without recreating it on the next deployment ?

Thanks

1 post - 1 participant

Read full topic

Support for Firebase Cloud Messaging (FCM) v1 for Azure Notification Hub (ANH)

$
0
0

Hi folks,

Does Terraform already support FCM v1 for ANH? I am looking at the documentation here but I am not able to find any details: (Terraform Registry)

Thank you!

1 post - 1 participant

Read full topic

Looping over a list in a list

$
0
0

hello.

I know there is a lot of example and article about this but i can’t get it working.

I have a variable like that:

dns = {
  server_ip     = "xxxxxxx"
  domains = [
    {
      domain        = "mydomain1.fr"
      a_records     = [""]
      cname_records = [
        "www"
      ]
    },
    {
      domain        = "mydomain2"
      a_records     = [""]
      cname_records = [
        "www",
        "back"
      ]
    }
  ]
}

I’m trying to iterate the list (dns) to create records into a registrar. How can I iterate over a_records inside the foreach (subdomain need a string, not a list) ?

resource "ovh_domain_zone_record" "a_records" {
  for_each = { for domain in var.dns2.domains : domain.domain => domain }

  zone      = each.key
  subdomain = each.value.a_records[0]
  fieldtype = "A"
  ttl       = 300
  target    = var.dns.server_ip
}

Thanks fr your help :cry:

2 posts - 2 participants

Read full topic

Not able to extract single string from map stored in output

$
0
0
######### Variable in module ##############
variable "instanceTargetAttachment" {
  type = map(object({
    targetGroupArn = string
    instanceID = string 
    port = number
  }))
  default = {}
}

####### Actual Value passed ############
variable "instanceTargetAttachment" {
 default = {
    target-11 = {
      targetGroupArn = "arn:aws:elasticloadbalancing:us-east-1:730335241082:targetgroup/terraformTest-80/656f5c02aa6183b"
      instanceID = ["i-09b14edc562c8778t", "i-09b14edc562c8778t"]
      port = 80
    }
   
    }   
  }
}

I am not able to extract single value to target_group_arn in aws_lb_target_group_attachment

the value in the output is like

terraform output
WebserverInstanceId = {
  "webserver-1" = "i-00aa69a47495d5dcf"
  "webserver-2" = "i-0fa626c1a9ab4d52b"
}
targetGroupArn = {
  "terraformTest-80" = "arn:aws:elasticloadbalancing:us-east-1:730335241082:targetgroup/terraformTest-80/656f5c02aa6183"
  "terraformTest-81" = "arn:aws:elasticloadbalancing:us-east-1:730335241082:targetgroup/terraformTest-81/814f284b095c86"
} 

I want to use the values in a way that single target group is picked and attach all the given instances and then second target group and attach the given instances to that with the port given.

kindly help
Thanks

1 post - 1 participant

Read full topic

Loop within a loop for GCP instance creation with multiple volumes

$
0
0

Hi guru’s,

I creating some terraform which automates the creation of GCE instances, along with multiple volumes. I’m trying to make it flexible, so all I need to do is input the GCE instance(s) variables (in a map), along with it’s volume resource requirements if the instance has multiple volumes. That way all I need to do is update the tfvars files with the new info for the application to create all of the GCE instances, and their associated volumes and other resources.

I have the CGE instances create loop working fine (using a map(object)), but now i’m working on creating the volumes within that process and I’m lost.

How do I get the Volume loop working within the GCE instance creation loop?

Thanks in advance.

1 post - 1 participant

Read full topic

How to manage all my cdk stacks?

$
0
0

So we have deploy multiple services. To an extent they are part of the same whole.

What I’m trying to figure out is how do we group these stacks?

I’m assuming that all my stacks that work together should all be tagged against a specific cdktf.json? right? I shouldn’t try and have multiple of these? I guess what I’m trying to avoid is having to always deploy all my stacks but I guess when deploying a specific stack I’m only going to need to deploy the stack and its dependencies. So not all the stacks. But then I know it should only deploy stacks that have changed.

So this would mean have a main.ts for example which houses the app and all the stacks and then referring to this file from cdktf.json. The alternative, which I think I’d prefer is to have multuiple of these cdktf.json files and then multiple smaller apps and stack creation ts files… Though I’m a little skeptical that this would work, it would certainly be easier to manage. I’m skeptical that this would work as I have a “General” stack that provides things like VPC and is thus shared by all the stacks…

I guess the problem with that though is if I use github actions to deploy then I won’t be able to tell which stack has changed and will probably have to deploy all the stacks in any case?

1 post - 1 participant

Read full topic


Create multiple resources in for_each context

$
0
0

Hello,

I’m currently stuck in finding a way to combine a count in a for_each ( yes, I know it’s not possible :slight_smile: )
I have a list of objects representing VM settings:

vms = [
{
purpose = “webfront”
size = “Standard”

},
{
purpose = “app”
size = “large”

}
]

no problem with that, it can be managed pretty easily with a count or a for_each.
Now I would like to add the possibility to create multiple VM of a kind.
For instance:

vms = [
{
number_to_create = 1
purpose = “webfront”
size = “Standard”

},
{
number_to_create = 2
purpose = “app”
size = “large”

}
]

I tried to do it by using the sum function over the number_to_create values to count the total number of VM to create, but the problem is that considering how lists are created, the result is not consistent. For example, with the above case I will have 2 webfront and 1 app because the list is probably created recursively.
count = 3 => [ “webfront”,“app”,“webfront” ]

What I would need is to “count” the number_to_create in “for-each” vm …

Do you have any idea on how I could achieve this ?

Thank you for your precious help

1 post - 1 participant

Read full topic

Dynamic Credentials AWS - Multiple Configurations - Terraform Enterprise

$
0
0

In the documentation it is stated that in order to use multiple dynamic credentials configurations defined in a workspace, you need to add the following variable to your code.

variable “tfc_aws_dynamic_credentials” {
description = “Object containing AWS dynamic credentials configuration”
type = object({
default = object({
shared_config_file = string
})
aliases = map(object({
shared_config_file = string
}))
})
}

For Terraform Cloud it works for Terraform Enterprise it does not work. I get the following error.

“Error: No value for required variable”

What version of the terraform provider and Terraform Enterprise is required.

1 post - 1 participant

Read full topic

Invalid value for "v" parameter: cannot convert tuple to string in for/if, isolating a string data element

$
0
0

I get an error during plan/apply that appears to be due to unresolved details of an object to build. Below is one of 3 errors (the others confirm AZ-letter is “b” and “c”).

│ Error: Invalid function argument

│ on vpc.tf line 63, in resource “aws_nat_gateway” “ngw”:
│ 63: allocation_id = tostring([for eip in aws_eip.nat_ip : eip.id if eip.tags.AZ-letter == each.value.tags.AZ-letter])
│ ├────────────────
│ │ while calling tostring(v)
│ │ aws_eip.nat_ip is object with 3 attributes
│ │ each.value.tags.AZ-letter is “a”

│ Invalid value for “v” parameter: cannot convert tuple to string.

Excerpts of my code suggest the if == comparison should be 2 strings. It appears the ‘aws_eip.nat_ip is object with 3 attributes’ isn’t being evaluated to recognise aws_eip.nat_ip.tags.AZ-letter will be a string value. Please provide guidance (or confirmation this is a bug and suggestions maybe how to work around it)

variable azs {
type = list(string)
default = [“ap-southeast-2a”,“ap-southeast-2b”,“ap-southeast-2c”]
}

locals {
subnets = flatten([for env_name, env_setup in var.envs :
[for subnet_type, octet_offset in var.subnet_defs :
[for az in var.azs :
[for subnet_details in tolist([{
subnet_name = “{var.prefix}-{env_name}-subnet-{subnet_type}-{substr(az,length(az)-1,1)}”,
subnet_ip = “{var.upper_network}.{env_setup.start+(octet_offset+(4*(index(var.azs,az)+1)))}.0”,
az = az,
env = env_name,
area = subnet_type,
az_letter = substr(az,length(az)-1,1)
}]) : subnet_details if (env_setup.active_azs[index(var.azs,az)] && contains(env_setup.reqd_defs, subnet_type))
]
]
]
])
}

resource “aws_subnet” “infra_subnets” {
for_each = {for subnet in local.subnets : subnet.subnet_name => subnet if subnet.env == “mgmt”}
vpc_id = aws_vpc.eos-vpc.id
cidr_block = “{each.value.subnet_ip}/{var.mask}”
availability_zone = each.value.az
tags = {
Name = each.value.subnet_name
Environment = each.value.env
AZ-letter = each.value.az_letter
}
}

resource “aws_eip” “nat_ip” {
for_each = aws_subnet.infra_subnets
domain = “vpc”
tags = {
Name = “{var.prefix}-mgmt-nat_ip-{each.value.tags.AZ-letter}”
AZ-letter = each.value.tags.AZ-letter
}
depends_on = [aws_internet_gateway.igw]
}

resource “aws_nat_gateway” “ngw” {
for_each = aws_subnet.infra_subnets
allocation_id = tostring([for eip in aws_eip.nat_ip : eip.id if eip.tags.AZ-letter == each.value.tags.AZ-letter])
subnet_id = each.value.id
tags = {
Name = “{var.prefix}-mgmt-ngw-{each.value.tags.AZ-letter}”
AZ-letter = each.value.tags.AZ-letter
}
depends_on = [aws_internet_gateway.igw, aws_eip.nat_ip]
}

6 posts - 2 participants

Read full topic

How do I pass a configuration block to a variable?

$
0
0

We have a very common pattern used in our company when creating AWS roles. For each role we create we’ll want to associate a policy with it.

The four resource types that we use are

  • aws_iam_role
  • aws_iam_policy_document
  • aws_iam_policy
  • aws_iam_policy_attachment

We also create them for multiple environments so we use for_each chaining to link them all together. It looks something like this:

resource "aws_iam_role" "role" {
  for_each = toset(["dev", "qa", "live"], )
  name = "role-name-${each.key}"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

data "aws_iam_policy_document" "doc" {
  for_each = aws_iam_role.role
  statement {
    sid = "1"

    actions = [
      "s3:GetObject",
      "s3:ListBucket"
    ]

    resources = [
      "arn:aws:s3:::bucket-name",
      "arn:aws:s3:::bucket-name/*"
    ]
  }

  statement {
    actions = [
      "s3:ListAllMyBuckets",
      "s3:GetBucketLocation"
    ]

    resources = [
      "arn:aws:s3:::*",
    ]
  }
}

resource "aws_iam_policy" "policy" {
  for_each = data.aws_iam_policy_document.doc
  name     = aws_iam_role.role[each.key].name
  path     = "/"
  policy   = each.value.json
}

resource "aws_iam_policy_attachment" "attachment" {
  for_each   = aws_iam_policy.policy
  name       = each.value.name
  policy_arn = each.value.arn
  roles = [
    aws_iam_role.role[each.key].name
  ]
}

This is such a common pattern that I’d like to abstract it into a module. The only things that will change each time the module is instantiated are:

  • role name
  • the list in the for_each
  • policy statements

so those will be module variables. The role name and list are easy to create variables for but I haven’t a clue how to pass multiple statements (which are represented as configuration blocks). Is it even possible?

Perhaps my variable needs to accept a list of objects and use dynamic blocks inside my module to create a statement for each object. I’d prefer to just pass the statements to my module though, is it possible?

1 post - 1 participant

Read full topic

Migrating out of Terragrunt

$
0
0

Hello,

I have a weird issue with migration out of terragrunt. Codebase is old and runs on version 12 of terraform. Infrastructure spins up EKS cluster in AWS using public terraform module + some other extra resources.

Thing is when I managed to get all inputs out of terragrunt and reuse tfstate terraform tries to recreate pretty much all resources.

What is even more weird I have cross-checked data of some resources I mean what terraform want to create and what is in current state and there is no difference at all.
I have no idea why terraform tries to recreate those during plan, even though it shouldn’t really do anything because all resources are present in state.

Running terraform refresh did not help either.

I cannot really run terraform apply because it will recreate all resources and this is not something I can do.

I’m thinking about maybe creating new deployment with new module and updated tf version but how I can copy resources in between both states?
I have done imports before, but not sure if all resources support import function (not all do in all providers).

Any ideas how to approach this problem?

1 post - 1 participant

Read full topic

The given value is not suitable for var.prefix_list declared at variable.tf:11,1-23: element "TO_WAN_1": attribute "rule":

$
0
0

I am trying to create a prefix-list using for_each however this resource has a rule attribute that is a block. I am trying to create a prefix-list and the name will make it unique. I want to be able to pass this down to a child module for right now, in the root module just trying to get this to work. End goal for me is to have child module be able to create a prefix list just by passing in values. I am new so any help is greatly appreciated! I can only post one snippet

variables.tf

3 posts - 1 participant

Read full topic

Issue initializing terraform

$
0
0

this is error I am kipping having.
error: failed to query available provider packages
could not retrieve the list of available versions for provider hashicorp/aws: could not connect to registry.terraform.io: failed to request discovery document

1 post - 1 participant

Read full topic


Cloudfront redirects

Experiment Feedback: Input Variable Validation can cross-reference other objects

$
0
0

Hi everyone,

In yesterday’s Terraform CLI v1.9.0-alpha20240501 there is an experimental implementation of the long-requested feature of allowing input variable validation rules to refer to other values in the same module as the variable declaration.

For example, it allows the validation rule of one variable to refer to another:

terraform {
  # This experiment opt-in will be required as long
  # as this remains experimental. If the experiment
  # is successful then this won't be needed in the
  # final release.
  experiments = [variable_validation_crossref]
}

variable "thingies" {
  type = map(object({
    size = number
  }))
}

variable "default_thingy" {
  type = string

  validation {
    # It was not previously valid for this expression
    # to refer to var.thingies.
    condition     = can(var.thingies[var.default_thingy])
    error_message = "The default thingy must match one of the keys specified in 'thingies'."
  }
}

This experimental implementation also allows referring to anything else that you would normally be able to refer to from inside the same module. We’re hoping that this full generality will work correctly, but since this is the first time we’ve allowed an input variable to refer to other items in the same module where it was declared we’d like to see folks try this out with various different kinds of references – e.g. references to data and resource blocks – to learn if there are any unexpected hazards we’ve not considered, such as tricky dependency cycles.

If you’re interested in this new capability, we’d appreciate it if you could try this out in the alpha release with some as-close-as-possible approximations of how you’d imagine using this feature in your real modules. The closer you can get to what you’d do “for real”, the better we can build confidence in the design and implementation of this feature.

Since this is only an alpha release we do not recommend using this build in production. Instead, please limit your experiments to development environments that cannot affect any infrastructure whose downtime would be detrimental to you or your organization.

If you choose to participate and have feedback to share, it would be most helpful if you could reply to this topic and include all of the relevant parts of the configuration you tried with. In particular, we’d love to see:

  • Your variable blocks containing validation blocks.
  • The declarations of whatever those validation blocks are referring to.
  • Some examples of typical ways users of your module would call it. Ideally, realistic patterns such as passing in references to resources from the calling module, rather than just hard-coded constant values.
  • If you encountered problems, the full text of any error messages Terraform returned.

I’m personally feeling pretty optimistic about this experiment since unlike most of them it’s a relatively small improvement building on other internal refactoring work we’ve been doing over the last few years, but your feedback will help us determine whether the current approach is good or whether some further design or implementation iteration is needed.

Thanks in advance for any testing and feedback!

1 post - 1 participant

Read full topic

Experiment Feedback: The `templatestring` function

$
0
0

Hi everyone,

In yesterday’s Terraform CLI v1.9.0-alpha20240501 there is an experimental implementation of the long-requested feature of treating a string value fetched from somewhere other than the local filesystem as a Terraform template, and rendering it with a provided set of template variables.

For (very contrived) example:

terraform {
  # This experiment opt-in will be required as long
  # as this remains experimental. If the experiment
  # is successful then this won't be needed in the
  # final release.
  experiments = [template_string_func]
}

data "aws_s3_object" "example" {
  bucket = "example-example-example"
  key    = "example.tmpl"
}

output "result" {
  value = templatestring(data.aws_s3_object.example.body, {
    foo = "bar"
  })
}

Those who were following earlier discussion about this request may recall that we were concerned that adding this might reintroduce an earlier problem of inexperienced Terraform users finding this function and thinking that it’s the way to render templates, and having a very bad time trying to figure out how to escape a literal template to pass to the function. That usability hazard came up a surprising number of times with the earlier template_file data source offered by the (now-deprecated) hashicorp/template provider, and so we were cautious about repeating it.

This experiment therefore includes an attempted compromise: unlike most Terraform functions, this one is more “fussy” about what syntax it will accept for specifying its first argument. Specifically, it requires the first argument to always be a direct reference to some other named object in the current module. In the example above, that reference is data.aws_s3_object.example.body.

In particular this means that it’s forbidden to write a template expression directly into the first argument, which would suggest that someone is trying to use this function unnecessarily:

# The following is not allowed, as a special case
templatestring("Hello, $${name}", {
  name = "Martin"
})

This compromise is here only to help Terraform give better feedback and not to constrain what’s possible. If you really do want to construct a template string dynamically from parts for some reason, you can achieve that by factoring out the construction of the template into a separate local value, which we’re using as a heuristic for “I know what I’m doing, get out of my way”:

locals {
  greeting_template = "Hello, $${name}"
}

output "result" {
  value = templatestring(local.greeting_template, {
    foo = "bar"
  })
}

Since the most commonly-reported use-cases for this function were in fetching templates from elsewhere (e.g. data sources) and passing template strings through input variables – both of which involve references to specific single objects – we’re hoping that this compromise will give power users a useful tool while also narrowly avoiding a repeat of the earlier usability hazard.


Before we move forward with this in a stable release, we’d like to gather some examples of it being used both successfully and unsuccessfully, to hopefully give us a signal about whether this is a viable compromise.

If you are interested in using this new function, it would help if you could download the alpha release and try it with something as close as possible to the real situation where you’d use this function.

Since this is only an alpha release we do not recommend using this build in production. Instead, please limit your experiments to development environments that cannot affect any infrastructure whose downtime would be detrimental to you or your organization.

If you choose to participate and have feedback to share, it would be most helpful if you could reply to this topic and include all of the relevant parts of the configuration you tried with. In particular, we’d love to see:

  • Whatever enclosing block you’re calling templatefile from, so that we can understand the specific use-case. (Specific, real-world examples are helpful for understanding the real impact of adding this feature.)
  • The configuration of whatever object you’ve referred to in the first argument to templatefile. If it’s an input variable to a shared module, it would be helpful to see an example of a typical module block using the module.
  • If you run into problems, the full text of any error messages Terraform returned, or any surprising output Terraform returned despite not returning an error.

Thanks in advance for any testing and feedback!

1 post - 1 participant

Read full topic

Nested loop with foreach

$
0
0

Hi all,

I have been following you for a long time and you have helped me many times… thank you very much!

So… i have little bit problem… and i don’t find out the solution

I need to deploy multiple VMs on Vsphere with multiple disks on multiple datastore…
I have compiled this module with this tfvars file, all is ok but i cannot get datastore.id by data.tf… :frowning:

when i run terraform plan, my result is it ok but the datastore id is not resolved by terraform but only take the “clear” data on tfvars… (will be not deploy inside it)… below the bold datastore.id

terraform plan --var site=US --var-file=prod.tfvars -out=prod.plan

# module.vm.vsphere_virtual_machine.vm["server1"] will be created
  + resource "vsphere_virtual_machine" "vm" {
      + annotation                              = "VM1 PRod"
      + boot_retry_delay                        = 10000
      + change_version                          = (known after apply)
      + cpu_hot_add_enabled                     = true
      + cpu_limit                               = -1
      + cpu_share_count                         = (known after apply)
      + cpu_share_level                         = "normal"
      + datastore_id                            = "datastore-1179"
      + default_ip_address                      = (known after apply)
      + ept_rvi_mode                            = "automatic"
      + extra_config_reboot_required            = true
      + firmware                                = "efi"
      + force_power_off                         = true
      + guest_id                                = "sles15_64Guest"
      + guest_ip_addresses                      = (known after apply)
      + hardware_version                        = (known after apply)
      + host_system_id                          = "host-1175"
      + hv_mode                                 = "hvAuto"
      + id                                      = (known after apply)
      + ide_controller_count                    = 2
      + imported                                = (known after apply)
      + latency_sensitivity                     = "normal"
      + memory                                  = 2048
      + memory_hot_add_enabled                  = true
      + memory_limit                            = -1
      + memory_share_count                      = (known after apply)
      + memory_share_level                      = "normal"
      + migrate_wait_timeout                    = 30
      + moid                                    = (known after apply)
      + name                                    = "server1"
      + num_cores_per_socket                    = 1
      + num_cpus                                = 8
      + power_state                             = (known after apply)
      + poweron_timeout                         = 300
      + reboot_required                         = (known after apply)
      + resource_pool_id                        = "resgroup-1177"
      + run_tools_scripts_after_power_on        = true
      + run_tools_scripts_after_resume          = true
      + run_tools_scripts_before_guest_shutdown = true
      + run_tools_scripts_before_guest_standby  = true
      + sata_controller_count                   = 0
      + scsi_bus_sharing                        = "noSharing"
      + scsi_controller_count                   = 4
      + scsi_type                               = "pvscsi"
      + shutdown_wait_timeout                   = 3
      + storage_policy_id                       = (known after apply)
      + swap_placement_policy                   = "inherit"
      + sync_time_with_host                     = true
      + tools_upgrade_policy                    = "manual"
      + uuid                                    = (known after apply)
      + vapp_transport                          = (known after apply)
      + vmware_tools_status                     = (known after apply)
      + vmx_path                                = (known after apply)
      + wait_for_guest_ip_timeout               = 0
      + wait_for_guest_net_routable             = true
      + wait_for_guest_net_timeout              = 0

      + clone {
          + template_uuid = "423deb75-fdf1-7553-b080-bd617bb1281d"
          + timeout       = 30

          + customize {
              + dns_server_list = [
                  + "10.237.216.7",
                  + "10.237.208.5",
                  + "10.237.111.8",
                ]
              + ipv4_gateway    = "10.237.113.1"
              + timeout         = 10

              + linux_options {
                  + domain       = "adgr.net"
                  + host_name    = "server1"
                  + hw_clock_utc = true
                }

              + network_interface {
                  + ipv4_address = "10.237.113.186"
                  + ipv4_netmask = 24
                }
            }
        }

      + disk {
          + attach            = false
          + controller_type   = "scsi"
          + datastore_id      = "<computed>"
          + device_address    = (known after apply)
          + disk_mode         = "persistent"
          + disk_sharing      = "sharingNone"
          + eagerly_scrub     = false
          + io_limit          = -1
          + io_reservation    = 0
          + io_share_count    = 0
          + io_share_level    = "normal"
          + keep_on_remove    = false
          + key               = 0
          + label             = "disk0"
          + path              = (known after apply)
          + size              = 80
          + storage_policy_id = (known after apply)
          + thin_provisioned  = true
          + unit_number       = 0
          + uuid              = (known after apply)
          + write_through     = false
        }
      + disk {
          + attach            = false
          + controller_type   = "scsi"
          + datastore_id      = "datastore1"
          + device_address    = (known after apply)
          + disk_mode         = "persistent"
          + disk_sharing      = "sharingNone"
          + eagerly_scrub     = false
          + io_limit          = -1
          + io_reservation    = 0
          + io_share_count    = 0
          + io_share_level    = "normal"
          + keep_on_remove    = false
          + key               = 0
          + label             = "0"
          + path              = (known after apply)
          + size              = 20
          + storage_policy_id = (known after apply)
          + thin_provisioned  = true
          + unit_number       = 10
          + uuid              = (known after apply)
          + write_through     = false
        }
      + disk {
          + attach            = false
          + controller_type   = "scsi"
          + datastore_id      = "LocalStorage103"
          + device_address    = (known after apply)
          + disk_mode         = "persistent"
          + disk_sharing      = "sharingNone"
          + eagerly_scrub     = false
          + io_limit          = -1
          + io_reservation    = 0
          + io_share_count    = 0
          + io_share_level    = "normal"
          + keep_on_remove    = false
          + key               = 0
          + label             = "1"
          + path              = (known after apply)
          + size              = 200
          + storage_policy_id = (known after apply)
          + thin_provisioned  = true
          + unit_number       = 30
          + uuid              = (known after apply)
          + write_through     = false
        }

      + network_interface {
          + adapter_type          = "vmxnet3"
          + bandwidth_limit       = -1
          + bandwidth_reservation = 0
          + bandwidth_share_count = (known after apply)
          + bandwidth_share_level = "normal"
          + device_address        = (known after apply)
          + key                   = (known after apply)
          + mac_address           = (known after apply)
          + network_id            = "network-12"
        }
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Below my configuration…

main.tf

module "vm" {
  source = "/home/omar/terraform-vm-foreach/vm"



vsphere_user = var.vsphere_user
vsphere_password = var.vsphere_password
vsphere_server = var.vsphere_server
vsphere_unverified_ssl = var.vsphere_unverified_ssl
compute_cluster = var.compute_cluster
#resource_pool = var.resource_pool
datacenter = var.datacenter
virtual_machines = var.virtual_machines
site = var.site
change = var.change
}

prod.tfvars

vsphere_server         = "192.168.10.100"
vsphere_unverified_ssl = true
datacenter          = "Lab.local"
compute_cluster     = "Lab.local"
change = "CH0000999"


virtual_machines = {
  server1 = {
    datacenter           = "Lab.local"
    compute_cluster      = "Lab.local"
    rspool               = "max"
    network_interface    = "VM Network"
    vmnotes              = "VM1 PRod"
    category             = "dbserver"
    system_cores         = 8
    system_memory        = 2048
    system_disk          = 80
    system_ipv4_address  = "10.237.113.186"
    system_ipv4_netmask  = "24"
    system_ipv4_gateway  = "10.237.113.1"
    datastore            = "LocalStorage103"
    datastore_a          = "LocalStorage103"
    datastore_b          = "datastore1"
    folder               = "/"
    system_name          = "server1"
    system_domain        = "ad1.local"
    dns_server_list      = ["192.168.1.200", "192.168.1.201", "192.168.1.202"]
    disks                = [ {
                vdisklabel = "server1-disk16"
                vdisksize = "20"
                vdisknumber = "10"
                vdatastore = "datastore1"
                },
                {
                vdisklabel = "server2-disk30"
                vdisksize = "20"
                vdisknumber = "30"
                vdatastore = "datastore2"
                },
                   ]
}
}

variables.tf

variable "vsphere_user" {}
variable "vsphere_password" {}
variable "vsphere_server" {}
variable "vsphere_unverified_ssl" {}
variable "compute_cluster" {}
variable "datacenter" {}
variable "site" {}
variable "change" {}
variable "virtual_machines" {}

On VM folder (this is the module)

data.tf

locals{
  vds = var.site == "US" ? "vds_001" : "vds_002"
  hostesx = var.site == "US" ? "192.168.10.103" : "192.168.10.104"
  vmgroup = var.site == "US" ? "RheLicenseVM" : "RheLicenseVM"
  template = var.site == "US" ? "MicroOS-Temp" : "RHEL8_ZH_template"

  virtm = { for_each = var.virtual_machines}

  flat_sandboxes = {
    for sandbox in var.virtual_machines :
    sandbox.system_name => sandbox
  }

  network_subnets = flatten([
    for network_key, network in var.virtual_machines : [
      for subnet in network.disks : {
        network_key       = network_key
        purpose           = subnet.vdatastore
        namedisk          = subnet.vdisklabel
        sizedisk          = subnet.vdisksize
        numberdisk        = subnet.vdisknumber
      }
    ]
  ])

}


data "vsphere_datacenter" "datacenter" {
  name = var.datacenter
}

data "vsphere_resource_pool" "pool" {
  for_each = var.virtual_machines

  name          = each.value.rspool
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_virtual_machine" "template" {
  name          = "MicroOS-Temp"
  datacenter_id = data.vsphere_datacenter.datacenter.id
}


data "vsphere_datastore" "datastore" {
  for_each = var.virtual_machines

  name          = each.value.datastore
  datacenter_id = data.vsphere_datacenter.datacenter.id
}


data "vsphere_datastore" "datastore2" {
  for_each = {
      #for ns in local.network_subnets: ns.purpose => ns
       for index, ns in local.network_subnets : index => ns 
    }

  name          = each.value.purpose
  datacenter_id = data.vsphere_datacenter.datacenter.id
}


data "vsphere_datastore" "datastore_a" {
  for_each = var.virtual_machines
  name          = each.value.datastore_a
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_datastore" "datastore_b" {
  for_each = var.virtual_machines

  name          = each.value.datastore_b
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_network" "network_interface" {
  for_each = var.virtual_machines

  name          = each.value.network_interface
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

data "vsphere_host" "host" {
  name          = local.hostesx
  datacenter_id = data.vsphere_datacenter.datacenter.id
}

instance.tf

resource "vsphere_virtual_machine" "vm" {
  for_each = var.virtual_machines

  name             = each.key
  resource_pool_id = "${data.vsphere_host.host.resource_pool_id}"

  guest_id  = data.vsphere_virtual_machine.template.guest_id
  scsi_type = data.vsphere_virtual_machine.template.scsi_type

  num_cpus = each.value.system_cores

  memory = each.value.system_memory

  host_system_id       = data.vsphere_host.host.id

  annotation = each.value.vmnotes
  firmware = "efi"
  sync_time_with_host = true

  cpu_hot_add_enabled = true

  memory_hot_add_enabled = true

  datastore_id       = data.vsphere_datastore.datastore[each.key].id
  folder   = each.value.folder


  wait_for_guest_ip_timeout  = 0
  wait_for_guest_net_timeout = 0


  scsi_controller_count = 4

  #Network
  network_interface {
    network_id   = data.vsphere_network.network_interface[each.key].id
    adapter_type = data.vsphere_virtual_machine.template.network_interface_types[0]
  }

  disk {
    label = "disk0"
    size  = each.value.system_disk
    eagerly_scrub    = false
    thin_provisioned = true
    #unit_number = 0
  }


dynamic "disk" {
    for_each = each.value.disks
    content {
      label = disk.key
      size = disk.value.vdisksize
      unit_number = disk.value.vdisknumber 
      datastore_id = disk.value.vdatastore
    }
  }

  #cloning from template
  clone {
    template_uuid = data.vsphere_virtual_machine.template.id

customize {
      linux_options {

        host_name = each.value.system_name
        domain    = each.value.system_domain

      }


      network_interface {
        ipv4_address = each.value.system_ipv4_address
        ipv4_netmask = each.value.system_ipv4_netmask
      }

      ipv4_gateway = each.value.system_ipv4_gateway
      dns_server_list = each.value.dns_server_list
    }

  }

}

resource "local_file" "change" {
  content = var.change
  filename = "${path.module}/change"
}

providers.tf

terraform {
  required_providers {
    vsphere = {
      source  = "hashicorp/vsphere"
    }
  }
  required_version = ">= 1.1.0"
}

provider "vsphere" {
  user                 = var.vsphere_user
  password             = var.vsphere_password
  vsphere_server       = var.vsphere_server
  allow_unverified_ssl = var.vsphere_unverified_ssl
}

variable.tf

variable "vsphere_user" {
  type        = string
  description = "User that connects to the vCenter."
  default     = "admin"
  sensitive   = true
}

variable "vsphere_password" {
  type        = string
  description = "Password of the user that connects to the vCenter."
  default     = "admin"
  sensitive   = true
}

variable "vsphere_server" {
  type        = string
  description = "vCenter URL."
  default     = "https://localhost"
}

variable "change" {
  type        = string
  description = "change"
  default     = ""
}



variable "vsphere_unverified_ssl" {
  type        = bool
  description = "Disable verification of vCenter server HTTPS certificate."
  default     = false
}


variable "compute_cluster" {
  type        = string
  description = "Cluster where to provision the servers of the group."
  default     = ""
}

variable "resource_pool" {
  type        = string
  description = "Cluster where to provision the servers of the group."
  default     = ""
}

variable "datacenter" {
  type        = string
  description = "Datacenter where to provision the servers of the group."
  default     = ""
}

variable "vds" {
  type        = string
  description = "select os option"
  default     = "vds"
}

variable "site" {}


variable "virtual_machines" {
  type = map(object({
    system_cores         = number
    system_memory        = number
    system_disk          = number
    system_ipv4_address  = string
    system_ipv4_netmask  = string
    system_ipv4_gateway  = string
    rspool               = string
    category             = string
    datastore            = string
    datastore_a          = string
    datastore_b          = string
    folder               = string
    compute_cluster      = string
    network_interface    = string
    vmnotes             = string
    system_name          = string
    system_domain        = string
    dns_server_list       = list(string)
    disks = list(object({
            vdisklabel=string
            vdisksize=number
            vdisknumber=number
            vdatastore=string}))
  }))

I hope to help me because i don’t understand where is my problem… :frowning:

Thx a lot :slight_smile:

Omar

4 posts - 2 participants

Read full topic

Help fix replace

$
0
0

hello, sorry but I’m noob about terraform
I’m using
source = “hashicorp/aws”
version = “~> 5.0”

I have this code:
family = contains(var.engine, “-cdb-”) ? replace(var.engine, “-cdb-”, “”) : lookup([for sg in var.database_parameters : sg if sg.fullname == var.engine][0], “family”, “”)

the idea is if var.engine contains word “-cdb-” then use whatever is in var.engine but remove word “-cdb-” from it, if does not contains word “-cdb-” then use this:
lookup([for sg in var.database_parameters : sg if sg.fullname == var.engine][0],“family”,“”)
example: var.cluster=postgres16 then family=postgresql16
another one, var.cluster=oracle-ee-cdb-19 then family=oracle-ee-19
but I’m getting this error:
│ Error: Error in function call

│ on paramgroup.tf line 46, in resource “aws_db_parameter_group” “rds_instance_parameter_group”:
│ 46: family = contains(var.engine, “-cdb-”) ? replace(var.engine, “-cdb-”, “”) : lookup([for sg in var.database_parameters : sg if sg.fullname == var.engine][0], “family”, “”)
│ ├────────────────
│ │ while calling contains(list, value)
│ │ var.engine is “oracle-ee-cdb-19”

│ Call to function “contains” failed: argument must be list, tuple, or set.

and to be honest I tried a lot of ways but still not working, if anyone know I really appreciate… thanks!

1 post - 1 participant

Read full topic

Viewing all 11407 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>