skip to Main Content

I am setting up variable validation for Kafka topic schemas for a Terraform module I am creating.

The schemas can be one of two types: AVRO or JSON. As both schema types are defined in a .json file, I use a variable called scheama_format to determine what type the incoming schema is. The schema itself is provided by a variable called schema_path, pointing to a .json file.

When evaluating if the file given by schema_path is valid, I have to know what type of file it is to know what keys I must check. I have tried many variations, but my current validation condition looks like this:

variable "schema_path" {
  type             = string
  description      = "Relative path to the schema file to upload to the Schema Registry."

  ...

  ###################
  # THIS IS THE VALIDATION THAT IS NOT WORKING
  ###################
  validation {
    conditions     = (var.schema_format != "AVRO") || (jsondecode(file(var.schema_path)).type == "record")
    error_message  = "If schema_format is 'AVRO', the schema file must have a type of 'record'."
  }
}

variable "schema_format" {
  type             = string
  description      = "The type of schema. Must be either 'JSON' or 'AVRO'."
  
  ...
}

No matter what I do, whenever a validation condition includes the value of a different variable, the condition will evaluate as true (and thus the validation will never trigger an error).

Is this a bug in Terraform, or is there something I am missing here?

I have tried en exhaustive number of conditions using a different variable and they all evaluate as true.

Even simple conditions such as:

variable "schema_path" {
  ...

  validation {
    conditions     = (length(var.schema_format) < 0) || (length(var.schema_path) < 0)
    error_message  = "TEST"
  }
}

variable "schema_format" {
  ...
}

To my mind, this condition should evaluate as false no matter what, but it evaluates as true.

If I try:

variable "schema_path" {
  ...

  validation {
    conditions     = false || (length(var.schema_path) < 0)
    error_message  = "TEST"
  }
}

variable "schema_format" {
  ...
}

the condition evaluates as false, but as soon as I use a different variable as part of the condition, it evaluates as true.

If this is the intended behaviour, I do not understand the point of Terraform version 1.9.0 allowing the use of different variables as part of a variable’s validation. What am I missing?

EDIT:

For context, this is what a generic version of the schema file:

{
  "type": "record",
  "namespace": "com.mycorp.mynamespace",
  "name": "sampleRecord",
  "doc": "Sample schema to help you get started.",
  "fields": [
    ...
  ]
}

2

Answers


  1. Chosen as BEST ANSWER

    After digging around some more, I ended up adding a lifecycle precondition to my schema resource.

    locals {
      schema     = file(var.schema_path)
      schemaJson = jsondecode(local.schema)
    }
    resource "confluent_schema" "schema" {
      depends_on   = [confluent_kafka_topic.topic]
      subject_name = "${confluent_kafka_topic.topic.topic_name}-value"
      format       = var.schema_format
      schema       = local.schema
    
    
      lifecycle {
        precondition {
          condition     = var.schema_format != "AVRO" || jsondecode(local.schema).type == "record"
          error_message = "Schema must be a valid AVRO schema. Key 'Type' must have value 'record'"
        }
      }
    }
    

    Using a precondition means that an error will be thrown if the condition is not met. Unfortunatley, this block will only run during terraform plan and terraform apply, meaning that terraform validate will no longer run all the validation logic.


    This is a workaround that will be fine for my use case, but the central question still stands:

    Why does using other variables in a variable's validate block cause the condition to always evaluate to true?

    I feel like I am still missing something. Either this is a bug in Terraform or I am missing something with how this functionality is intended to be used.


  2. Add a validation block to the schema_format variable and then use a check block to validate the variable against the json file:

    variable "schema_path" {
      type        = string
      description = "Relative path to the schema file to upload to the Schema Registry."
    }
    
    variable "schema_format" {
      type = string
      validation {
        condition     = contains(["AVRO", "JSON"], var.schema_format)
        error_message = "The type of schema. Must be either 'JSON' or 'AVRO'."
      }
    
    }
    
    check "validate_schema" {
      assert {
        condition     = var.schema_format == "AVRO" && (jsondecode(file(var.schema_path)).type == "record")
        error_message = "If schema_format is 'AVRO', the schema file must have a type of 'record'."
      }
    }
    

    Alternatively if you want to error out then you can use an external data source (requires jq):

    data "external" "loki_config_validation" {
      program = ["bash", "-c", <<-EOF
        if [ "${var.schema_format}" == "AVRO" ]; then
          jq -e -r 'if (.type != "record") then "If schema_format is 'AVRO', the schema file must have a type of 'record'.n"| halt_error(1) end' ${var.schema_path}
        else 
          jq -r -n '{}'; 
        fi
        EOF
      ]
    }
    
    variable "schema_path" {
      type        = string
      description = "Relative path to the schema file to upload to the Schema Registry."
    }
    
    variable "schema_format" {
      type = string
      validation {
        condition     = contains(["AVRO", "JSON"], var.schema_format)
        error_message = "The type of schema. Must be either 'JSON' or 'AVRO'."
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search