A Terraform provider for Dokploy
Plugin-framework provider covering projects, environments, applications, Compose stacks, managed databases, domains, mounts, ports, redirects, basic auth, registries, SSH keys, certificates and backup destinations, over Dokploy's tRPC-over-REST API. The shim package exposes the provider to other Go modules, which is how pulumi-dokploy bridges it.
This commit is contained in:
171
internal/provider/provider.go
Normal file
171
internal/provider/provider.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
|
||||
"github.com/maxvojtkov/terraform-provider-dokploy/internal/client"
|
||||
)
|
||||
|
||||
// New returns the provider factory used by main.go and by acceptance tests.
|
||||
func New(version string) func() provider.Provider {
|
||||
return func() provider.Provider {
|
||||
return &dokployProvider{version: version}
|
||||
}
|
||||
}
|
||||
|
||||
type dokployProvider struct {
|
||||
version string
|
||||
}
|
||||
|
||||
type providerModel struct {
|
||||
Host types.String `tfsdk:"host"`
|
||||
APIKey types.String `tfsdk:"api_key"`
|
||||
Timeout types.Int64 `tfsdk:"timeout_seconds"`
|
||||
SkipVerify types.Bool `tfsdk:"insecure_skip_verify"`
|
||||
}
|
||||
|
||||
func (p *dokployProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
|
||||
resp.TypeName = "dokploy"
|
||||
resp.Version = p.version
|
||||
}
|
||||
|
||||
func (p *dokployProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
|
||||
resp.Schema = schema.Schema{
|
||||
MarkdownDescription: "Manage [Dokploy](https://dokploy.com) projects, environments, applications, " +
|
||||
"compose stacks, databases and networking with Terraform.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"host": schema.StringAttribute{
|
||||
Optional: true,
|
||||
MarkdownDescription: "Base URL of the Dokploy instance, for example `https://dokploy.example.com`. " +
|
||||
"A trailing `/api` is optional. May also be set with the `DOKPLOY_HOST` environment variable.",
|
||||
},
|
||||
"api_key": schema.StringAttribute{
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
MarkdownDescription: "API token generated in Dokploy under *Settings -> Profile -> API/CLI*. " +
|
||||
"May also be set with the `DOKPLOY_API_KEY` environment variable.",
|
||||
},
|
||||
"timeout_seconds": schema.Int64Attribute{
|
||||
Optional: true,
|
||||
MarkdownDescription: "Per-request timeout in seconds. Defaults to `60`. May also be set with the " +
|
||||
"`DOKPLOY_TIMEOUT_SECONDS` environment variable.",
|
||||
},
|
||||
"insecure_skip_verify": schema.BoolAttribute{
|
||||
Optional: true,
|
||||
MarkdownDescription: "Skip TLS certificate verification. Only use this for instances behind a " +
|
||||
"self-signed certificate. Defaults to `false`.",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *dokployProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
|
||||
var config providerModel
|
||||
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
host := stringOrEnv(config.Host, "DOKPLOY_HOST")
|
||||
apiKey := stringOrEnv(config.APIKey, "DOKPLOY_API_KEY")
|
||||
|
||||
if host == "" {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
path.Root("host"),
|
||||
"Missing Dokploy host",
|
||||
"Set the `host` provider attribute or the DOKPLOY_HOST environment variable.",
|
||||
)
|
||||
}
|
||||
if apiKey == "" {
|
||||
resp.Diagnostics.AddAttributeError(
|
||||
path.Root("api_key"),
|
||||
"Missing Dokploy API key",
|
||||
"Set the `api_key` provider attribute or the DOKPLOY_API_KEY environment variable.",
|
||||
)
|
||||
}
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
timeout := 60 * time.Second
|
||||
if !config.Timeout.IsNull() && !config.Timeout.IsUnknown() {
|
||||
timeout = time.Duration(config.Timeout.ValueInt64()) * time.Second
|
||||
} else if env := os.Getenv("DOKPLOY_TIMEOUT_SECONDS"); env != "" {
|
||||
if seconds, err := strconv.Atoi(env); err == nil {
|
||||
timeout = time.Duration(seconds) * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
var httpClient *http.Client
|
||||
if config.SkipVerify.ValueBool() {
|
||||
httpClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec // opt-in
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
api, err := client.New(host, apiKey, timeout, httpClient)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("Invalid Dokploy provider configuration", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
resp.DataSourceData = api
|
||||
resp.ResourceData = api
|
||||
}
|
||||
|
||||
func (p *dokployProvider) Resources(_ context.Context) []func() resource.Resource {
|
||||
return []func() resource.Resource{
|
||||
newGenericResource(projectResource()),
|
||||
newGenericResource(environmentResource()),
|
||||
newGenericResource(applicationResource()),
|
||||
newGenericResource(composeResource()),
|
||||
|
||||
newGenericResource(postgresResource()),
|
||||
newGenericResource(mysqlResource()),
|
||||
newGenericResource(mariadbResource()),
|
||||
newGenericResource(mongoResource()),
|
||||
newGenericResource(redisResource()),
|
||||
|
||||
newGenericResource(domainResource()),
|
||||
newGenericResource(mountResource()),
|
||||
newGenericResource(portResource()),
|
||||
newGenericResource(redirectResource()),
|
||||
newGenericResource(securityResource()),
|
||||
|
||||
newGenericResource(registryResource()),
|
||||
newGenericResource(sshKeyResource()),
|
||||
newGenericResource(certificateResource()),
|
||||
newGenericResource(destinationResource()),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *dokployProvider) DataSources(_ context.Context) []func() datasource.DataSource {
|
||||
return []func() datasource.DataSource{
|
||||
newProjectDataSource,
|
||||
newProjectsDataSource,
|
||||
newEnvironmentDataSource,
|
||||
newApplicationDataSource,
|
||||
newServersDataSource,
|
||||
}
|
||||
}
|
||||
|
||||
func stringOrEnv(value types.String, envVar string) string {
|
||||
if !value.IsNull() && !value.IsUnknown() && value.ValueString() != "" {
|
||||
return value.ValueString()
|
||||
}
|
||||
return os.Getenv(envVar)
|
||||
}
|
||||
Reference in New Issue
Block a user