为了账号安全,请及时绑定邮箱和手机立即绑定

将 map[string]interface{} 类型的 terraform

将 map[string]interface{} 类型的 terraform

Go
撒科打诨 2023-01-03 10:13:26
我正在创建自定义 Terraform 提供程序,我遇到了这个问题。我试图将一个schema.TypeList字段转换为一个结构,TypeList 看起来像这样:"template": {                Type:     schema.TypeList,                Required: true,                ForceNew: false,                Elem: &schema.Resource{                    Schema: map[string]*schema.Schema{                        "lists_test": {                            Type:     schema.TypeSet,                            Required: true,                            ForceNew: false,                            Elem: &schema.Schema{                                Type: schema.TypeString,                            },                        },                        "name_test": {                            Type:     schema.TypeString,                            Required: true,                            ForceNew: false,                        },},},我试图对齐的结构看起来像这样:type TestStruct struct {    NameTest string   `json:"name_test"`    ListsTests   []string `json:"lists_test"`}我尝试了几种解决方案,例如我尝试将其解组为 json。像下面这样的东西:template := d.Get("template").([]interface{})[0].(map[string]interface{})templateStr, err := json.Marshal(template)templateConverted := &TestStruct{}json.Unmarshal(template, templateConverted)但是,我收到一个错误json: unsupported type: SchemaSetFunc,这可能是因为它试图编组一个schema.Schema类型而不是 map[string]interface{} 类型,这让我感到困惑。我也尝试使用gohcl.DecodeBody但我放弃了这个想法,因为它的用法似乎更倾向于读取直接 tf 文件而不是*schema.ResourceData类型。有没有人有处理这种情况的相同经验?任何帮助或建议表示赞赏。谢谢!
查看完整描述

1 回答

?
冉冉说

TA贡献1877条经验 获得超1个赞

Terraform 的旧版 SDK (SDKv2) 并不是围绕解码成标记结构的范例而设计的,而是希望您使用d.Get并手动键入断言单个值,在您的情况下,这些值可能看起来像这样:


  raw := d.Get("template").([]interface{})[0].(map[string]interface{})

  t := &TestStruct{

      NameTest: raw["name_test"].(string),

      ListsTests: make([]string, len(raw["lists_test"].([]interface{})),

  }

  for i, itemRaw := range raw["lists_test"].([]interface{}) {

    t.ListsTests[i] = itemRaw.(string)

  }

大多数 Terraform 提供程序的惯用风格是为每个复杂类型的属性在单独的函数中编写这样的逻辑,其中每个属性返回目标平台 SDK 中适当类型的对象。通常还会有一个相反方向的匹配函数:从目标平台的 SDK 中给定一个对象,返回一个map[string]interface{}可以分配给该属性的d.Set.


然而,仅仅因为 SDK 中没有内置的东西来处理这个,并不意味着你不能使用其他库,这些库是更通用的实用程序,可用于任何 Go 程序。


一个示例库是github.com/mitchellh/mapstructure,它正是为您的目标而设计的:获取某种接口类型的值并尝试使用反射将其适合标记的结构类型。


如果你想使用那个库,那么你需要用mapstructure:,而不是json:那些来注释你的结构,然后将你的raw值传递给mapstructure.Decode函数:


  raw := d.Get("template").([]interface{})[0].(map[string]interface{})

  var t TestStruct

  err := mapstructure.Decode(raw, &t)

由于schema.ResourceDataSDKv2 中的抽象保证根据您定义的模式返回特定数据类型,因此mapstructure.Decode只要您的模式和目标类型匹配,您通常不会收到错误,但无论如何检查错误仍然是一个好主意,否则您的t价值可能没有完全填充,导致下游混乱的破坏行为。


这不是官方提供程序中使用的典型实现样式,但如果您发现这种样式更方便或更易于维护,那么以这种方式编写您的提供程序并没有什么真正的坏处。


或者,如果您还没有深入研究 SDKv2,那么您可能希望考虑改用Terraform 插件框架。除了围绕现代 Terraform 的类型系统设计(而 SDKv2 是为 Terraform v0.11 及更早版本设计的),它还支持一种更像您所追求的编程风格,使用诸如tfsdk.Plan.Get和之类的方法tfsdk.Plan.GetAttribute可以直接解码为适当形状和适当标记的“正常”Go 值。


我无法简单地展示一个例子,因为它会假定提供程序以完全不同的方式编写,但希望您可以从这两个函数的签名中看出它们的使用方式。在访问状态、配置和计划中有更多的评论和示例。


查看完整回答
反对 回复 2023-01-03
  • 1 回答
  • 0 关注
  • 112 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信