Terraform自定义提供商 - 数据源架构

发布于 2025-01-24 16:34:07 字数 1964 浏览 5 评论 0原文

我正在使用Terraform SDK创建自定义Terraform提供商。我正在尝试从现有API获取呼叫中读取数据。我发现很难将JSON响应从API映射到Terraform模式。这是我的数据源架构:

func dataSourceProjects() *schema.Resource {
  return &schema.Resource{
    ReadContext: dataSourceProjectsRead,
    Schema: map[string]*schema.Schema{
      "members": &schema.Schema{
        Type:     schema.TypeList,
        Elem:     &schema.Schema{Type: schema.TypeString},
        Computed: true,
      },
      "owners": &schema.Schema{
        Type:     schema.TypeList,
        Elem:     &schema.Schema{Type: schema.TypeString},
        Computed: true,
      },
    },
  }
}

这是API JSON响应:

{
  "members": [
    "test12",
    "test8800",
    "test0032",
    "test1234"
  ],
  "owners": [
    "test000",
    "test111",
    "test12",
    "test1234"
  ]
}

这是我的数据源读取功能,

func dataSourceProjectsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {

  client := &http.Client{Timeout: 10 * time.Second}

  // Warning or errors can be collected in a slice type
  var diags diag.Diagnostics

  req, err := http.NewRequest("GET", fmt.Sprintf("%s/test/team", "https://myurl/v1"), nil)
  req.Header.Add("Authorization", "Bearer xxxxx")
  if err != nil {
    return diag.FromErr(err)
  }

  r, err := client.Do(req)
  if err != nil {
    return diag.FromErr(err)
  }
  defer r.Body.Close()
  members := make([]string, 0)
  err = json.NewDecoder(r.Body).Decode(&members)
  if err != nil {
    return diag.FromErr(err)
  }

  if err := d.Set("members", members); err != nil {
    return diag.FromErr(err)
  }

  // always run
  d.SetId(strconv.FormatInt(time.Now().Unix(), 10))

  return diags
}

我一直遇到此错误:

错误:JSON:无法将type []字符串

的GO值汇总到GO值中

I am working on creating a custom terraform provider by using terraform sdk. I am trying to read data from the existing API GET call. I am finding it difficult to map the JSON response from an API to terraform schema. This is my data source schema:

func dataSourceProjects() *schema.Resource {
  return &schema.Resource{
    ReadContext: dataSourceProjectsRead,
    Schema: map[string]*schema.Schema{
      "members": &schema.Schema{
        Type:     schema.TypeList,
        Elem:     &schema.Schema{Type: schema.TypeString},
        Computed: true,
      },
      "owners": &schema.Schema{
        Type:     schema.TypeList,
        Elem:     &schema.Schema{Type: schema.TypeString},
        Computed: true,
      },
    },
  }
}

This is the API JSON response:

{
  "members": [
    "test12",
    "test8800",
    "test0032",
    "test1234"
  ],
  "owners": [
    "test000",
    "test111",
    "test12",
    "test1234"
  ]
}

This is my Data source read function

func dataSourceProjectsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {

  client := &http.Client{Timeout: 10 * time.Second}

  // Warning or errors can be collected in a slice type
  var diags diag.Diagnostics

  req, err := http.NewRequest("GET", fmt.Sprintf("%s/test/team", "https://myurl/v1"), nil)
  req.Header.Add("Authorization", "Bearer xxxxx")
  if err != nil {
    return diag.FromErr(err)
  }

  r, err := client.Do(req)
  if err != nil {
    return diag.FromErr(err)
  }
  defer r.Body.Close()
  members := make([]string, 0)
  err = json.NewDecoder(r.Body).Decode(&members)
  if err != nil {
    return diag.FromErr(err)
  }

  if err := d.Set("members", members); err != nil {
    return diag.FromErr(err)
  }

  // always run
  d.SetId(strconv.FormatInt(time.Now().Unix(), 10))

  return diags
}

I keep getting this error:

Error: json: cannot unmarshal object into Go value of type []string

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

新一帅帅 2025-01-31 16:34:07

server.go

package main

import (
    "log"
    "net/http"
)

func main() {
    s := `
    {
      "members": [
        "test12",
        "test8800",
        "test0032",
        "test1234"
      ],
      "owners": [
        "test000",
        "test111",
        "test12",
        "test1234"
      ]
    }
    `

    http.HandleFunc("/projects", func(w http.ResponseWriter, _ *http.Request) {
      log.Println("Getting Projects")
      w.WriteHeader(http.StatusOK)
      w.Write([]byte(s))
    })

    log.Println("Listening...")
    log.Fatal(http.ListenAndServe(":8000", nil))
}

data_source_projects.go

package hashicups

import (
    "context"
    "encoding/json"
    "fmt"
    "net/http"
    "strconv"
    "time"

    "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
    "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceProjects() *schema.Resource {
  return &schema.Resource{
    ReadContext: dataSourceProjectsRead,
    Schema: map[string]*schema.Schema{
      "members": &schema.Schema{
        Type:     schema.TypeList,
        Elem:     &schema.Schema{Type: schema.TypeString},
        Computed: true,
      },
      "owners": &schema.Schema{
        Type:     schema.TypeList,
        Elem:     &schema.Schema{Type: schema.TypeString},
        Computed: true,
      },
    },
  }
}

func dataSourceProjectsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
    client := &http.Client{Timeout: 10 * time.Second}

    // Warning or errors can be collected in a slice type
    var diags diag.Diagnostics

    req, err := http.NewRequest("GET", fmt.Sprintf("%s/projects", "http://localhost:8000"), nil)
    if err != nil {
        return diag.FromErr(err)
    }

    r, err := client.Do(req)
    if err != nil {
        return diag.FromErr(err)
    }
    defer r.Body.Close()

    var projects map[string]interface{}
    err = json.NewDecoder(r.Body).Decode(&projects)
    if err != nil {
        return diag.FromErr(err)
    }

    if err := d.Set("members", projects["members"]); err != nil {
        return diag.FromErr(err)
    }

    if err := d.Set("owners", projects["owners"]); err != nil {
        return diag.FromErr(err)
    }

    // always run
    d.SetId(strconv.FormatInt(time.Now().Unix(), 10))

    return diags
}

输出:

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes


Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

project = {
  "id" = "1651575329"
  "members" = tolist([
    "test12",
    "test8800",
    "test0032",
    "test1234",
  ])
  "owners" = tolist([
    "test000",
    "test111",
    "test12",
    "test1234",
  ])
}

server.go

package main

import (
    "log"
    "net/http"
)

func main() {
    s := `
    {
      "members": [
        "test12",
        "test8800",
        "test0032",
        "test1234"
      ],
      "owners": [
        "test000",
        "test111",
        "test12",
        "test1234"
      ]
    }
    `

    http.HandleFunc("/projects", func(w http.ResponseWriter, _ *http.Request) {
      log.Println("Getting Projects")
      w.WriteHeader(http.StatusOK)
      w.Write([]byte(s))
    })

    log.Println("Listening...")
    log.Fatal(http.ListenAndServe(":8000", nil))
}

data_source_projects.go

package hashicups

import (
    "context"
    "encoding/json"
    "fmt"
    "net/http"
    "strconv"
    "time"

    "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
    "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceProjects() *schema.Resource {
  return &schema.Resource{
    ReadContext: dataSourceProjectsRead,
    Schema: map[string]*schema.Schema{
      "members": &schema.Schema{
        Type:     schema.TypeList,
        Elem:     &schema.Schema{Type: schema.TypeString},
        Computed: true,
      },
      "owners": &schema.Schema{
        Type:     schema.TypeList,
        Elem:     &schema.Schema{Type: schema.TypeString},
        Computed: true,
      },
    },
  }
}

func dataSourceProjectsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
    client := &http.Client{Timeout: 10 * time.Second}

    // Warning or errors can be collected in a slice type
    var diags diag.Diagnostics

    req, err := http.NewRequest("GET", fmt.Sprintf("%s/projects", "http://localhost:8000"), nil)
    if err != nil {
        return diag.FromErr(err)
    }

    r, err := client.Do(req)
    if err != nil {
        return diag.FromErr(err)
    }
    defer r.Body.Close()

    var projects map[string]interface{}
    err = json.NewDecoder(r.Body).Decode(&projects)
    if err != nil {
        return diag.FromErr(err)
    }

    if err := d.Set("members", projects["members"]); err != nil {
        return diag.FromErr(err)
    }

    if err := d.Set("owners", projects["owners"]); err != nil {
        return diag.FromErr(err)
    }

    // always run
    d.SetId(strconv.FormatInt(time.Now().Unix(), 10))

    return diags
}

Output:

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes


Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

project = {
  "id" = "1651575329"
  "members" = tolist([
    "test12",
    "test8800",
    "test0032",
    "test1234",
  ])
  "owners" = tolist([
    "test000",
    "test111",
    "test12",
    "test1234",
  ])
}
星星的轨迹 2025-01-31 16:34:07

正如马特(Matt)和错误代码所提到的那样,您正在尝试将身体勾勒出不适当的结构。

基本上,您的体内没有数组,您的对象具有带有一系列字符串的字段。

您的拆卸方式将适用于诸如

["test12", "test23", "test34"]

试图按照下面进行解码之类的身体,因此请使用具有显式映射的结构。

package main

import (
    "encoding/json"
    "fmt"
)

type Schema struct {
    Members []string `json:"members"`
    Owners  []string `json:"owners"`
}

var jsonBody = `{
  "members": [
    "test12",
    "test8800",
    "test0032",
    "test1234"
  ],
  "owners": [
    "test000",
    "test111",
    "test12",
    "test1234"
  ]
}`

func main() {
    var s Schema
    err := json.Unmarshal([]byte(jsonBody), &s)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(s)
    }

}

Just as Matt and the error code mentioned, you're trying to unmarshal your body to an improper struct.

Basically, you don't have an array in the Body, you have an object with fields that have an array of strings.

Your way of unmarshalling would work for bodies like

["test12", "test23", "test34"]

Try to decode it as below, so use a struct with explicit mapping.

package main

import (
    "encoding/json"
    "fmt"
)

type Schema struct {
    Members []string `json:"members"`
    Owners  []string `json:"owners"`
}

var jsonBody = `{
  "members": [
    "test12",
    "test8800",
    "test0032",
    "test1234"
  ],
  "owners": [
    "test000",
    "test111",
    "test12",
    "test1234"
  ]
}`

func main() {
    var s Schema
    err := json.Unmarshal([]byte(jsonBody), &s)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(s)
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文