Введите утверждение для TypeList в провайдере terraform - PullRequest
1 голос
/ 13 января 2020

Я пишу провайдер Terraform и пытаюсь найти лучший способ сделать утверждение типа, когда у меня есть TypeList, содержащий элементы TypeString.

Resouce определяется следующим образом:

    return &schema.Resource{
        Create: resourceConfigObjectCreate,
        Read:   resourceConfigObjectRead,
        Update: resourceConfigObjectUpdate,
        Delete: resourceConfigObjectDelete,

        Schema: map[string]*schema.Schema{
            "name": &schema.Schema{
                Type:     schema.TypeString,
                Required: true,
            },
            "notification_options": &schema.Schema{
                Type:     schema.TypeList,
                Optional: true,
                Elem: schema.Schema{
                    Type:             schema.TypeString,
                },
            },
        },
    }
}

И я хотел бы загрузить эти значения в пользовательский тип, определенный следующим образом:

type ConfigObject struct {
    Name                        string   `json:"name,omitempty"`
    NotificationOptions         []string `json:"notification_options,omitempty"`

}

Поскольку schema.ResourceData.Get возвращает интерфейс {}, необходимо утверждение типа.

    item := thruk.ConfigObject{
        Name: schema.ResourceData.Get("name").(string),
        NotificationOptions: extractSliceOfStrings(schema.ResourceData.Get("notification_options")),
    }

Я сделал это легко для строки, но фрагмент строки был более сложным, и я создал следующую функцию:

func extractSliceOfStrings(i interface{}) (slice []string) {
    s := reflect.ValueOf(i)
    if !s.IsValid() {
        return
    }
    for i := 0; i < s.Len(); i++ {
        slice = append(slice, s.Index(i).String())
    }
    return
}

Это правильный подход?

1 Ответ

1 голос
/ 14 января 2020

При работе с ResourceData API в провайдере Terraform полезно знать, какой тип Go соответствует каждому из типов схем. Вы уже сделали вывод, что schema.TypeString соответствует string. Вот полный список:

  • TypeBoolbool
  • TypeStringstring
  • TypeIntint
  • TypeList[]interface{}
  • TypeMapmap[string]interface{}
  • TypeSet*schema.Set
  • Тип элемента при установке Elem *schema.Resource: map[string]interface{}

Переводы, приведенные выше, документированы на странице документации Типы схем для SDK, как "Структура данных:" под каждым из заголовков. .

Всякий раз, когда вы имеете дело с коллекцией, тип элемента с точки зрения Go всегда равен interface{}, что отражает тот факт, что тип элемента не определен до времени выполнения. Однако те же правила сопоставления, определенные выше, также применимы к этим значениям элемента, поэтому для преобразования TypeList, Elem которого равно TypeString, сначала необходимо установить тип среза, а затем по очереди каждый элемент:

itemsRaw := d.Get("example").([]interface{})
items := make([]string, len(itemsRaw))
for i, raw := range itemsRaw {
    items[i] = raw.(string)
}

К сожалению, нет способа go напрямую из []interface{} до []string за один шаг, из-за дизайна Go интерфейсов и утверждений типа.

Вы можете использовать аналогичный подход для TypeMap, если вам в конечном итоге понадобится map[string]string:

itemsRaw := d.Get("example").(map[string]interface{})
items := make(map[string]string, len(itemsRaw))
for k, raw := range itemsRaw {
    items[k] = raw.(string)
}

TypeSet немного сложнее из-за пользовательского контейнера *schema.Set, но вы можете вызвать List метод набора для получения []interface{}, который затем можно обработать так же, как с TypeList выше:

itemsRaw := d.Get("example").(*schema.Set).List()
items := make([]string, len(itemsRaw))
for i, raw := range itemsRaw {
    items[i] = raw.(string)
}
...