Azure Terraform external数据源异常报错及函数密钥获取咨询
问题分析与解决方案
一、异常原因解析
1. 首次执行报错:"JSON输入意外结束"
脚本未输出任何合法JSON内容导致的。函数应用刚部署完成时,函数的密钥还未完成生成,脚本循环30次后仍未获取到有效密钥,最终没有输出任何JSON,Terraform解析空输出时触发该错误。
2. 第二次执行报错:"顶层值后出现无效字符'{' "
添加az login和订阅切换命令后,Azure CLI会输出登录验证、订阅切换的额外信息(比如登录成功的JSON响应、订阅切换提示文本),这些内容和脚本最终输出的密钥JSON混合在一起,导致整体输出不是单一的合法JSON对象。Terraform要求外部数据源的输出必须是唯一的顶层JSON对象,混杂的输出触发了解析错误。
3. 第三次执行无报错
第三次恢复原脚本时,函数应用已经完成部署流程,密钥已生成就绪,脚本能在循环内快速获取到密钥并输出合法JSON,Terraform可以正常解析,因此没有报错。
二、替代获取函数密钥的方案
方案1:使用AzureRM原生数据源(推荐)
从AzureRM Provider 3.x版本开始,支持直接通过数据源获取函数密钥,无需依赖外部脚本,稳定性和可靠性更高:
获取指定函数的密钥(对应你的httptrigger)
data "azurerm_function_app_function_keys" "httptrigger" { provider = azurerm.sub-fits-55070-dev-01 function_app_id = module.function_app_zis.function_app_id function_name = "httptrigger" depends_on = [module.function_app_zis] } # 使用示例:data.azurerm_function_app_function_keys.httptrigger.default_key
获取函数应用主机级密钥(若需全局密钥)
data "azurerm_function_app_host_keys" "this" { provider = azurerm.sub-fits-55070-dev-01 function_app_id = module.function_app_zis.function_app_id depends_on = [module.function_app_zis] } # 使用示例:data.azurerm_function_app_host_keys.this.default_function_key
方案2:优化现有Shell脚本(若必须保留脚本方式)
如果因特殊场景需要保留外部脚本,需解决输出纯净度和超时问题:
- 屏蔽Azure CLI的所有无关输出,仅保留最终JSON
- 增加超时后的错误输出,避免空输出
- 从Terraform传递参数,避免脚本硬编码资源信息
优化后的脚本示例:
#!/bin/bash # 接收Terraform传递的参数 APP_NAME="$1" RESOURCE_GROUP="$2" SUBSCRIPTION="$3" FUNCTION_NAME="$4" # 循环尝试获取密钥,屏蔽CLI无关输出 for i in {1..30}; do FUNCTION_KEY=$(az functionapp function keys list --subscription "$SUBSCRIPTION" --resource-group "$RESOURCE_GROUP" --name "$APP_NAME" --function-name "$FUNCTION_NAME" --query default --output tsv 2>/dev/null) if [ -n "$FUNCTION_KEY" ]; then echo "{\"function_key\": \"$FUNCTION_KEY\"}" exit 0 fi sleep 2 done # 超时后输出错误JSON,避免空输出 echo "{\"error\": \"超时未获取到函数密钥\"}" exit 1
对应的Terraform external数据源修改:
data "external" "function_key" { program = ["bash", "${path.module}/get_function_key.sh", module.function_app_zis.function_app_name, module.function_app_zis.resource_group_name, "sub-fits-55070-dev-01", "httptrigger"] count = module.function_app_zis.function_app_name != "" ? 1 : 0 depends_on = [module.function_app_zis] }
三、总结
优先选择AzureRM原生数据源方案,完全基于Terraform生态,避免外部脚本的不确定性;若必须使用脚本,务必保证输出纯净且包含超时处理逻辑。
内容的提问来源于stack exchange,提问作者Odelys
相关产品推荐
相关产品推荐

