// Package provider is the Terraform provider for Hammerhead. package provider import ( "context" "os" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider/schema" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" "git.veillax.com/Veillax/hhctl/client" ) type hammerheadProvider struct{ version string } // New returns a provider factory. func New(version string) func() provider.Provider { return func() provider.Provider { return &hammerheadProvider{version} } } type providerModel struct { URL types.String `tfsdk:"url"` Token types.String `tfsdk:"token"` Org types.String `tfsdk:"org"` } func (p *hammerheadProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) { resp.TypeName = "hammerhead" resp.Version = p.version } func (p *hammerheadProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { resp.Schema = schema.Schema{ Description: "Manage a Hammerhead control plane: sites, ports, domains, edges and alert channels.", Attributes: map[string]schema.Attribute{ "url": schema.StringAttribute{Optional: true, Description: "Hammerhead address, e.g. https://hammerhead.example.com. Defaults to $HAMMERHEAD_URL."}, "token": schema.StringAttribute{Optional: true, Sensitive: true, Description: "API key (hhk_...). An organization key manages that organization; edges and server alert channels need a server key. Defaults to $HAMMERHEAD_TOKEN."}, "org": schema.StringAttribute{Optional: true, Description: "Organization ID. Optional with an organization key. Defaults to $HAMMERHEAD_ORG."}, }, } } func orDefault(v types.String, env string) string { if !v.IsNull() && !v.IsUnknown() { return v.ValueString() } return os.Getenv(env) } func (p *hammerheadProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { var cfg providerModel resp.Diagnostics.Append(req.Config.Get(ctx, &cfg)...) if resp.Diagnostics.HasError() { return } for _, v := range []struct { name string val types.String }{{"url", cfg.URL}, {"token", cfg.Token}, {"org", cfg.Org}} { if v.val.IsUnknown() { resp.Diagnostics.AddAttributeError(path.Root(v.name), "Unknown "+v.name, "The value must be known when the provider is configured.") } } if resp.Diagnostics.HasError() { return } url, token := orDefault(cfg.URL, "HAMMERHEAD_URL"), orDefault(cfg.Token, "HAMMERHEAD_TOKEN") if url == "" || token == "" { resp.Diagnostics.AddError("Missing configuration", "Set url and token in the provider block, or HAMMERHEAD_URL and HAMMERHEAD_TOKEN.") return } c := client.New(url, token, orDefault(cfg.Org, "HAMMERHEAD_ORG")) resp.ResourceData, resp.DataSourceData = c, c } func (p *hammerheadProvider) Resources(context.Context) []func() resource.Resource { return []func() resource.Resource{NewSite, NewPort, NewDomain, NewEdge, NewAlertChannel} } func (p *hammerheadProvider) DataSources(context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{NewEdgeData} } // clientFrom pulls the configured client out of ProviderData (nil before Configure ran). func clientFrom(data any) *client.Client { c, _ := data.(*client.Client) return c }