mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-05 07:26:36 +08:00
feat(cloudflare): add DNS pointing integration
Implement Cloudflare connection management, pointing groups and members, asynchronous A-record reconciliation, node IP triggers, admin APIs, management pages, migrations, tests, and documentation.
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS of_cf_connections (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
source VARCHAR(32) NOT NULL DEFAULT '',
|
||||
dns_account_id BIGINT,
|
||||
authorization TEXT NOT NULL DEFAULT '',
|
||||
status VARCHAR(16) NOT NULL DEFAULT '',
|
||||
verified_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_connections_dns_account_id ON of_cf_connections (dns_account_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS of_cf_pointing_groups (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
primary_node_id BIGINT NOT NULL,
|
||||
backup_node_id BIGINT,
|
||||
active_node_id BIGINT NOT NULL,
|
||||
default_proxied BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_pointing_groups_primary_node_id ON of_cf_pointing_groups (primary_node_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_pointing_groups_backup_node_id ON of_cf_pointing_groups (backup_node_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_pointing_groups_active_node_id ON of_cf_pointing_groups (active_node_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS of_cf_pointing_members (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
group_id BIGINT NOT NULL,
|
||||
zone_domain_id BIGINT NOT NULL,
|
||||
proxied BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
cf_zone_id VARCHAR(64) NOT NULL DEFAULT '',
|
||||
cf_record_id VARCHAR(64) NOT NULL DEFAULT '',
|
||||
desired_ip VARCHAR(64) NOT NULL DEFAULT '',
|
||||
sync_status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||||
last_error TEXT NOT NULL DEFAULT '',
|
||||
synced_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_pointing_members_group_id ON of_cf_pointing_members (group_id);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_of_cf_pointing_members_zone_domain_id ON of_cf_pointing_members (zone_domain_id);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS of_cf_pointing_members;
|
||||
DROP TABLE IF EXISTS of_cf_pointing_groups;
|
||||
DROP TABLE IF EXISTS of_cf_connections;
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS of_cf_connections (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
source TEXT NOT NULL DEFAULT '',
|
||||
dns_account_id INTEGER,
|
||||
authorization TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT '',
|
||||
verified_at DATETIME,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_connections_dns_account_id ON of_cf_connections (dns_account_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS of_cf_pointing_groups (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
primary_node_id INTEGER NOT NULL,
|
||||
backup_node_id INTEGER,
|
||||
active_node_id INTEGER NOT NULL,
|
||||
default_proxied BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_pointing_groups_primary_node_id ON of_cf_pointing_groups (primary_node_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_pointing_groups_backup_node_id ON of_cf_pointing_groups (backup_node_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_pointing_groups_active_node_id ON of_cf_pointing_groups (active_node_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS of_cf_pointing_members (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
group_id INTEGER NOT NULL,
|
||||
zone_domain_id INTEGER NOT NULL,
|
||||
proxied BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
cf_zone_id TEXT NOT NULL DEFAULT '',
|
||||
cf_record_id TEXT NOT NULL DEFAULT '',
|
||||
desired_ip TEXT NOT NULL DEFAULT '',
|
||||
sync_status TEXT NOT NULL DEFAULT 'pending',
|
||||
last_error TEXT NOT NULL DEFAULT '',
|
||||
synced_at DATETIME,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_of_cf_pointing_members_group_id ON of_cf_pointing_members (group_id);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_of_cf_pointing_members_zone_domain_id ON of_cf_pointing_members (zone_domain_id);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS of_cf_pointing_members;
|
||||
DROP TABLE IF EXISTS of_cf_pointing_groups;
|
||||
DROP TABLE IF EXISTS of_cf_connections;
|
||||
@@ -84,6 +84,15 @@ func TestMigrateInitializesSQLiteDatabase(t *testing.T) {
|
||||
if !sqliteDB.Migrator().HasTable("of_zone_domains") {
|
||||
t.Error("Migrate() did not create of_zone_domains")
|
||||
}
|
||||
for _, table := range []string{
|
||||
"of_cf_connections",
|
||||
"of_cf_pointing_groups",
|
||||
"of_cf_pointing_members",
|
||||
} {
|
||||
if !sqliteDB.Migrator().HasTable(table) {
|
||||
t.Errorf("Migrate() did not create %s", table)
|
||||
}
|
||||
}
|
||||
if sqliteDB.Migrator().HasTable("of_managed_domains") {
|
||||
t.Error("Migrate() should drop of_managed_domains after phase-2 cleanup")
|
||||
}
|
||||
@@ -118,6 +127,17 @@ func TestMigrateInitializesSQLiteDatabase(t *testing.T) {
|
||||
if err := sqliteDB.Create(&model.ZoneDomain{ZoneID: zone.ID, Domain: domain.Domain}).Error; err == nil {
|
||||
t.Error("Migrate() allowed duplicate of_zone_domains.domain")
|
||||
}
|
||||
|
||||
if err := sqliteDB.Exec(`INSERT INTO of_cf_pointing_members
|
||||
(group_id, zone_domain_id, proxied, cf_zone_id, cf_record_id, desired_ip, sync_status, last_error)
|
||||
VALUES (?, ?, ?, '', '', '', 'pending', '')`, 1, domain.ID, false).Error; err != nil {
|
||||
t.Fatalf("Migrate() insert Cloudflare member error = %v", err)
|
||||
}
|
||||
if err := sqliteDB.Exec(`INSERT INTO of_cf_pointing_members
|
||||
(group_id, zone_domain_id, proxied, cf_zone_id, cf_record_id, desired_ip, sync_status, last_error)
|
||||
VALUES (?, ?, ?, '', '', '', 'pending', '')`, 2, domain.ID, false).Error; err == nil {
|
||||
t.Error("Migrate() allowed duplicate of_cf_pointing_members.zone_domain_id")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateClearsStaleSystemConfigCache(t *testing.T) {
|
||||
|
||||
@@ -8,6 +8,7 @@ package handlers
|
||||
import (
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/admin/push"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/openflare"
|
||||
cf "github.com/Rain-kl/Wavelet/internal/apps/openflare/cloudflare"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/openflare/pages"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/openflare/tls"
|
||||
"github.com/Rain-kl/Wavelet/internal/apps/upload"
|
||||
@@ -52,6 +53,13 @@ func Register() {
|
||||
task.RegisterHandler(openflare.UptimeKumaSyncTask, &openflare.UptimeKumaSyncHandler{})
|
||||
task.RegisterTaskMeta(openflare.UptimeKumaSyncMeta)
|
||||
|
||||
task.RegisterHandler(cf.SyncMemberTask, &cf.SyncMemberTaskHandler{})
|
||||
task.RegisterTaskMeta(cf.SyncMemberMeta)
|
||||
task.RegisterHandler(cf.SyncGroupTask, &cf.SyncGroupTaskHandler{})
|
||||
task.RegisterTaskMeta(cf.SyncGroupMeta)
|
||||
task.RegisterHandler(cf.SyncByNodeTask, &cf.SyncByNodeTaskHandler{})
|
||||
task.RegisterTaskMeta(cf.SyncByNodeMeta)
|
||||
|
||||
// pages source actions are only dispatched by the Pages domain API/scanner.
|
||||
task.RegisterHandler(pages.PagesSourceScanTask, &pages.SourceScanHandler{})
|
||||
task.RegisterTaskMeta(pages.PagesSourceScanMeta)
|
||||
|
||||
Reference in New Issue
Block a user