Контекст: я разрабатываю TF Provider и просматриваю руководство HashiCorp.
Я пытаюсь придумать определение ресурса и не могу понять, какое из них выбрать.
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"endpoint": {
Type: schema.TypeString,
Required: true,
},
},
resource "foo" "bar" {
name = "alex"
endpoint = "https://api.stripe.com" # unique for every bar
}
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"district_id": {
Type: schema.TypeString,
Required: true,
},
},
resource "foo" "bar" {
name = "alex"
district_id = "NE53DE" # unique for every bar
}
Преимущество № 1 заключается в том, что он следует API, и для выполнения операций CRUD TF Provider может взаимодействовать только с одной группой API (существует сопоставление 1: 1 между группой API и ресурсом).
Преимущество № 2 заключается в том, что он более удобочитаем, но для вызова группы API № 1 нам все равно нужно выяснить конечную точку, поэтому TF Provider должен вызвать группу API № 2 для получения этой конечной точки.
Какой из этих вариантов чаще используется при разработке TF Providers?
То, что вы обсуждаете здесь, к сожалению, является, вероятно, наиболее важной частью разработки провайдера Terraform: поиск компромиссов и суждений о том, как лучше всего преобразовать независимую от провайдера модель жизненного цикла Terraform в физические ограничения конкретного реального API.
Большим преимуществом тщательного следования дизайну удаленного API является то, что меньше вероятность того, что будущее расширение дизайна API сделает недействительным дизайн вашего провайдера. Это может быть особенно важно, если провайдер разрабатывается кем-то, кто не работает напрямую с командой, разрабатывающей API, поскольку разработчик провайдера обычно не может предсказать, как API может измениться в будущем и какие принципы проектирования будут использоваться. Команда разработчиков API обычно следует им при рассмотрении новых вариантов использования.
Однако, как вы заметили, реальные API-интерфейсы часто не предназначены для удобного прямого использования, а вместо этого предназначены для предоставления необработанных строительных блоков в предположении, что другие создадут подходящие абстракции конкретный вариант использования поверх них. Разработчик поставщика Terraform оказывается здесь в несколько затруднительном положении, потому что он обычно также пытается предоставить общее решение (нет ориентирован на конкретный вариант использования), но также хочет разработать что-то, что относительно удобно для использования в языке Terraform.
Я не могу дать конкретный совет из-за отсутствия достаточного контекста API, для которого вы разрабатываете, или ваших целей проектирования для провайдера, но я могу, по крайней мере, предложить потенциальную возможность для компромисса: источники данных.
Наряду с управляемыми типами ресурсов, которые представляют Terraform, непосредственно управляющим каким-либо объектом в удаленной системе, Terraform также поддерживает типы ресурсов данные (для краткости «источники данных»), которые появляются на языке Terraform как data
блоки. По сути, они моделируют внешние зависимости конкретного модуля, под которым я подразумеваю объекты, которые, как ожидается, модуль уже создал кем-то другим и которые модуль должен объявить объектами, которыми он будет управлять сам (его ресурсы удалось).
Если ваше сопоставление «идентификатора района» с «конечной точкой» можно в каком-то смысле представить как внешний объект, то источник данных может помочь заполнить этот пробел. Не беспокойтесь слишком сильно о том, действительно ли является является первоклассным объектом в удаленной системе; здесь важно то, разумно ли автору модуля Terraform думать о нем как об одном, чтобы он мог представить ваше требование «выяснить конечную точку» как ресурс данных:
data "foo_district_endpoint" "example" {
district_id = "NE53DE"
}
resource "foo" "bar" {
name = "alex"
endpoint = data.foo_district_endpoint.example.endpoint
}
Затем это делает явной описанную вами потребность сделать запрос API для определения конечной точки по идентификатору района, а не скрывать его как деталь реализации foo
. Важным преимуществом явного описания является то, что модуль, который его ищет, не всегда может быть тем модулем, который его использует; для конфигураций, использующих шаблоны Состав модуля, возможно, что эти две потребности будут разделены на два меньших модуля, и, таким образом, значение endpoint
будет перетекать от одного к другому с использованием выходных значений и входных переменных.
Две возможности, которые вы описали, и эта третья возможность, которую я добавил, являются допустимыми и оправданными конструкциями для различных ситуаций. Хотя я не могу сказать вам, какой из них лучше всего подходит для вашей конкретной ситуации, я надеюсь, что этот комментарий, по крайней мере, поможет вам кое-что рассмотреть, чтобы помочь вам принять решение для себя.