
# 输入变量
输入变量可以理解为模块的参数，通过关键字 "variable" 进行声明。通过定义输入变量，您可以无需变更模块的源代码就能灵活修改配置。输入变量的值可以使用默认值，CLI 选项，环境变量等方式来设置。
#### 定义输入变量
按照约定，输入变量通常在名为 variables.tf 的文件中定义。输入变量通过关键字 "variable" 进行声明：
```
variable "image_id" {
  type        = string
  description = "image id of Ubuntu 1804"
}
variable "availability_zone_name" {
  type    = string
  default = "cn-north-1a"
}
```
variable 关键字后的标签是输入变量的名称，该名称在同一模块中的所有变量之间必须唯一。变量的名称可以是除保留关键字以外的任何有效的标识符。保留关键字包括：
```
source    version    providers    count    for_each    lifecycle    depends_on    locals
```
variable块中主要包括如下参数：
- type：指定变量的类型，默认为 string。
- description ：指定变量的描述信息，用于描述变量的用途。
- default：指定变量的默认值，存在默认值的变量可视为可选变量。
- validation块：指定变量的自定义验证规则。
如果未明确指定变量类型，则默认为 string。建议开发者显式指定变量类型，这样可以方便地提醒用户如何使用该模块，并允许Terraform在使用错误的类型后返回有用的错误信息。Terraform 输入变量支持的类型有：
- 基本类型：string，number，bool
- 复合类型：list(\<TYPE\>)，set(\<TYPE\>)，map(\<TYPE\>)
复合类型的变量定义如下：
```
variable "availability_zone_names" {
  type    = list(string)
  default = ["cn-north-1a"]
}
variable "docker_ports" {
  type = list(object({
    internal = number
    external = number
    protocol = string
  }))
  default = [{
    internal = 8300
    external = 8300
    protocol = "tcp"
  }]
}
```
#### 自定义验证规则
您可以使用 validation嵌套块为输入变量指定自定义验证规则，该特性在 Terraform 0.13.0之后的版本支持，例如：
```
variable "iam_user_password" {
    type        = string
    description = "The password for iam user to log in."
    validation {
      condition     = length(var.iam_user_password)>=8
      error_message = "The password is too short."
    }
}
```
其中，condition 参数是一个布尔表达式，您可以使用 can 函数来检测表达式是否会产生错误，例如：
```
variable "iam_user_name" {
    type        = string
    description = "This name is used for iam user to log in."
    validation {
      # regex(...) 如果匹配失败将返回错误
      condition     = can(regex("([a-zA-Z])", var.iam_user_name))
      error_message = "Incorrect user name. Please check whether it contains upper and lower case letters."
    }
}
```
如果condition 的结果为false，Terraform 将产生一条错误消息，其内容为 error_message 所定义的字符串。error_message 应该至少是一个完整的句子，以大写字母开头，以 "." 或者 "?" 结尾。
#### 引用输入变量
输入变量可以通过 var.\<变量名称\> 的形式访问，且只能在声明该变量的模块内访问：
```
# variables.tf
variable "vpc_cidr" {
  type        = string
  description = "the CIDR of VPC"
}
# main.tf
resource "huaweicloud_vpc" "vpc_example" {
```
#### 设置变量
通过如下方式可以设置输入变量：
- 通过命令行中 -var 选项指定
- 通过变量定义文件 (.tfvars)，在命令行中指定或自动加载
- 设置环境变量
#### 变量定义 (.tfvars) 文件
如果配置中使用了很多变量，建议使用变量定义文件来设置这些变量，然后通过 -var-file 选项指定该文件：
```
terraform apply -var-file="testing.tfvars"
```
变量定义文件的扩展名为 ".tfvars"，变量定义文件的语法与配置文件的语法相同，但仅用于指定变量名称：
```
vpc_name = "my_vpc"
vpc_cidr = "192.168.0.0/16"
availability_zone_names = [
    "cn-north-1a","cn-north-1c",
]
```
Terraform 还会自动加载特殊命名的变量定义文件：
- 文件名为 terraform.tfvars 或 terraform.tfvars.json 的文件
- 文件名称以 .auto.tfvars 或 .auto.tfvars.json 结尾的文件
对于以 .json 结尾的文件，需要使用 JSON对象表示：
```
{
    "vpc_name": "my_vpc"
    "availability_zone_names": ["cn-north-1a", "cn-north-1c"]
}
```
#### 变量定义优先级
您可以自由组合使用上述设置变量的方式。对于复合类型的变量，为了提高可读性并避免转义带来的问题，建议使用变量定义文件来设置。如果为同一个变量分配了多个值，Terraform 将使用最后一个值进行覆盖。Terraform 根据以下顺序加载变量 (根据顺序，后面的源优于前面的源)：
1. 环境变量
2. terraform.tfvars 或 terraform.tfvars.json 文件
3. \*.auto.tfvars 或 \*.auto.tfvars.json 文件
4. 命令行中的 -var 和 -var-file 选项
 
注：不能在单个源中为同一个变量分配多个值。
有关变量的更多信息，请参见Terraform的 [输入变量](https://www.terraform.io/docs/configuration/variables.html)文档。
