c730cfaa45
Add flexible DNS management to Docker Watcher. By default, wildcard DNS is assumed (current behavior). When disabled, users can configure a Cloudflare DNS provider with API token and zone selection. DNS A records are automatically created/updated/deleted in sync with proxy consumers (deployed instances and standalone proxies). - Settings: wildcard_dns toggle, dns_provider, cloudflare credentials - Cloudflare client: Provider interface with EnsureRecord/DeleteRecord/ListRecords - DNS lifecycle hooks in deployer and proxy manager (best-effort) - Settings UI: DNS config section with provider picker, zone selector, test button - DNS Records page at /dns with filtering, sync status, reconciliation - Records visible in both wildcard and managed modes - Cleanup on provider change: removes old records when switching modes
71 lines
2.8 KiB
Go
71 lines
2.8 KiB
Go
package deployer
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
)
|
|
|
|
// rollback cleans up a failed deployment by removing the container,
|
|
// deleting the NPM proxy host, and updating the instance status.
|
|
// Errors during rollback are logged but do not prevent other cleanup steps.
|
|
func (d *Deployer) rollback(ctx context.Context, deployID string, containerID string, npmProxyID int, instanceID string) {
|
|
d.logDeploy(deployID, "Rolling back failed deployment", "warn")
|
|
|
|
// Remove the container if it was created.
|
|
if containerID != "" {
|
|
if err := d.docker.RemoveContainer(ctx, containerID, true); err != nil {
|
|
slog.Warn("rollback: remove container", "container_id", containerID, "error", err)
|
|
d.logDeploy(deployID, fmt.Sprintf("Rollback: failed to remove container: %v", err), "error")
|
|
} else {
|
|
d.logDeploy(deployID, "Rollback: container removed", "info")
|
|
}
|
|
}
|
|
|
|
// Delete the NPM proxy host if it was created.
|
|
if npmProxyID > 0 {
|
|
settings, err := d.store.GetSettings()
|
|
if err != nil {
|
|
slog.Warn("rollback: get settings for npm auth", "error", err)
|
|
d.logDeploy(deployID, fmt.Sprintf("Rollback: failed to get settings for proxy cleanup: %v", err), "error")
|
|
} else if npmPassword, err := d.decryptNpmPassword(settings.NpmPassword); err != nil {
|
|
slog.Warn("rollback: decrypt npm password", "error", err)
|
|
d.logDeploy(deployID, "Rollback: failed to decrypt NPM password for proxy cleanup", "error")
|
|
} else if err := d.npm.Authenticate(ctx, settings.NpmEmail, npmPassword); err != nil {
|
|
slog.Warn("rollback: authenticate npm", "error", err)
|
|
d.logDeploy(deployID, "Rollback: failed to authenticate NPM for proxy cleanup", "error")
|
|
} else if err := d.npm.DeleteProxyHost(ctx, npmProxyID); err != nil {
|
|
slog.Warn("rollback: delete proxy host", "proxy_id", npmProxyID, "error", err)
|
|
d.logDeploy(deployID, fmt.Sprintf("Rollback: failed to delete proxy host: %v", err), "error")
|
|
} else {
|
|
d.logDeploy(deployID, "Rollback: proxy host deleted", "info")
|
|
}
|
|
}
|
|
|
|
// Clean up DNS record if the instance had a subdomain.
|
|
if instanceID != "" {
|
|
inst, err := d.store.GetInstanceByID(instanceID)
|
|
if err == nil && inst.Subdomain != "" {
|
|
settings, _ := d.store.GetSettings()
|
|
if settings.Domain != "" {
|
|
fqdn := inst.Subdomain + "." + settings.Domain
|
|
d.removeDNS(ctx, fqdn, deployID)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update instance status to failed if it was created.
|
|
if instanceID != "" {
|
|
if err := d.store.UpdateInstanceStatus(instanceID, "failed"); err != nil {
|
|
slog.Warn("rollback: update instance status", "instance_id", instanceID, "error", err)
|
|
}
|
|
}
|
|
|
|
// Mark deploy as rolled back.
|
|
if err := d.store.UpdateDeployStatus(deployID, "rolled_back", "deployment failed, rolled back"); err != nil {
|
|
slog.Warn("rollback: update deploy status", "deploy_id", deployID, "error", err)
|
|
}
|
|
|
|
d.logDeploy(deployID, "Rollback complete", "info")
|
|
}
|