Search code examples
terraformhcl

Equal attribution of value to objects with Terraform


I would like your technical advice on the way to achieve a specific variable attribution with Terraform. Regardless of the context, I have n objects to which I would like to attribute a value between [1-3] so that the values are equally distributed (whether it is in a sequential or random way does not really matter).

To be more explicit here are the two ways I thought of :

  1. randomly selects starting value (1 or 2 or 3)
  2. selects the next index (if 2 were to be selected as starting value, 3 would be selected next)
  3. if there are 4 or more objects on total the loop should start over and over as long as there are remaining objects

OR

  1. randomly selects starting value (1 or 2 or 3)
  2. selects randomly any of the remaining value
  3. if there are 4 or more objects on total, randoms values would be selected so the global distribution would be equal

I can easily achieve the first step with the random provider, but I have no clue on how to proceed for the other steps. I mean I know how to increment a value, but how to proceed when the value is 3 and I want to start the loop over and come back to value 1 ? Or how to randomly select values between remaining ones ?


Solution

  • sequential

    You mentioned that the way doesn't really matter... I think in a sequential way is simpler, using range and a loop with a math trick (i % 3) + 1 to get the value between [1-3] like you want

    variable "objects" {
      default = 12
    }
    
    locals {
        distrib = [ for i in range(var.objects) : (i % 3) + 1 ]
    }
    
    output "test" {
        value = local.distrib
    }
    

    a terraform plan on that:

    Changes to Outputs:
      + test = [
          + 1,
          + 2,
          + 3,
          + 1,
          + 2,
          + 3,
          + 1,
          + 2,
          + 3,
          + 1,
          + 2,
          + 3,
        ]
    

    sequential with random start

    We can do a random start with the help of the random_integer resource and using the start and limit parameters in the range function

    variable "objects" {
      default = 12
    }
    
    resource "random_integer" "extra" {
      min = 0
      max = 2
    }
    
    locals {
      start   = random_integer.extra.result
      distrib = [for i in range(local.start, var.objects + local.start) : (i % 3) + 1]
    }
    
    output "test" {
      value = local.distrib
    }
    

    random

    Randomization is also possible using the random_shuffle resource:
    https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/shuffle

    variable "objects" {
      default = 12
    }
    
    locals {
        distrib = [ for i in range(var.objects) : (i % 3) + 1 ]
    }
    
    resource "random_shuffle" "random" {
      input        = local.distrib
      result_count = var.objects
    }
    
    output "test" {
        value = random_shuffle.random.result
    }
    

    and a terraform apply on that:

    Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
    
    Outputs:
    
    test = tolist([
      "3",
      "1",
      "3",
      "2",
      "2",
      "3",
      "1",
      "1",
      "2",
      "2",
      "1",
      "3",
    ])
    

    more complex


    We can also use other values instead of [1-3] see sample below using colors

    variable "objects" {
      default = 9
    }
    
    variable "items" {
      default = ["red", "blue", "cyan"]
    }
    
    locals {
      distrib = [for i in range(var.objects) : element(var.items, (i % length(var.items)))]
    }
    
    resource "random_shuffle" "random" {
      input        = local.distrib
      result_count = var.objects
    }
    
    output "test" {
      value = random_shuffle.random.result
    }