0
votes

When I use count or for_each in my resource definition, the resources are created in parallel. Is there a kind of workaround to make it sequential? First a resource with count.index=0 is created, then count.index=1, then count.index=2 e.t.c.

A little background... I'm using terraform for initial Hyperledger Fabric setup. For some tasks I need to do configuration updates of the blockchain network sequentially (like approving chaincode for participating organizations). Otherwise I get (MVCC_READ_CONFLICT). This can of course be achieved if I outsource this logic completely to some bash script but maybe...

2
I'm pretty sure there's no terraform feature for this, but when I googled MVCC_READ_CONFLICT to see if it meant what I thought it does I found there's various discussions of your particular scenario that may be helpful.T.H.

2 Answers

0
votes

It sounds to me you are looking for a way to create dependencies on various resources so they are deployed in the sequential manner you described. One way to achieve this within the resource block is using Terraforms meta-argument depends_on (Link below). This meta-argument does exactly as it sounds. It allows you to define within your resource (Resource A) the name of another resource in the same module (Resource B) to finish before executing. In other words, Resource A does not start until Resource B is done. I'm not certain of the behavior when used in conjunction with loops such as for_each and count

Note: Terraform recommends to use this as a last resort. Review their documentation for more details.

https://www.terraform.io/docs/configuration/resources.html#depends_on-explicit-resource-dependencies

0
votes

So to make things work one needs to store a kind of state elsewhere. The most simple thing is to use a file:

resource "null_resource" "set_initial_state" {
    provisioner "local-exec" {
        interpreter = ["bash", "-c"]
        command = "echo \"0\" > current_state.txt"
    }
}

The second resource implements a waiting loop in the beginning and state change in the end:

resource "null_resource" "sequential_resources" {
    count = var.x
    provisioner "local-exec" {
        interpreter = ["bash", "-c"]
        command = "while [[ $(cat current_state.txt) != \"${count.index}\" ]]; do echo \"${count.index} is waiting...\";sleep 5;done"
    }

# Here you pack your sequential logic, e.g. upload of files to a service, 
# that can handle only one file at once.

    provisioner "file" {
        connection {
                type     = "ssh"
                host     = var.ip_address
                private_key = file(var.config.private_key)
                user     = var.config.admin_username
                script_path = var.provisioner_script_path
        }
        source = "${var.local_folder}/file_${count.index}.txt"
        destination = "/opt/data/file_${count.index}.txt"
    }

    provisioner "local-exec" {
        interpreter = ["bash", "-c"]
        command = "echo \"${count.index+1}\" > current_state.txt"
    }

depends_on = [null_resource.set_initial_state]
}

In this example file_0.txt is uploaded first, then file_1.txt, then file_2.txt e.t.c. until file_x.txt