我正在开发一个自定义 Terraform 提供程序。 我已完成所有用于创建/读取/更新/删除资源的自定义逻辑,但我无法配置提供程序。 我已克隆此存储库作为基础https://github.com/hashicorp/terraform-provider-scaffolding-framework/tree/main。 如果我调试该存储库中的代码,然后在
provider.go
类型的 Configure
方法处的 hashicupsProvider
文件中添加一行,以便在该方法中获得断点,则该断点永远不会命中。
我自己的提供商有完全相同的“骨架”,所以我认为没有必要提供整个源代码,因为即使从 HashiCorp 提供的示例来看它也不起作用。
我已使用
.terraformrc
覆盖了提供程序地址/路径,并且可以使用 terraform providers schema -json
成功生成提供程序的架构。
我在文档中遗漏了一些您必须做的事情,以便 Terraform 认识到它应该调用
Configure
方法吗?
编辑: 添加提供程序结构和部分接口实现的代码。
type myproviderProvider struct {
version string
}
func (p *myproviderProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "myprovider"
resp.Version = p.version
}
func (p *myproviderProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
tflog.Debug(ctx, "Configure myprovider provider was called")
tflog.Info(ctx, "Creating myprovider client")
// And so on......
}
func (p *myproviderProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Interact with myprovider.",
Attributes: map[string]schema.Attribute{
"username": schema.StringAttribute{
Description: "Username for myapp API. May also be provided via myprovider_USER environment variable.",
Optional: true,
},
"password": schema.StringAttribute{
Description: "Password for myapp API. May also be provided via myprovider_PW environment variable.",
Optional: true,
},
"api_url": schema.StringAttribute{
Description: "Url for myapp API. May also be provided via myprovider_URL environment variable.",
Optional: true,
Sensitive: true,
},
"domain_id": schema.StringAttribute{
Description: "DomainId for myapp API. May also be provided via myprovider_DOMAIN_ID environment variable.",
Optional: true,
Sensitive: true,
},
},
}
}
这是用于将提供者返回到
Serve
方法 的函数
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &myproviderProvider{
version: version,
}
}
}
Terraform 代码
terraform {
required_providers {
myprov = {
source = "hashicorp.com/myuser/myprov"
version = "0.1.0"
}
}
}
provider "myprov" {
username = "myuser"
password = "verysecret"
api_url = "https://someurl.com"
domain_id = "a-guid"
}
我遇到了这样的问题,尽管由于缺少上下文,所以并不能 100% 清楚它是否“完全”是这样。我的问题是:
我用provider.Provider
函数创建了自己的
。这会读取配置,实例化Configure()
并将其设置为与以下内容一起使用:http.Client
resp.DataSourceData = client resp.ResourceData = client
然后我创建了一个resource.Resource
,它还有一个
方法,通过以下方式使用此客户端:Configure()
client, ok := req.ProviderData.(*http.Client)
规划/应用时,req.ProviderData
中的值将是
,并且我的资源将无法创建。 然后我进入nil
方法并尝试通过Provider.Configure()
放置日志 - 它从未出现在输出中。 事实证明这是预期的行为 - 您的资源/数据源必须妥善处理它。在应用/计划期间,可以调用tflog.Info
Resource.Configure()
方法
多次,而您的
Provider.Configure()
方法可能尚未被调用。 在这种情况下,
req.ProviderData
是
nil
,因为配置尚未运行。正确处理这个问题的方法是检查并尽早返回:func (r *ApplicationResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
// IMPORTANT: This method is called MULTIPLE times. An initial call might not have configured the Provider yet, so we need
// to handle this gracefully. It will eventually be called with a configured provider.
return
}
client, ok := req.ProviderData.(*http.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}
r.client = client
}