Files
terraform-provider-dokploy/internal/provider/provider.go
T
max-voitcov 2d1caf6e73
build / build (push) Successful in 3m56s
release / release (push) Successful in 15m2s
Cover what Dokploy v0.30 added
Six new resources, all backed by endpoints that did not exist before v0.30.0
and verified end-to-end against a live v0.30.2 instance:

  dokploy_network         Docker networks, now first-class. Services attach
                          through network_ids, which is what deprecates
                          Compose's isolated_deployment upstream.
  dokploy_dns_provider    Cloudflare or Route53, so adding a domain creates
                          its DNS record.
  dokploy_vault_provider  Env values resolved from HashiCorp Vault, Infisical,
                          AWS, Doppler, Azure or Scaleway at deploy time, so
                          the secret never lands in Dokploy or in state.
  dokploy_schedule        Cron jobs in a container, a stack, or on a server.
  dokploy_volume_backup   Scheduled backups of a named volume — the companion
                          to a mount that persists.
  dokploy_libsql          The sixth managed database engine.

libsql.create is the strictest endpoint in the API: eleven keys required to
be present, several only meaningfully null, no generated service name, and it
returns `true` rather than the row. CreateDefaults and ListIDs absorb all
three so the resource behaves like every other database.

Also filled the gaps a field-by-field diff against the live schema turned up:
domain gains `enabled` (the v0.30.0 park-a-domain toggle), compose gains
create_env_file, icon and service_networks, application gains icon and
preview_require_collaborator_permissions, and mounts accept libsql.

DNS and vault credentials are masked by Dokploy on read, so `config` is
tagged noread and keeps the configured value, as the basic-auth password
already does.
2026-08-26 00:40:27 +03:00

184 lines
5.8 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, Docker networks 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(libsqlResource()),
newGenericResource(domainResource()),
newGenericResource(mountResource()),
newGenericResource(portResource()),
newGenericResource(redirectResource()),
newGenericResource(securityResource()),
// Docker network management, added in Dokploy v0.30.0.
newGenericResource(networkResource()),
// Scheduling, added in Dokploy v0.30.0.
newGenericResource(scheduleResource()),
newGenericResource(volumeBackupResource()),
// External integrations, added in Dokploy v0.30.0.
newGenericResource(dnsProviderResource()),
newGenericResource(vaultProviderResource()),
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)
}