簡體   English   中英

將 map[string]interface{} 類型的 terraform resourceData 轉換為 struct

[英]Convert terraform resourceData of type map[string]interface{} to struct

我正在創建一個自定義 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類型。

有沒有人在處理這種情況時有相同的經驗? 任何幫助或建議表示贊賞。 謝謝!

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 的對象,返回一個可以使用d.Set分配給該屬性的map[string]interface{}


然而,僅僅因為 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)

由於 SDKv2 中的schema.ResourceData抽象保證根據您定義的架構返回特定的數據類型,因此只要您的架構和目標類型匹配,您通常不會從mapstructure.Decode中得到錯誤,但檢查一下仍然是個好主意無論如何都會出錯,因為否則您的t值可能不會完全填充,從而導致下游的混亂行為。

這不是官方提供程序中使用的典型實現樣式,但是如果您發現這種樣式更方便或更易於維護,那么以這種方式編寫您的提供程序並沒有真正的危害。


或者,如果您尚未對 SDKv2 進行深入投資,那么您可能希望考慮使用Terraform 插件框架 除了圍繞現代 Terraform 的類型系統進行設計(而 SDKv2 是為 Terraform v0.11 及更早版本設計的),它還支持一種更像您的目標的編程風格,使用tfsdk.Plan.Gettfsdk.Plan.GetAttribute等方法tfsdk.Plan.GetAttribute可以直接解碼為適當形狀和適當標記的“正常”圍棋值。

我不能輕易地展示一個例子,因為它會假定一個提供者以完全不同的方式編寫,但希望你能從這兩個函數的簽名中看到它們是如何使用的。 Accessing State、Config 和 Plan中有更多評論和示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM