Validating input variables using JSON syntax

I’m trying to create a condition for validating an input variable in a file named variables.tf.json. The condition is to use regex to make sure an input IP address is made up of 4 octets of 1-3 digits each (I didn’t want to go as far as verifying each octet is between 0-255, at least not yet). The relevant portion looks like this:

variables.tf.json

{
    "variable" : {
        "ipv4_address" : {
            "description" : "IPv4 address to assign to network interface.",
            "type" : "string",
            "validation"  : {
                "condition" : "${can(regex(\"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\", var.ipv4_address))}",
                "error_message" : "The IP address is not properly formed."
            }
        }
    }
}

The error message returned is

╷
│ Error: Invalid variable validation condition
│
│   on variables.tf.json line 39, in variable.ipv4_address.validation:
│   39:                 "condition"     : "${can(regex(\"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\", var.ipv4_address))}",
│
│ The condition for variable "ipv4_address" must refer to var.ipv4_address in order to test incoming values.
╵

I have a condition on another variable which DOES work:

"condition" : "${contains([\"server\", \"workstation\"], var.os_type)}",

I suspect it may have something to do with the nested can(regex()) function calls in the first condition not being interpreted correctly, since the working condition only has one function call to contains().

I have tried enclosing var.ipv4_address in a nested ${ } interpolation, as well as enclosing the entire call to regex() in ${ }, but with no luck.

How can I correct the syntax to allow what I’m trying to accomplish? Or, if I’m making a dumb mistake, can someone kindly point out where I made the mistake? Thanks!

I managed to get it working. I ran the following using terraform console:

jsonencode("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")

which returned:

"\"\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\""

The working validation condition now looks like:

"condition" : "${can(regex(\"\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\", var.ipv4_address))}",

Heck of a lot of backslashes, but it was a learning experience nonetheless.

An alternative means to create the same condition:
condition= can(cidrsubnet("${var.ipv4_address}/32",0,0))

Hi @howardj99,

Indeed, one downside of the JSON syntax variant is that it is constrained by JSON string syntax and it happens to use the same escaping character as Terraform’s expression language does, which in turn is the same escaping character that regular expression syntax uses, and so you can end up needing multiple levels of escaping in some extreme cases like this.

The Terraform JSON syntax variant is intended primarily for situations where the files are being generated programmatically, rather than hand-written. In that case, you can at least delegate one level of escaping to the JSON encoding library in whatever language you are using to generate the JSON, and then only need to worry about the escaping that would normally be needed in a Terraform string template in the native syntax.