Files
arcadia-cloud/lib/arcadia_cloud/sync/domains_worker.ex
Giuliano Silvestro 53b664558d Phase 1 continued: ProjectsWorker, DomainsWorker, Oban Cron schedule
ProjectsWorker mirrors DO Projects to cloud_projects table in a two-pass
sweep: upsert projects, then walk each project's resource membership
(list_project_resources) and update cloud_resources.cloud_project_id +
tenant_id. DO URN kinds get normalized via normalize_kind/1 (domain →
dns_zone, space → spaces_bucket) so attribution matches local naming.

DomainsWorker syncs DNS zones (DO Domains). Same upsert chokepoint, same
three-strike stale handling. Zones are global to the account; attribution
happens via ProjectsWorker if a domain is in a DO project, else stays
NULL pending operator classification.

Oban.Plugins.Cron added with 15-minute schedules for ProjectsWorker,
DropletsWorker, DomainsWorker — workers run automatically once a token
is configured. Phase 0/1 cadence; phase 2 moves droplets to cloud_sync_fast
(1-min) for real-time status visibility.

DigitalOcean.Client gains list_domains / list_volumes / list_floating_ips.
Volumes and floating IPs not yet wired to workers; trivial follow-on.

Live smoke test: 5 droplets + 7 DNS zones discovered, all attributed to
their existing DO projects via membership lookup (skyai-internal becomes
the fallback only for genuinely orphan resources).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 22:11:40 +10:00

54 lines
1.3 KiB
Elixir

defmodule ArcadiaCloud.Sync.DomainsWorker do
@moduledoc """
Full sync of DigitalOcean Domains (DNS zones).
Domains are global to the DO account (no region, no project membership
via URN in the same way droplets have). They are typically attributed
manually by operator action; first sync leaves them with cloud_project_id
nil + tenant_id nil. ProjectsWorker's attribution pass picks them up if
they appear in project memberships.
"""
use Oban.Worker, queue: :cloud_sync_full, max_attempts: 3
alias ArcadiaCloud.Cloud
alias ArcadiaCloud.DigitalOcean.Client
@kind "dns_zone"
@provider "digitalocean"
@impl Oban.Worker
def perform(_job) do
sync_started_at = DateTime.utc_now() |> DateTime.truncate(:second)
with {:ok, domains} <- Client.list_domains() do
Enum.each(domains, fn d ->
Cloud.upsert_resource(normalize(d, sync_started_at))
end)
Cloud.mark_stale(@kind, sync_started_at)
:ok
end
end
defp normalize(d, now) do
name = d["name"]
%{
provider: @provider,
provider_id: name,
kind: @kind,
name: name,
region: nil,
status: "active",
tags: [],
attrs: %{
ttl: d["ttl"],
zone_file: d["zone_file"]
},
first_seen_at: now,
last_seen_at: now
}
end
end