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.
172 lines
5.3 KiB
Go
172 lines
5.3 KiB
Go
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)
|
|
}
|