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.
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
// DNS providers and vault providers both arrived in Dokploy v0.30.0. They
|
||||
// share a shape: a name plus a free-form `config` object whose keys depend on
|
||||
// a `providerType` discriminator nested inside it.
|
||||
//
|
||||
// Dokploy masks the credentials in `config` on every read, so the value is
|
||||
// tagged `noread`: the configured value stays authoritative in state instead
|
||||
// of being overwritten with asterisks on the next refresh.
|
||||
|
||||
// ---------------------------------------------------------- DNS provider
|
||||
|
||||
type dnsProviderModel struct {
|
||||
ID types.String `tfsdk:"id" dokploy:"dnsProviderId,id"`
|
||||
Name types.String `tfsdk:"name" dokploy:"name"`
|
||||
Config jsontypes.Normalized `tfsdk:"config" dokploy:"config,noread"`
|
||||
|
||||
ProviderType types.String `tfsdk:"provider_type" dokploy:"providerType,ro"`
|
||||
OrganizationID types.String `tfsdk:"organization_id" dokploy:"organizationId,ro"`
|
||||
CreatedAt types.String `tfsdk:"created_at" dokploy:"createdAt,ro"`
|
||||
}
|
||||
|
||||
func dnsProviderResource() ResourceSpec {
|
||||
return ResourceSpec{
|
||||
Name: "dns_provider",
|
||||
CreateProc: "dnsProvider.create",
|
||||
ReadProc: "dnsProvider.one",
|
||||
UpdateProc: "dnsProvider.update",
|
||||
DeleteProc: "dnsProvider.remove",
|
||||
NewModel: func() any { return &dnsProviderModel{} },
|
||||
Schema: schema.Schema{
|
||||
MarkdownDescription: "A DNS provider connection Dokploy uses to create records for domains " +
|
||||
"automatically.\n\n" +
|
||||
"`config` is a JSON object whose shape depends on `providerType`:\n\n" +
|
||||
"```hcl\n" +
|
||||
"# Cloudflare\n" +
|
||||
"config = jsonencode({ providerType = \"cloudflare\", apiToken = var.cloudflare_token })\n\n" +
|
||||
"# AWS Route53\n" +
|
||||
"config = jsonencode({\n" +
|
||||
" providerType = \"route53\"\n" +
|
||||
" accessKeyId = var.aws_access_key_id\n" +
|
||||
" secretAccessKey = var.aws_secret_access_key\n" +
|
||||
"})\n" +
|
||||
"```\n\n" +
|
||||
"~> Dokploy masks the credentials when reading a provider back, so Terraform keeps the value " +
|
||||
"you configured. Drift in `config` is not detected.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": computedID("Unique DNS provider identifier."),
|
||||
"name": requiredString("Name of the connection. Must be unique within the organization and may " +
|
||||
"contain only letters, digits, `-` and `_`."),
|
||||
"config": schema.StringAttribute{
|
||||
Required: true,
|
||||
Sensitive: true,
|
||||
CustomType: jsontypes.NormalizedType{},
|
||||
MarkdownDescription: "Provider credentials as a JSON object, including the `providerType` discriminator.",
|
||||
},
|
||||
"provider_type": computedString("Provider kind derived from `config`: `cloudflare` or `route53`."),
|
||||
"organization_id": computedString("Organization that owns the connection."),
|
||||
"created_at": computedString("RFC 3339 timestamp of when the connection was created."),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------- Vault provider
|
||||
|
||||
type vaultProviderModel struct {
|
||||
ID types.String `tfsdk:"id" dokploy:"vaultProviderId,id"`
|
||||
Name types.String `tfsdk:"name" dokploy:"name"`
|
||||
Config jsontypes.Normalized `tfsdk:"config" dokploy:"config,noread"`
|
||||
Assignments jsontypes.Normalized `tfsdk:"assignments" dokploy:"assignments"`
|
||||
|
||||
ProviderType types.String `tfsdk:"provider_type" dokploy:"providerType,ro"`
|
||||
OrganizationID types.String `tfsdk:"organization_id" dokploy:"organizationId,ro"`
|
||||
CreatedAt types.String `tfsdk:"created_at" dokploy:"createdAt,ro"`
|
||||
}
|
||||
|
||||
func vaultProviderResource() ResourceSpec {
|
||||
return ResourceSpec{
|
||||
Name: "vault_provider",
|
||||
CreateProc: "vaultProvider.create",
|
||||
ReadProc: "vaultProvider.one",
|
||||
UpdateProc: "vaultProvider.update",
|
||||
DeleteProc: "vaultProvider.remove",
|
||||
NewModel: func() any { return &vaultProviderModel{} },
|
||||
Schema: schema.Schema{
|
||||
MarkdownDescription: "An external secret manager Dokploy resolves environment variables from at " +
|
||||
"deploy time.\n\n" +
|
||||
"Reference a secret from any `env` value with `${{vault.<scope>.<key>}}`. The value is fetched " +
|
||||
"when the deployment runs and is never stored in Dokploy — so rotating it in the vault takes " +
|
||||
"effect on the next deploy with no Terraform change.\n\n" +
|
||||
"Supported `providerType` values: `hashicorp` (Vault/OpenBao), `infisical`, `aws` " +
|
||||
"(Secrets Manager), `doppler`, `azure` (Key Vault) and `scaleway`.\n\n" +
|
||||
"```hcl\n" +
|
||||
"config = jsonencode({\n" +
|
||||
" providerType = \"hashicorp\"\n" +
|
||||
" url = \"https://vault.example.com\"\n" +
|
||||
" token = var.vault_token\n" +
|
||||
" mount = \"secret\"\n" +
|
||||
"})\n" +
|
||||
"```\n\n" +
|
||||
"~> Dokploy masks the credentials when reading a provider back, so Terraform keeps the value " +
|
||||
"you configured. Drift in `config` is not detected.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": computedID("Unique vault provider identifier."),
|
||||
"name": requiredString("Name of the connection, unique within the organization."),
|
||||
"config": schema.StringAttribute{
|
||||
Required: true,
|
||||
Sensitive: true,
|
||||
CustomType: jsontypes.NormalizedType{},
|
||||
MarkdownDescription: "Provider credentials as a JSON object, including the `providerType` discriminator.",
|
||||
},
|
||||
"assignments": schema.StringAttribute{
|
||||
Required: true,
|
||||
CustomType: jsontypes.NormalizedType{},
|
||||
MarkdownDescription: "JSON array scoping which projects or environments may resolve secrets " +
|
||||
"from this provider. Pass `jsonencode([])` to leave it unscoped.",
|
||||
},
|
||||
"provider_type": computedString("Provider kind derived from `config`."),
|
||||
"organization_id": computedString("Organization that owns the connection."),
|
||||
"created_at": computedString("RFC 3339 timestamp of when the connection was created."),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user