fix(integrations): разворачивать CNAME до IP при sync в VPS Tracker
CNAME-bindings отдавали пустой ips[]; теперь IP берутся из локальной цепочки bindings, DNS resolve4 или IP сервиса — чтобы vps-tracker мог матчить домен к VPS. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { ServiceBindingView } from "@cfdm/shared";
|
||||
import { resolveBindingIpsForSync } from "../src/services/vps-tracker-sync.js";
|
||||
|
||||
function binding(
|
||||
partial: Partial<ServiceBindingView> &
|
||||
Pick<ServiceBindingView, "id" | "hostname" | "zone_name">,
|
||||
): ServiceBindingView {
|
||||
return {
|
||||
domain_id: 1,
|
||||
service_id: 1,
|
||||
dns_record_id: null,
|
||||
group_id: null,
|
||||
group_name: null,
|
||||
service_name: "svc",
|
||||
service_slug: "svc",
|
||||
target_ip: null,
|
||||
target_ips: [],
|
||||
target_ip_weights: {},
|
||||
target_ip_priorities: {},
|
||||
cname_target: null,
|
||||
lb_mode: "off",
|
||||
health_check_enabled: false,
|
||||
health_check_type: "tcp",
|
||||
health_check_port: null,
|
||||
health_check_path: null,
|
||||
health_check_expected_status: null,
|
||||
health_check_interval_sec: 60,
|
||||
health_check_timeout_ms: 3000,
|
||||
health_check_verify_tls: true,
|
||||
sync_status: null,
|
||||
created_at: "",
|
||||
updated_at: "",
|
||||
...partial,
|
||||
};
|
||||
}
|
||||
|
||||
describe("resolveBindingIpsForSync", () => {
|
||||
it("uses A-record IPs when present", async () => {
|
||||
const a = binding({
|
||||
id: 1,
|
||||
hostname: "ihome",
|
||||
zone_name: "rkns.top",
|
||||
target_ips: ["10.0.0.5"],
|
||||
});
|
||||
const index = { byFqdn: new Map([["ihome.rkns.top", a]]) };
|
||||
const ips = await resolveBindingIpsForSync(a, ["9.9.9.9"], index);
|
||||
expect(ips).toEqual(["10.0.0.5"]);
|
||||
});
|
||||
|
||||
it("resolves CNAME via local binding chain to VPS IP", async () => {
|
||||
const target = binding({
|
||||
id: 1,
|
||||
hostname: "ihome",
|
||||
zone_name: "rkns.top",
|
||||
target_ips: ["203.0.113.10"],
|
||||
});
|
||||
const cname = binding({
|
||||
id: 2,
|
||||
hostname: "imsk",
|
||||
zone_name: "rkns.top",
|
||||
cname_target: "ihome.rkns.top",
|
||||
target_ips: [],
|
||||
});
|
||||
const index = {
|
||||
byFqdn: new Map([
|
||||
["ihome.rkns.top", target],
|
||||
["imsk.rkns.top", cname],
|
||||
]),
|
||||
};
|
||||
const ips = await resolveBindingIpsForSync(cname, [], index);
|
||||
expect(ips).toEqual(["203.0.113.10"]);
|
||||
});
|
||||
|
||||
it("resolves short CNAME target relative to zone", async () => {
|
||||
const target = binding({
|
||||
id: 1,
|
||||
hostname: "ihome",
|
||||
zone_name: "rkns.top",
|
||||
target_ips: ["203.0.113.11"],
|
||||
});
|
||||
const cname = binding({
|
||||
id: 2,
|
||||
hostname: "imsk",
|
||||
zone_name: "rkns.top",
|
||||
cname_target: "ihome",
|
||||
target_ips: [],
|
||||
});
|
||||
const index = {
|
||||
byFqdn: new Map([
|
||||
["ihome.rkns.top", target],
|
||||
["imsk.rkns.top", cname],
|
||||
]),
|
||||
};
|
||||
const ips = await resolveBindingIpsForSync(cname, [], index);
|
||||
expect(ips).toEqual(["203.0.113.11"]);
|
||||
});
|
||||
|
||||
it("falls back to service IPs when CNAME target unknown locally and DNS fails", async () => {
|
||||
const cname = binding({
|
||||
id: 2,
|
||||
hostname: "imsk",
|
||||
zone_name: "rkns.top",
|
||||
cname_target: "definitely-not-resolvable-xyz.invalid",
|
||||
target_ips: [],
|
||||
});
|
||||
const index = { byFqdn: new Map([["imsk.rkns.top", cname]]) };
|
||||
const ips = await resolveBindingIpsForSync(cname, ["198.51.100.7"], index);
|
||||
expect(ips).toEqual(["198.51.100.7"]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user