Update a null_resource

There is currently a bug with the azurerm frontdoor resource so I’m working around it using null_resource to call az cli scripts.

At the moment I’m working on the ability to create, update and delete a routing rule in front door. So far it looks something like this.

resource "null_resource" "frontdoor_routing_rule" {

    triggers = {

      "routingRuleName" = var.frontdoor_routing_rule_name

      "frontDoorName" = var.frontdoor_name

      "resourceGroup" = var.frontdoor_resource_group

    }

    provisioner "local-exec" {

      command = <<EOF

${path.module}/create_frontdoor_routing_rule.ps1

      EOF

      interpreter = ["pwsh", "-Command"]

    }

    provisioner "local-exec" {

      when = destroy

      command = <<EOF

az network front-door routing-rule delete `

--name  ${self.triggers.routingRuleName} `

--front-door-name ${self.triggers.frontDoorName} `

--resource-group ${self.triggers.resourceGroup}

EOF

      interpreter = ["pwsh", "-Command"]

    } 

}

The problem I’m having is - how do I update without destroying? If one of my triggers changes then it wants to destroy the resource and recreate it. I don’t want that. I want it to run the creation script again (The script can detect if the resource already exists and update the values instead). I cant remove the triggers either because destroy can only self reference.

Any ideas?

1 Like

Hi @Evilweebl,

Unfortunately what you want to do here is not within the capabilities of null_resource. That resource type doesn’t actually do anything itself: it just has some special logic in it to generate a “replace” action each time the triggers value changes. The behavior you’ve added to it with provisioners can therefore only respond to the create and destroy events that result from it; there is never any sense of “updating” a null_resource instance, and even if there were provisioners only run during create or destroy anyway.

I’m afraid I don’t have a good answer for what to do instead other than to wait for the bug that is blocking you to be fixed. :confounded: The best I can suggest is to remove the when = destroy provisioner altogether, which will then allow you to run the create-time provisioner each time the triggers value changes, but at the expense of having to manually delete the routing rule if you need to do that before the bug is fixed. From what you’ve described it sounds like updating is the more routine action than destroying, so hopefully that tradeoff is acceptable as a temporary workaround.

Hi @apparentlymart,

I appreciate the reply. I think I’ve also got to the point of realising there’s not much I can do. I did consider getting rid of the destroy but for now the recreate is somewhat acceptable while in a development environment and I can hope the bug is fixed before we get to production.

I dont know if this is the forum for a feature request but it feels like this could be solvable if there were 2 types of triggers to define. 1 set would run the current create/recreate command and the other set would run an update command.

Hi @Evilweebl,

The constraints with null_resource here come from the fact that this resource type doesn’t actually do anything itself, and it’s only serving as an artificial trigger to run some provisioners outside of their normal lifecycle.

However, it would in principle be possible to write a resource type which could get a result similar to what you’re describing. The key requirement would be that it be the resource type itself that is running the external commands, so there wouldn’t be any provisioners and the commands to run would instead be a part of the main configuration of the resource.

To make this a bit more real, it might look something like this:

resource "exec_command" "example" {
  update_on_change = {
    # values that, if changed, should cause the
    # update command to run
  }
  replace_on_change = {
    # values that, if changed, should cause the
    # resource to be planned for replacement,
    # and thus to run the create and delete
    # actions in an order determined by the
    # lifecycle settings.
  }

  create {
    command     = "${path.module}/create_frontdoor_routing_rule.ps1"
    interpreter = ["pwsh", "-Command"]
  }

  update {
    command     = "${path.module}/update_frontdoor_routing_rule.ps1"
    interpreter = ["pwsh", "-Command"]
  }

  delete {
    command     = "az network front-door routing-rule delete etc etc etc"
    interpreter = ["pwsh", "-Command"]
  }
}

Taking a look in Terraform Registry’s provider index, I see a few community providers that seem to have aims similar to this, though perhaps with slightly different design details than my hypothetical above:

I haven’t used any of these providers so I can’t recommend any of them in particular, but you might like to review them in more detail and see if any of them would be a good fit for your requirements.

1 Like

Thanks for your help,

I’ll be sure to take a look at the providers suggested.