Skip to content

共享包 ​

四个一方包 packages/dn42_* 是 Control Server 与 Node Agent 共用的地基:协议模型、渲染、文件产物、公共工具。本文讲它们的分层、依赖方向与各自职责。字段细节见 DesiredState 参考。

依赖方向 ​

dn42_common 是无上游依赖的叶子。dn42_schemas 只依赖 common。dn42_templates 依赖三者(产出 RenderedFile)。无循环依赖。控制面(apps/control-server)用 schemas(校验/合成);Node Agent 用全部四个(渲染 + 规划 + 执行)。

dn42_schemas —— 协议模型 ​

所有跨组件传输的数据结构,基于 Pydantic v2。基类 StrictModel(base.py):extra="forbid"(拒未知字段)+ frozen=True(不可变)+ canonical_json() / canonical_sha256()(稳定序列化,用于内容寻址)。

文件内容
desired_state.pyDesiredState 顶层 + validate_references + 四个 _normalize_* 钩子(端口发布、bird socket、DNS runtime、DNS anycast)
network.pyNodeSpec(含 link_local 单源)、InterfaceSpec、WireGuardPeerSpec
routing.pyBgpSessionSpec、BfdSpec、Bird2ConfigSpec、InternalTopologySpec、BirdHostSpec、DummyInterfaceSpec、BgpLargeCommunitySpec
dns.pyDnsSpec、DnsZoneSpec、DnsRecordSpec、DnsForwardSpec
runtime.pyRouterRuntimeSpec、RuntimeServiceSpec、UnderlayNetworkSpec、PortPublishSpec、WireGuardPortRangeSpec、RpkiSpec 等容器编排模型
agent.pyAgent 协议:注册请求/响应、RuntimeSnapshot、ReconciliationReport、ApplyResult、各 Observed*
enums.pyInterfaceKind、ServiceRole、AddressFamily、ApplyStatus、BootstrapStatus、NodeHealth、ObservationStatus 等
testing.py示例 builder(hkg1、本地多节点),供测试与渲染 golden 用

DesiredState 的字段、校验规则、normalize 钩子是单独的参考主题,见 DesiredState 参考。

dn42_templates —— 渲染 ​

把 DesiredState 渲染为节点上的配置文件与脚本。入口 render_desired_state(state) -> list[RenderedFile](desired_state.py)。

产出模板
bird/*.confconfig-bird2/(community_filters、custom_filters、rpki、anycast_services、bird.conf、dn42_peers、ibgp、ospf、ospf_interfaces)
wireguard/<iface>.confconfig-wireguard/interface.conf.j2
coredns/Corefile + coredns/zones/db.<zone>config-coredns/(DNS 启用时)
scripts/bird/*、scripts/wg/*config-scripts/(apply / start 脚本)

bird2.py 的 build_config_bird2_context 把 DesiredState 翻译成 BIRD 模板上下文(ownip、ownnets*_ipset、bird_hosts、wg_peers、large_communities、route_collectors、rpki_ip 等)——这里就是"loopback / prefixes → OWNIP / ipset"等派生发生的地方(见 地址模型)。Jinja 环境用 StrictUndefined(缺变量即报错)+ shell_quote / yaml_quote 过滤器。

router 容器的 Dockerfile 不渲染成文件,由 agent 在内存里从 runtime.router_dockerfile 经 Docker Engine API 生成。

dn42_runtime —— 文件产物与 Dockerfile ​

文件内容
types.pyRenderedFile(不可变;路径强校验:禁 ..、NUL、绝对路径、Windows 盘符)
docker.pyrender_router_dockerfile()(多阶段 router 镜像模板)
paths.py模板目录发现

写盘计划的执行(原子写 + 删除)由此包提供,被 agent 的 writer 调用。

dn42_common —— 公共工具 ​

无上游依赖的叶子,被其余三包与两个 app 共用。

模块内容
validators/IP / 网络 / link-local、DN42 地址空间(172.20.0.0/14、fd00::/8、anycast 段)、ASN、WireGuard key / endpoint、域名、ISO8601、agent token
labels.py容器/网络 label 单源:dn42.managed、dn42.node_id、dn42.config_hash、dn42.component
naming.pynode_project_name、service_container_name(<project>-<service>-1)、agent_id_for
communities.pyDN42 origin region community 编码、国家代码映射
serialization.pycanonical_json_dumps / canonical_sha256_hex(内容寻址哈希)
jinja.pycreate_environment、shell_quote、yaml_quote
io.pyatomic_write_text / atomic_write_json
crypto.pyWireGuard 密钥生成、恢复密钥 seal / unseal(escrow)

labels.py 与 serialization.py 一起支撑了内容寻址:容器 config_hash 来自容器定义 payload 的 canonical SHA-256,是最小扰动设计的基础(见 架构)。

锁步约束 ​

修改 dn42_common 或 dn42_schemas 的校验规则、哈希算法或模型字段,会同时影响控制面与全机群 agent——两侧对同一输入的接受集与摘要口径必须一致,否则会分叉。

StrictModel 的 extra="forbid" 让这类分叉在解析期就报错而不是静默降级,代价是发布顺序有硬性要求:加字段先升控制面、删字段先升 agent。详见 锁步契约。