You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform:仅在变量设置时创建数据源的实现方案

Hetzner Terraform模块SSH密钥二选一配置问题

需求是实现两种SSH密钥使用方式:

  • 提供已有Hetzner SSH密钥的指纹,直接复用
  • 未提供指纹时,通过本地公钥路径创建新的SSH密钥

当前代码运行报错:

data.hcloud_ssh_key.existing: Reading...
╷
│ Error: please specify a id, a name, a fingerprint or a selector to lookup the sshkey
│
│ with data.hcloud_ssh_key.existing,
│ on main.tf line 11, in data "hcloud_ssh_key" "existing":
│ 11: data "hcloud_ssh_key" "existing" {

问题根源:无论ssh_key_existing_fingerprint是否为null,Terraform都会尝试执行data.hcloud_ssh_key.existing数据源读取操作,当指纹为空时,数据源缺少必要参数导致报错。


解决方案:条件化控制资源与数据源

通过Terraform的count参数,实现仅在满足条件时才创建/读取对应的资源或数据源:

1. 优化变量定义(可选)

给变量添加清晰描述和非空约束,避免歧义:

variable "ssh_key" {
  description = "本地SSH公钥路径,未提供已有密钥指纹时使用"
  type        = string
  default     = "~/.ssh/id_rsa.pub"
  nullable    = false
}

variable "ssh_key_existing_fingerprint" {
  description = "已存在于Hetzner的SSH密钥指纹,优先使用"
  type        = string
  default     = null
}

2. 修改main.tf实现条件化逻辑

# 仅当提供了已有密钥指纹时,才读取Hetzner上的密钥数据源
data "hcloud_ssh_key" "existing" {
  count         = var.ssh_key_existing_fingerprint != null ? 1 : 0
  fingerprint   = var.ssh_key_existing_fingerprint
}

# 仅当未提供已有密钥指纹时,才在Hetzner创建新的SSH密钥
resource "hcloud_ssh_key" "default" {
  count         = var.ssh_key_existing_fingerprint == null ? 1 : 0
  name          = "servers default ssh key"
  public_key    = file(var.ssh_key)
}

resource "hcloud_server" "server" {
  name          = var.server_name
  server_type   = var.server_flavor
  image         = var.server_image
  location      = var.server_location

  # 根据条件选择密钥ID:已有指纹存在则用数据源ID,否则用新创建的密钥ID
  ssh_keys = [
    var.ssh_key_existing_fingerprint != null 
    ? data.hcloud_ssh_key.existing[0].id 
    : hcloud_ssh_key.default[0].id
  ]
}

原理说明

  • count = 条件 ? 1 : 0:满足条件时创建1个资源实例,否则创建0个(即不执行该资源/数据源)
  • 引用资源时通过[0]索引访问,因为count为1时会生成列表形式的资源实例

额外优化:添加指纹格式验证(可选)

给ssh_key_existing_fingerprint添加格式校验,避免用户输入无效指纹:

variable "ssh_key_existing_fingerprint" {
  description = "已存在于Hetzner的SSH密钥指纹,优先使用"
  type        = string
  default     = null

  validation {
    condition     = can(regex("^[a-f0-9]{2}(:[a-f0-9]{2})+$", var.ssh_key_existing_fingerprint)) || var.ssh_key_existing_fingerprint == null
    error_message = "SSH密钥指纹格式无效,需符合aa:bb:cc:...的十六进制冒号分隔格式。"
  }
}

内容的提问来源于stack exchange,提问作者Michael Niemand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:00:03