@homeflare/alchemy 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/dist/cloudflare/client.d.ts +45 -0
- package/dist/cloudflare/client.d.ts.map +1 -0
- package/dist/cloudflare/index.d.ts +11 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +129 -0
- package/dist/cloudflare/index.js.map +13 -0
- package/dist/cloudflare/lock-rules.d.ts +50 -0
- package/dist/cloudflare/lock-rules.d.ts.map +1 -0
- package/dist/cloudflare/providers.d.ts +19 -0
- package/dist/cloudflare/providers.d.ts.map +1 -0
- package/dist/cloudflare/r2-bucket-lock.d.ts +100 -0
- package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -0
- package/dist/forgejo/branch-protection-form.d.ts +19 -0
- package/dist/forgejo/branch-protection-form.d.ts.map +1 -0
- package/dist/forgejo/branch-protection.d.ts +47 -0
- package/dist/forgejo/branch-protection.d.ts.map +1 -0
- package/dist/forgejo/client.d.ts +37 -0
- package/dist/forgejo/client.d.ts.map +1 -0
- package/dist/forgejo/index.d.ts +18 -0
- package/dist/forgejo/index.d.ts.map +1 -0
- package/dist/forgejo/index.js +479 -0
- package/dist/forgejo/index.js.map +21 -0
- package/dist/forgejo/org-actions-secrets.d.ts +45 -0
- package/dist/forgejo/org-actions-secrets.d.ts.map +1 -0
- package/dist/forgejo/org-label.d.ts +46 -0
- package/dist/forgejo/org-label.d.ts.map +1 -0
- package/dist/forgejo/org-team.d.ts +42 -0
- package/dist/forgejo/org-team.d.ts.map +1 -0
- package/dist/forgejo/repo-webhook-form.d.ts +27 -0
- package/dist/forgejo/repo-webhook-form.d.ts.map +1 -0
- package/dist/forgejo/repo-webhook.d.ts +46 -0
- package/dist/forgejo/repo-webhook.d.ts.map +1 -0
- package/dist/forgejo/repository.d.ts +45 -0
- package/dist/forgejo/repository.d.ts.map +1 -0
- package/dist/forgejo/resource.d.ts +83 -0
- package/dist/forgejo/resource.d.ts.map +1 -0
- package/dist/forgejo/team-member.d.ts +39 -0
- package/dist/forgejo/team-member.d.ts.map +1 -0
- package/dist/forgejo/values.d.ts +24 -0
- package/dist/forgejo/values.d.ts.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +9 -0
- package/dist/openbao/auth-role-form.d.ts +38 -0
- package/dist/openbao/auth-role-form.d.ts.map +1 -0
- package/dist/openbao/auth-role.d.ts +20 -0
- package/dist/openbao/auth-role.d.ts.map +1 -0
- package/dist/openbao/bao-address.d.ts +72 -0
- package/dist/openbao/bao-address.d.ts.map +1 -0
- package/dist/openbao/bao-http.d.ts +71 -0
- package/dist/openbao/bao-http.d.ts.map +1 -0
- package/dist/openbao/bao-status.d.ts +74 -0
- package/dist/openbao/bao-status.d.ts.map +1 -0
- package/dist/openbao/cloudflare-group-scope.d.ts +73 -0
- package/dist/openbao/cloudflare-group-scope.d.ts.map +1 -0
- package/dist/openbao/cloudflare-parity-catalog.d.ts +28 -0
- package/dist/openbao/cloudflare-parity-catalog.d.ts.map +1 -0
- package/dist/openbao/cloudflare-parity-snapshot.d.ts +31 -0
- package/dist/openbao/cloudflare-parity-snapshot.d.ts.map +1 -0
- package/dist/openbao/cloudflare-parity.d.ts +14 -0
- package/dist/openbao/cloudflare-parity.d.ts.map +1 -0
- package/dist/openbao/cloudflare-permission-groups-solve.d.ts +85 -0
- package/dist/openbao/cloudflare-permission-groups-solve.d.ts.map +1 -0
- package/dist/openbao/cloudflare-permission-groups.d.ts +87 -0
- package/dist/openbao/cloudflare-permission-groups.d.ts.map +1 -0
- package/dist/openbao/cloudflare-policy.d.ts +65 -0
- package/dist/openbao/cloudflare-policy.d.ts.map +1 -0
- package/dist/openbao/cloudflare-role-form.d.ts +110 -0
- package/dist/openbao/cloudflare-role-form.d.ts.map +1 -0
- package/dist/openbao/cloudflare-role-wire.d.ts +27 -0
- package/dist/openbao/cloudflare-role-wire.d.ts.map +1 -0
- package/dist/openbao/cloudflare-role.d.ts +35 -0
- package/dist/openbao/cloudflare-role.d.ts.map +1 -0
- package/dist/openbao/cloudflare-roles-config.d.ts +67 -0
- package/dist/openbao/cloudflare-roles-config.d.ts.map +1 -0
- package/dist/openbao/cloudflare-roles-expand.d.ts +76 -0
- package/dist/openbao/cloudflare-roles-expand.d.ts.map +1 -0
- package/dist/openbao/digest.d.ts +24 -0
- package/dist/openbao/digest.d.ts.map +1 -0
- package/dist/openbao/fake-bao.d.ts +40 -0
- package/dist/openbao/fake-bao.d.ts.map +1 -0
- package/dist/openbao/forgejo-bootstrap-parse.d.ts +46 -0
- package/dist/openbao/forgejo-bootstrap-parse.d.ts.map +1 -0
- package/dist/openbao/forgejo-bootstrap.d.ts +29 -0
- package/dist/openbao/forgejo-bootstrap.d.ts.map +1 -0
- package/dist/openbao/index.d.ts +18 -0
- package/dist/openbao/index.d.ts.map +1 -0
- package/dist/openbao/index.js +1158 -0
- package/dist/openbao/index.js.map +33 -0
- package/dist/openbao/mount-form.d.ts +60 -0
- package/dist/openbao/mount-form.d.ts.map +1 -0
- package/dist/openbao/mount-wire.d.ts +24 -0
- package/dist/openbao/mount-wire.d.ts.map +1 -0
- package/dist/openbao/mount.d.ts +20 -0
- package/dist/openbao/mount.d.ts.map +1 -0
- package/dist/openbao/pki-role-form.d.ts +118 -0
- package/dist/openbao/pki-role-form.d.ts.map +1 -0
- package/dist/openbao/pki-role.d.ts +50 -0
- package/dist/openbao/pki-role.d.ts.map +1 -0
- package/dist/openbao/policy-assembly.d.ts +13 -0
- package/dist/openbao/policy-assembly.d.ts.map +1 -0
- package/dist/openbao/policy-wire.d.ts +41 -0
- package/dist/openbao/policy-wire.d.ts.map +1 -0
- package/dist/openbao/policy.d.ts +83 -0
- package/dist/openbao/policy.d.ts.map +1 -0
- package/dist/openbao/proxmox-role-form.d.ts +92 -0
- package/dist/openbao/proxmox-role-form.d.ts.map +1 -0
- package/dist/openbao/proxmox-role.d.ts +47 -0
- package/dist/openbao/proxmox-role.d.ts.map +1 -0
- package/dist/openbao/ssh-role-form.d.ts +99 -0
- package/dist/openbao/ssh-role-form.d.ts.map +1 -0
- package/dist/openbao/ssh-role.d.ts +43 -0
- package/dist/openbao/ssh-role.d.ts.map +1 -0
- package/dist/proxmox/acl.d.ts +72 -0
- package/dist/proxmox/acl.d.ts.map +1 -0
- package/dist/proxmox/api-token-form.d.ts +59 -0
- package/dist/proxmox/api-token-form.d.ts.map +1 -0
- package/dist/proxmox/api-token.d.ts +159 -0
- package/dist/proxmox/api-token.d.ts.map +1 -0
- package/dist/proxmox/backup-job.d.ts +112 -0
- package/dist/proxmox/backup-job.d.ts.map +1 -0
- package/dist/proxmox/ceph-daemon-form.d.ts +70 -0
- package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -0
- package/dist/proxmox/ceph-daemon.d.ts +162 -0
- package/dist/proxmox/ceph-daemon.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag.d.ts +131 -0
- package/dist/proxmox/ceph-flag.d.ts.map +1 -0
- package/dist/proxmox/ceph-fs-wire.d.ts +106 -0
- package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-fs.d.ts +124 -0
- package/dist/proxmox/ceph-fs.d.ts.map +1 -0
- package/dist/proxmox/ceph-osd-tree.d.ts +154 -0
- package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -0
- package/dist/proxmox/ceph-osd-write.d.ts +36 -0
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -0
- package/dist/proxmox/ceph-osd.d.ts +102 -0
- package/dist/proxmox/ceph-osd.d.ts.map +1 -0
- package/dist/proxmox/ceph-pool-form.d.ts +217 -0
- package/dist/proxmox/ceph-pool-form.d.ts.map +1 -0
- package/dist/proxmox/ceph-pool-settle.d.ts +39 -0
- package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -0
- package/dist/proxmox/ceph-pool.d.ts +48 -0
- package/dist/proxmox/ceph-pool.d.ts.map +1 -0
- package/dist/proxmox/client.d.ts +64 -0
- package/dist/proxmox/client.d.ts.map +1 -0
- package/dist/proxmox/credentials.d.ts +153 -0
- package/dist/proxmox/credentials.d.ts.map +1 -0
- package/dist/proxmox/firewall-alias-form.d.ts +98 -0
- package/dist/proxmox/firewall-alias-form.d.ts.map +1 -0
- package/dist/proxmox/firewall-alias.d.ts +141 -0
- package/dist/proxmox/firewall-alias.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs.d.ts +388 -0
- package/dist/proxmox/generated/pbs.d.ts.map +1 -0
- package/dist/proxmox/generated/pve.d.ts +4713 -0
- package/dist/proxmox/generated/pve.d.ts.map +1 -0
- package/dist/proxmox/group.d.ts +104 -0
- package/dist/proxmox/group.d.ts.map +1 -0
- package/dist/proxmox/ha-resource.d.ts +104 -0
- package/dist/proxmox/ha-resource.d.ts.map +1 -0
- package/dist/proxmox/ha-rule-form.d.ts +103 -0
- package/dist/proxmox/ha-rule-form.d.ts.map +1 -0
- package/dist/proxmox/ha-rule.d.ts +156 -0
- package/dist/proxmox/ha-rule.d.ts.map +1 -0
- package/dist/proxmox/index.d.ts +43 -0
- package/dist/proxmox/index.d.ts.map +1 -0
- package/dist/proxmox/index.js +2322 -0
- package/dist/proxmox/index.js.map +70 -0
- package/dist/proxmox/lease-cache.d.ts +98 -0
- package/dist/proxmox/lease-cache.d.ts.map +1 -0
- package/dist/proxmox/lxc.d.ts +59 -0
- package/dist/proxmox/lxc.d.ts.map +1 -0
- package/dist/proxmox/members.d.ts +56 -0
- package/dist/proxmox/members.d.ts.map +1 -0
- package/dist/proxmox/metric-server-form.d.ts +53 -0
- package/dist/proxmox/metric-server-form.d.ts.map +1 -0
- package/dist/proxmox/metric-server-otel.d.ts +49 -0
- package/dist/proxmox/metric-server-otel.d.ts.map +1 -0
- package/dist/proxmox/metric-server.d.ts +123 -0
- package/dist/proxmox/metric-server.d.ts.map +1 -0
- package/dist/proxmox/network-apply-read.d.ts +93 -0
- package/dist/proxmox/network-apply-read.d.ts.map +1 -0
- package/dist/proxmox/network-apply.d.ts +102 -0
- package/dist/proxmox/network-apply.d.ts.map +1 -0
- package/dist/proxmox/node-network-form.d.ts +128 -0
- package/dist/proxmox/node-network-form.d.ts.map +1 -0
- package/dist/proxmox/node-network.d.ts +173 -0
- package/dist/proxmox/node-network.d.ts.map +1 -0
- package/dist/proxmox/notification-target-form.d.ts +44 -0
- package/dist/proxmox/notification-target-form.d.ts.map +1 -0
- package/dist/proxmox/notification-target.d.ts +146 -0
- package/dist/proxmox/notification-target.d.ts.map +1 -0
- package/dist/proxmox/pbs-datastore-form.d.ts +147 -0
- package/dist/proxmox/pbs-datastore-form.d.ts.map +1 -0
- package/dist/proxmox/pbs-datastore-guard.d.ts +55 -0
- package/dist/proxmox/pbs-datastore-guard.d.ts.map +1 -0
- package/dist/proxmox/pbs-datastore.d.ts +140 -0
- package/dist/proxmox/pbs-datastore.d.ts.map +1 -0
- package/dist/proxmox/pbs-prune-job-form.d.ts +97 -0
- package/dist/proxmox/pbs-prune-job-form.d.ts.map +1 -0
- package/dist/proxmox/pbs-prune-job.d.ts +168 -0
- package/dist/proxmox/pbs-prune-job.d.ts.map +1 -0
- package/dist/proxmox/pbs-sync-job-form.d.ts +83 -0
- package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -0
- package/dist/proxmox/pbs-sync-job.d.ts +246 -0
- package/dist/proxmox/pbs-sync-job.d.ts.map +1 -0
- package/dist/proxmox/pbs-verify-job-form.d.ts +114 -0
- package/dist/proxmox/pbs-verify-job-form.d.ts.map +1 -0
- package/dist/proxmox/pbs-verify-job.d.ts +145 -0
- package/dist/proxmox/pbs-verify-job.d.ts.map +1 -0
- package/dist/proxmox/pool.d.ts +42 -0
- package/dist/proxmox/pool.d.ts.map +1 -0
- package/dist/proxmox/qemu.d.ts +46 -0
- package/dist/proxmox/qemu.d.ts.map +1 -0
- package/dist/proxmox/replication-job-form.d.ts +71 -0
- package/dist/proxmox/replication-job-form.d.ts.map +1 -0
- package/dist/proxmox/replication-job.d.ts +162 -0
- package/dist/proxmox/replication-job.d.ts.map +1 -0
- package/dist/proxmox/resource.d.ts +157 -0
- package/dist/proxmox/resource.d.ts.map +1 -0
- package/dist/proxmox/role.d.ts +97 -0
- package/dist/proxmox/role.d.ts.map +1 -0
- package/dist/proxmox/sdn-apply-read.d.ts +80 -0
- package/dist/proxmox/sdn-apply-read.d.ts.map +1 -0
- package/dist/proxmox/sdn-apply.d.ts +63 -0
- package/dist/proxmox/sdn-apply.d.ts.map +1 -0
- package/dist/proxmox/sdn-subnet-form.d.ts +111 -0
- package/dist/proxmox/sdn-subnet-form.d.ts.map +1 -0
- package/dist/proxmox/sdn-subnet.d.ts +161 -0
- package/dist/proxmox/sdn-subnet.d.ts.map +1 -0
- package/dist/proxmox/sdn-vnet.d.ts +113 -0
- package/dist/proxmox/sdn-vnet.d.ts.map +1 -0
- package/dist/proxmox/sdn-zone.d.ts +126 -0
- package/dist/proxmox/sdn-zone.d.ts.map +1 -0
- package/dist/proxmox/storage.d.ts +120 -0
- package/dist/proxmox/storage.d.ts.map +1 -0
- package/dist/proxmox/user.d.ts +107 -0
- package/dist/proxmox/user.d.ts.map +1 -0
- package/dist/proxmox/values.d.ts +134 -0
- package/dist/proxmox/values.d.ts.map +1 -0
- package/dist/proxmox/zfs-pool-write.d.ts +76 -0
- package/dist/proxmox/zfs-pool-write.d.ts.map +1 -0
- package/dist/proxmox/zfs-pool.d.ts +146 -0
- package/dist/proxmox/zfs-pool.d.ts.map +1 -0
- package/dist/talos/credentials.d.ts +30 -0
- package/dist/talos/credentials.d.ts.map +1 -0
- package/dist/talos/index.d.ts +15 -0
- package/dist/talos/index.d.ts.map +1 -0
- package/dist/talos/index.js +392 -0
- package/dist/talos/index.js.map +16 -0
- package/dist/talos/kubeconfig.d.ts +53 -0
- package/dist/talos/kubeconfig.d.ts.map +1 -0
- package/dist/talos/resource.d.ts +32 -0
- package/dist/talos/resource.d.ts.map +1 -0
- package/dist/talos/talos-bootstrap.d.ts +27 -0
- package/dist/talos/talos-bootstrap.d.ts.map +1 -0
- package/dist/talos/talos-cluster-health.d.ts +36 -0
- package/dist/talos/talos-cluster-health.d.ts.map +1 -0
- package/dist/talos/talos-machine-config.d.ts +41 -0
- package/dist/talos/talos-machine-config.d.ts.map +1 -0
- package/dist/talos/talosctl.d.ts +29 -0
- package/dist/talos/talosctl.d.ts.map +1 -0
- package/dist/talos/values.d.ts +20 -0
- package/dist/talos/values.d.ts.map +1 -0
- package/package.json +57 -0
- package/src/cloudflare/client.ts +76 -0
- package/src/cloudflare/index.ts +10 -0
- package/src/cloudflare/lock-rules.ts +60 -0
- package/src/cloudflare/providers.ts +23 -0
- package/src/cloudflare/r2-bucket-lock.ts +220 -0
- package/src/forgejo/branch-protection-form.ts +29 -0
- package/src/forgejo/branch-protection.ts +101 -0
- package/src/forgejo/client.ts +136 -0
- package/src/forgejo/index.ts +17 -0
- package/src/forgejo/org-actions-secrets.ts +99 -0
- package/src/forgejo/org-label.ts +100 -0
- package/src/forgejo/org-team.ts +105 -0
- package/src/forgejo/repo-webhook-form.ts +47 -0
- package/src/forgejo/repo-webhook.ts +118 -0
- package/src/forgejo/repository.ts +126 -0
- package/src/forgejo/resource.ts +171 -0
- package/src/forgejo/team-member.ts +97 -0
- package/src/forgejo/values.test.ts +48 -0
- package/src/forgejo/values.ts +61 -0
- package/src/index.ts +18 -0
- package/src/openbao/auth-role-form.ts +112 -0
- package/src/openbao/auth-role.ts +101 -0
- package/src/openbao/bao-address.test.ts +89 -0
- package/src/openbao/bao-address.ts +97 -0
- package/src/openbao/bao-http-gate.test.ts +88 -0
- package/src/openbao/bao-http-unix.test.ts +70 -0
- package/src/openbao/bao-http.test.ts +161 -0
- package/src/openbao/bao-http.ts +185 -0
- package/src/openbao/bao-status.test.ts +114 -0
- package/src/openbao/bao-status.ts +137 -0
- package/src/openbao/cloudflare-group-scope.test.ts +103 -0
- package/src/openbao/cloudflare-group-scope.ts +83 -0
- package/src/openbao/cloudflare-parity-catalog.ts +104 -0
- package/src/openbao/cloudflare-parity-snapshot.ts +84 -0
- package/src/openbao/cloudflare-parity.ts +152 -0
- package/src/openbao/cloudflare-permission-groups-solve.test.ts +171 -0
- package/src/openbao/cloudflare-permission-groups-solve.ts +197 -0
- package/src/openbao/cloudflare-permission-groups.test.ts +369 -0
- package/src/openbao/cloudflare-permission-groups.ts +299 -0
- package/src/openbao/cloudflare-policy.ts +180 -0
- package/src/openbao/cloudflare-role-form.test.ts +177 -0
- package/src/openbao/cloudflare-role-form.ts +183 -0
- package/src/openbao/cloudflare-role-wire.test.ts +132 -0
- package/src/openbao/cloudflare-role-wire.ts +41 -0
- package/src/openbao/cloudflare-role.ts +189 -0
- package/src/openbao/cloudflare-roles-config.ts +230 -0
- package/src/openbao/cloudflare-roles-expand-bucket.test.ts +134 -0
- package/src/openbao/cloudflare-roles-expand.ts +231 -0
- package/src/openbao/digest.ts +26 -0
- package/src/openbao/fake-bao.ts +84 -0
- package/src/openbao/forgejo-bootstrap-parse.test.ts +76 -0
- package/src/openbao/forgejo-bootstrap-parse.ts +90 -0
- package/src/openbao/forgejo-bootstrap.ts +181 -0
- package/src/openbao/index.ts +17 -0
- package/src/openbao/mount-form.ts +147 -0
- package/src/openbao/mount-wire.test.ts +108 -0
- package/src/openbao/mount-wire.ts +79 -0
- package/src/openbao/mount.ts +132 -0
- package/src/openbao/pki-role-form.ts +248 -0
- package/src/openbao/pki-role.ts +202 -0
- package/src/openbao/policy-assembly.test.ts +28 -0
- package/src/openbao/policy-assembly.ts +13 -0
- package/src/openbao/policy-wire.test.ts +90 -0
- package/src/openbao/policy-wire.ts +53 -0
- package/src/openbao/policy.ts +212 -0
- package/src/openbao/proxmox-role-form.ts +174 -0
- package/src/openbao/proxmox-role.ts +214 -0
- package/src/openbao/ssh-role-form.ts +248 -0
- package/src/openbao/ssh-role.ts +240 -0
- package/src/proxmox/acl.ts +267 -0
- package/src/proxmox/api-token-form.ts +122 -0
- package/src/proxmox/api-token.ts +222 -0
- package/src/proxmox/backup-job.ts +213 -0
- package/src/proxmox/ceph-daemon-form.ts +84 -0
- package/src/proxmox/ceph-daemon.ts +243 -0
- package/src/proxmox/ceph-flag.ts +249 -0
- package/src/proxmox/ceph-fs-wire.ts +246 -0
- package/src/proxmox/ceph-fs.ts +249 -0
- package/src/proxmox/ceph-osd-tree.ts +193 -0
- package/src/proxmox/ceph-osd-write.ts +76 -0
- package/src/proxmox/ceph-osd.ts +244 -0
- package/src/proxmox/ceph-pool-form.ts +249 -0
- package/src/proxmox/ceph-pool-settle.ts +70 -0
- package/src/proxmox/ceph-pool.ts +212 -0
- package/src/proxmox/client.test.ts +185 -0
- package/src/proxmox/client.ts +240 -0
- package/src/proxmox/credentials.test.ts +144 -0
- package/src/proxmox/credentials.ts +254 -0
- package/src/proxmox/firewall-alias-form.ts +112 -0
- package/src/proxmox/firewall-alias.ts +208 -0
- package/src/proxmox/generated/pbs.ts +461 -0
- package/src/proxmox/generated/pve.ts +7344 -0
- package/src/proxmox/group.ts +199 -0
- package/src/proxmox/ha-resource.ts +169 -0
- package/src/proxmox/ha-rule-form.ts +185 -0
- package/src/proxmox/ha-rule.ts +240 -0
- package/src/proxmox/index.ts +42 -0
- package/src/proxmox/lease-cache.test.ts +163 -0
- package/src/proxmox/lease-cache.ts +131 -0
- package/src/proxmox/lxc.ts +117 -0
- package/src/proxmox/members.test.ts +54 -0
- package/src/proxmox/members.ts +174 -0
- package/src/proxmox/metric-server-form.ts +128 -0
- package/src/proxmox/metric-server-otel.ts +99 -0
- package/src/proxmox/metric-server.ts +214 -0
- package/src/proxmox/network-apply-read.ts +228 -0
- package/src/proxmox/network-apply.ts +244 -0
- package/src/proxmox/node-network-form.ts +213 -0
- package/src/proxmox/node-network.ts +243 -0
- package/src/proxmox/notification-target-form.ts +104 -0
- package/src/proxmox/notification-target.ts +222 -0
- package/src/proxmox/pbs-datastore-form.ts +248 -0
- package/src/proxmox/pbs-datastore-guard.ts +105 -0
- package/src/proxmox/pbs-datastore.ts +271 -0
- package/src/proxmox/pbs-prune-job-form.ts +208 -0
- package/src/proxmox/pbs-prune-job.ts +227 -0
- package/src/proxmox/pbs-sync-job-form.ts +234 -0
- package/src/proxmox/pbs-sync-job.ts +258 -0
- package/src/proxmox/pbs-verify-job-form.ts +131 -0
- package/src/proxmox/pbs-verify-job.ts +227 -0
- package/src/proxmox/pool.test.ts +42 -0
- package/src/proxmox/pool.ts +80 -0
- package/src/proxmox/qemu.ts +89 -0
- package/src/proxmox/replication-job-form.ts +89 -0
- package/src/proxmox/replication-job.ts +248 -0
- package/src/proxmox/resource.ts +257 -0
- package/src/proxmox/role.ts +161 -0
- package/src/proxmox/sdn-apply-read.test.ts +152 -0
- package/src/proxmox/sdn-apply-read.ts +189 -0
- package/src/proxmox/sdn-apply.ts +154 -0
- package/src/proxmox/sdn-subnet-form.ts +156 -0
- package/src/proxmox/sdn-subnet.ts +238 -0
- package/src/proxmox/sdn-vnet.ts +228 -0
- package/src/proxmox/sdn-zone.ts +246 -0
- package/src/proxmox/storage.ts +245 -0
- package/src/proxmox/user.ts +214 -0
- package/src/proxmox/values.test.ts +193 -0
- package/src/proxmox/values.ts +203 -0
- package/src/proxmox/zfs-pool-write.ts +130 -0
- package/src/proxmox/zfs-pool.ts +253 -0
- package/src/talos/credentials.ts +136 -0
- package/src/talos/index.ts +14 -0
- package/src/talos/kubeconfig.ts +170 -0
- package/src/talos/resource.ts +31 -0
- package/src/talos/talos-bootstrap.ts +109 -0
- package/src/talos/talos-cluster-health.ts +119 -0
- package/src/talos/talos-machine-config.ts +146 -0
- package/src/talos/talosctl.ts +94 -0
- package/src/talos/values.test.ts +80 -0
- package/src/talos/values.ts +70 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One credential per (target, role) for the life of a run, instead of one per API call.
|
|
3
|
+
*
|
|
4
|
+
* 🔴 THE MEASUREMENT THAT MADE THIS NECESSARY. A single `alchemy plan` plus `deploy` of the TB4
|
|
5
|
+
* stack — 98 resources — left **760 API token entries in `/etc/pve/user.cfg`**, counted on n2
|
|
6
|
+
* immediately afterwards. `mint()` asked OpenBao for a new credential on EVERY call, and each
|
|
7
|
+
* mint creates a real Proxmox token: read, diff, reconcile and read-back each got their own. They
|
|
8
|
+
* drain as the leases expire (760 down to 712 over five minutes), so nothing was broken — but
|
|
9
|
+
* `/etc/pve` is pmxcfs, a REPLICATED cluster filesystem, and every one of those mints is a write
|
|
10
|
+
* to it that all three nodes must agree on. Two plans in quick succession stack thousands.
|
|
11
|
+
*
|
|
12
|
+
* ⛔ AND ON PBS THE COST IS SECONDS, NOT BYTES. `pbs_grant.go` waits for PBS to honour a freshly
|
|
13
|
+
* granted ACL before handing the credential over — measured at about 4.5s, and unavoidable,
|
|
14
|
+
* because PBS caches its parsed ACL config. Per mint. The ten PBS resources in pbs.ts would pay
|
|
15
|
+
* that ten times over for credentials identical to each other.
|
|
16
|
+
*
|
|
17
|
+
* ★ SO THE FIX IS TO STOP THROWING AWAY A CREDENTIAL THAT IS STILL VALID. This is strictly FEWER
|
|
18
|
+
* credentials in existence at once, not more: the lease TTL is untouched, and a token that would
|
|
19
|
+
* have been minted and abandoned is simply never minted. It is the same reasoning
|
|
20
|
+
* `network-apply.ts` already applies by hand when it threads one lease through `pveWith` for its
|
|
21
|
+
* apply and its task poll.
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ THE CACHE IS PROCESS-SCOPED AND THAT IS THE INTENDED LIFETIME. A plan or a deploy is one
|
|
24
|
+
* process; the next one starts cold. Nothing is written to disk, and a credential never outlives
|
|
25
|
+
* the run that minted it.
|
|
26
|
+
*
|
|
27
|
+
* ⛔ IT IS NOT A PERFORMANCE CACHE, SO IT MUST NEVER SERVE A CREDENTIAL THAT COULD DIE MID-CALL.
|
|
28
|
+
* The provision lease is 300s and a deploy can run longer than that. A credential handed out at
|
|
29
|
+
* t+299 would fail the call it was handed to, and the failure surfaces as a 401 — which `read`
|
|
30
|
+
* folds into "absent", which is how a plan comes to say CREATE for an object that exists. That is
|
|
31
|
+
* the exact class of bug this package found three times in one day, so the margin below is
|
|
32
|
+
* deliberately generous rather than tuned.
|
|
33
|
+
*
|
|
34
|
+
* ★ THE MECHANISM IS EFFECT'S OWN `Cache`, AND THE HAND-WRITTEN ONE IT REPLACED WAS WRONG IN
|
|
35
|
+
* EXACTLY THE PLACE A LIBRARY IS NOT. A TTL map alone still minted 89 credentials for 98
|
|
36
|
+
* resources, because Alchemy plans concurrently and every resource missed in the same instant;
|
|
37
|
+
* the in-flight map added to fix that got the first miss right and the failure path wrong. A
|
|
38
|
+
* waiter woken by a FAILED or uncacheable mint claimed the slot without looking again, the
|
|
39
|
+
* waiters overwrote each other's claims, and each one's cleanup deleted somebody else's — the
|
|
40
|
+
* thundering herd back through the error door (found in review 2026-09-14, confirmed by
|
|
41
|
+
* reading). `Cache.get` shares one pending lookup among concurrent callers by design. MEASURED
|
|
42
|
+
* with a probe before this was written: ten concurrent gets on equal-but-distinct key objects ran
|
|
43
|
+
* the lookup once; a zero time-to-live ran it again for the next caller; a failure reached all
|
|
44
|
+
* ten waiters and was not kept.
|
|
45
|
+
*/
|
|
46
|
+
import * as Cache from 'effect/Cache';
|
|
47
|
+
import * as Duration from 'effect/Duration';
|
|
48
|
+
import * as Effect from 'effect/Effect';
|
|
49
|
+
import * as Exit from 'effect/Exit';
|
|
50
|
+
import { type ApiTarget, type PveCredential, type PveRole } from './credentials.ts';
|
|
51
|
+
/**
|
|
52
|
+
* What a credential is cached under.
|
|
53
|
+
*
|
|
54
|
+
* ⛔ KEYED ON THE OPENBAO MOUNT AND ROLE, NOT ON A MEMBER HOSTNAME. A PVE API token is
|
|
55
|
+
* cluster-wide — `user.cfg` is replicated — so n2, n3 and n4 share one credential. Keying on
|
|
56
|
+
* `api` would mint three identical tokens when failover rotates members.
|
|
57
|
+
* ★ THE MOUNT CANNOT COLLIDE ACROSS CLUSTERS: `proxmox-tb4`, `proxmox-ops` and `pbs-tb4` are
|
|
58
|
+
* distinct OpenBao mounts with distinct policies; two estates never share a mount name.
|
|
59
|
+
* ★ A PLAIN OBJECT IS A SAFE KEY BECAUSE EFFECT COMPARES KEYS STRUCTURALLY — two separately built
|
|
60
|
+
* literals with the same fields are one entry, which the probe above measured.
|
|
61
|
+
*/
|
|
62
|
+
export type LeaseKey = {
|
|
63
|
+
readonly mount: string;
|
|
64
|
+
readonly role: PveRole;
|
|
65
|
+
readonly scheme: ApiTarget['scheme'];
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* How long a freshly minted credential may be handed out again.
|
|
69
|
+
*
|
|
70
|
+
* ⛔ ZERO FOR A FAILURE, FOR AN UNKNOWN LIFETIME AND FOR A LEASE INSIDE THE MARGIN. Zero means "do
|
|
71
|
+
* not keep": the callers already waiting on THIS mint still receive its result, and the next
|
|
72
|
+
* caller mints again. Keeping a failure would turn one refused mint into a refused run.
|
|
73
|
+
* ⚠️ EXPORTED FOR THE TEST. The margin is the whole safety property, so it is pinned from both
|
|
74
|
+
* sides of its edge without waiting four minutes of wall clock.
|
|
75
|
+
*/
|
|
76
|
+
export declare const timeToLive: (exit: Exit.Exit<PveCredential, unknown>) => Duration.Duration;
|
|
77
|
+
/**
|
|
78
|
+
* A lease cache over any mint.
|
|
79
|
+
*
|
|
80
|
+
* ⚠️ ONE BEHAVIOUR CHANGED WITH THE MOVE TO `Cache`, DELIBERATELY. Callers waiting on a mint that
|
|
81
|
+
* FAILS now receive that failure, where the hand-written version had each of them mint again.
|
|
82
|
+
* They asked in the same instant for the same credential, and a plan with one failed resource
|
|
83
|
+
* fails either way — so the change is in how many errors the output lists, not in the outcome,
|
|
84
|
+
* and a sealed vault is asked once rather than ninety-eight times.
|
|
85
|
+
* ★ `requireServicesAt: 'lookup'` IS WHAT LETS IT BE BUILT ONCE, AT IMPORT. The mint needs an
|
|
86
|
+
* `HttpClient`; that requirement moves to each `get`, where every caller already has one.
|
|
87
|
+
* ⚠️ EXPORTED FOR THE TEST, which hands it a counting mint instead of calling OpenBao.
|
|
88
|
+
*/
|
|
89
|
+
export declare const makeLeases: <E, R>(mintFor: (key: LeaseKey) => Effect.Effect<PveCredential, E, R>) => Effect.Effect<Cache.Cache<LeaseKey, PveCredential, E, R>, never, never>;
|
|
90
|
+
/**
|
|
91
|
+
* A credential for `role` on `target`: a still-valid lease when one is kept, one shared mint when
|
|
92
|
+
* not.
|
|
93
|
+
*
|
|
94
|
+
* ★ client.ts is the one place that decides to use the cache. `mint` stays exported and unchanged
|
|
95
|
+
* for the caller that reasons about identity rather than cost — network-apply.ts.
|
|
96
|
+
*/
|
|
97
|
+
export declare const leased: (target: ApiTarget, role: PveRole) => Effect.Effect<PveCredential, Error, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
98
|
+
//# sourceMappingURL=lease-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lease-cache.d.ts","sourceRoot":"","sources":["../../src/proxmox/lease-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,KAAK,OAAO,EAAQ,MAAM,kBAAkB,CAAC;AAe1F;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;CACtC,CAAC;AAQF;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,SAAU,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,KAAG,QAAQ,CAAC,QAG3D,CAAC;AAEpB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC,4EACX,CAAC;AASrF;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,WAAY,SAAS,QAAQ,OAAO,8FAA2C,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Proxmox.Lxc` — a container, declared. This is what the estate's provision credential exists for.
|
|
3
|
+
*
|
|
4
|
+
* ★ `hf-provision@pve` HOLDS EXACTLY THE ROLE THIS NEEDS, and nothing more: `LXCProvisioner` on `/`
|
|
5
|
+
* grants VM.Allocate, VM.Audit, VM.Config.{CPU,Disk,HWType,Memory,Network,Options},
|
|
6
|
+
* VM.PowerMgmt, Datastore.AllocateSpace, Datastore.Audit, SDN.Use, Sys.Audit. Read that list as a
|
|
7
|
+
* specification: the credential was scoped to provision containers and to do nothing else.
|
|
8
|
+
*
|
|
9
|
+
* ⛔ `vmid` IS THE PRIMARY KEY AND IT IS CLUSTER-WIDE, not per node. Two resources declaring the
|
|
10
|
+
* same vmid on different nodes are the same object, and PVE will refuse the second with
|
|
11
|
+
* "already exists". It is required rather than allocated here: letting the provider pick the next
|
|
12
|
+
* free id would make the identity of a container depend on the order plans happened to run in.
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ MOST FIELDS ARE CREATE-TIME. `ostemplate` and `storage` are consumed when the rootfs is built
|
|
15
|
+
* and are not readable back afterwards, so they are deliberately NOT compared in `matches` --
|
|
16
|
+
* a provider that diffed them would report an update on every plan, forever. What is compared is
|
|
17
|
+
* what PVE will actually tell you about a running container.
|
|
18
|
+
*/
|
|
19
|
+
import { Resource } from 'alchemy';
|
|
20
|
+
import * as Provider from 'alchemy/Provider';
|
|
21
|
+
import { type PveRequirements, type WithTarget } from './resource.ts';
|
|
22
|
+
export interface LxcProps extends WithTarget {
|
|
23
|
+
/** Which node hosts it. Moving a container between nodes is a migration, not an update. */
|
|
24
|
+
node: string;
|
|
25
|
+
/** ⛔ CLUSTER-WIDE primary key. Required, never auto-allocated — see the ⛔ above. */
|
|
26
|
+
vmid: number;
|
|
27
|
+
/** e.g. `local:vztmpl/debian-13-standard_13.0-1_amd64.tar.zst`. Create-time only. */
|
|
28
|
+
ostemplate: string;
|
|
29
|
+
/** Storage for the rootfs, e.g. `local-zfs`. Create-time only. */
|
|
30
|
+
storage: string;
|
|
31
|
+
hostname?: string;
|
|
32
|
+
/** MiB. Mutable. */
|
|
33
|
+
memory?: number;
|
|
34
|
+
cores?: number;
|
|
35
|
+
/** e.g. `name=eth0,bridge=vmbr0,ip=dhcp`. Mutable. */
|
|
36
|
+
net0?: string;
|
|
37
|
+
/** Start on boot. Mutable. */
|
|
38
|
+
onboot?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface LxcAttributes {
|
|
41
|
+
vmid: number;
|
|
42
|
+
node: string;
|
|
43
|
+
hostname: string;
|
|
44
|
+
memory: number;
|
|
45
|
+
cores: number;
|
|
46
|
+
onboot: boolean;
|
|
47
|
+
/** `running` | `stopped`. Reported, never declared — power state is not configuration. */
|
|
48
|
+
status: string;
|
|
49
|
+
}
|
|
50
|
+
export interface ProxmoxLxc extends Resource<'Proxmox.Lxc', LxcProps, LxcAttributes, never, PveRequirements> {
|
|
51
|
+
}
|
|
52
|
+
export declare const ProxmoxLxc: import("alchemy").ResourceClass<ProxmoxLxc>;
|
|
53
|
+
/**
|
|
54
|
+
* ⛔ PVE REFUSES TO DELETE A RUNNING CONTAINER, and that refusal is kept — `handlers.delete`
|
|
55
|
+
* passes it straight through. Stopping a guest so that a `destroy` can proceed is a decision an
|
|
56
|
+
* operator makes, not one a plan makes on their behalf while they are reading the diff.
|
|
57
|
+
*/
|
|
58
|
+
export declare const ProxmoxLxcProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxLxc>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
59
|
+
//# sourceMappingURL=lxc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lxc.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAAsC,CAAC;AAgD9D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gIACgD,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TB4 cluster members: ordered failover, last-good preference, transport classification.
|
|
3
|
+
*
|
|
4
|
+
* ★ ANY MEMBER'S :8006 API MANAGES THE WHOLE CLUSTER — PVE proxies node paths itself — so the
|
|
5
|
+
* provider reaches the cluster through whichever member is up, not through one pinned node.
|
|
6
|
+
*
|
|
7
|
+
* ⛔ NEVER cluster-tb4.example.com: it resolves to 10.20.10.250, which nothing serves.
|
|
8
|
+
*/
|
|
9
|
+
import * as Effect from 'effect/Effect';
|
|
10
|
+
import * as HttpClient from 'effect/unstable/http/HttpClient';
|
|
11
|
+
import type * as HttpClientRequest from 'effect/unstable/http/HttpClientRequest';
|
|
12
|
+
import type * as HttpClientResponse from 'effect/unstable/http/HttpClientResponse';
|
|
13
|
+
import type { PveTarget } from './credentials.ts';
|
|
14
|
+
export declare const PVE_API_PORT = 8006;
|
|
15
|
+
/** Strict TLS, always :8006 — each node's certificate carries its mgmt name as a SAN. */
|
|
16
|
+
export declare const pveApiBase: (member: string) => string;
|
|
17
|
+
/** ⚠️ TESTS ONLY — resets sticky member choice between cases. */
|
|
18
|
+
export declare const resetLastGoodForTest: () => void;
|
|
19
|
+
export declare const noteGoodMember: (target: PveTarget, member: string) => void;
|
|
20
|
+
/** Last-good first, then the rest in configuration order. */
|
|
21
|
+
export declare const orderedMembers: (target: PveTarget) => readonly string[];
|
|
22
|
+
/**
|
|
23
|
+
* Effect HttpClientError.reason._tag — see effect HttpClientError.ts RequestError vs ResponseError.
|
|
24
|
+
* ★ TransportError | InvalidUrlError | EncodeError occur before a response exists; StatusCodeError
|
|
25
|
+
* and kin include a response. client.execute does NOT filter status, so HTTP answers are never
|
|
26
|
+
* TransportError — only the transport layer is.
|
|
27
|
+
*/
|
|
28
|
+
export declare const isTransportFailure: (cause: unknown) => boolean;
|
|
29
|
+
/** Pre-send only: connection refused, DNS, a certificate refused — never a timeout after connect. */
|
|
30
|
+
export declare const isPreSendTransport: (cause: unknown) => boolean;
|
|
31
|
+
export declare const describeTransport: (cause: unknown) => string;
|
|
32
|
+
export type MemberAttempt = {
|
|
33
|
+
readonly member: string;
|
|
34
|
+
readonly why: string;
|
|
35
|
+
};
|
|
36
|
+
export type PveMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
37
|
+
/**
|
|
38
|
+
* Run one request against cluster members with failover.
|
|
39
|
+
*
|
|
40
|
+
* ⛔ A POST/PUT/DELETE WHOSE REQUEST MAY HAVE REACHED A MEMBER MUST NOT BE SENT AGAIN TO ANOTHER.
|
|
41
|
+
* Only fail over a write on a provably pre-send transport failure — connection refused, DNS or a
|
|
42
|
+
* refused certificate. A timeout after sending is NOT pre-send: fail it, never repeat it. An HTTP
|
|
43
|
+
* status of any kind, including 5xx and PVE's 596, is the answer from a live member — retrying
|
|
44
|
+
* elsewhere can repeat a write.
|
|
45
|
+
*
|
|
46
|
+
* ★ Reads fail over on any transport failure, including timeout — no side effect to duplicate.
|
|
47
|
+
* MEASURED 2026-09-14: full TB4 plans stayed all-noop with the first member refused (127.0.0.1)
|
|
48
|
+
* and with it unresolvable (n9.invalid).
|
|
49
|
+
*/
|
|
50
|
+
export declare const executeOnCluster: (target: PveTarget, method: PveMethod, path: string, build: (apiBase: string) => HttpClientRequest.HttpClientRequest) => Effect.Effect<HttpClientResponse.HttpClientResponse, {
|
|
51
|
+
readonly tag: 'cluster';
|
|
52
|
+
readonly method: PveMethod;
|
|
53
|
+
readonly path: string;
|
|
54
|
+
readonly attempts: readonly MemberAttempt[];
|
|
55
|
+
}, HttpClient.HttpClient>;
|
|
56
|
+
//# sourceMappingURL=members.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../../src/proxmox/members.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAE9D,OAAO,KAAK,KAAK,iBAAiB,MAAM,wCAAwC,CAAC;AACjF,OAAO,KAAK,KAAK,kBAAkB,MAAM,yCAAyC,CAAC;AACnF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,eAAO,MAAM,YAAY,OAAO,CAAC;AAEjC,yFAAyF;AACzF,eAAO,MAAM,UAAU,WAAY,MAAM,WAA0D,CAAC;AAKpG,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,YAAgC,CAAC;AAElE,eAAO,MAAM,cAAc,WAAY,SAAS,UAAU,MAAM,SAE/D,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,cAAc,WAAY,SAAS,KAAG,SAAS,MAAM,EAIjE,CAAC;AA2CF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,UAAW,OAAO,KAAG,OAInD,CAAC;AAEF,qGAAqG;AACrG,eAAO,MAAM,kBAAkB,UAAW,OAAO,KAAG,OASnD,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAW,OAAO,KAAG,MAGlD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9E,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,WACnB,SAAS,UACT,SAAS,QACX,MAAM,SACL,CAAC,OAAO,EAAE,MAAM,KAAK,iBAAiB,CAAC,iBAAiB,KAC9D,MAAM,CAAC,MAAM,CACd,kBAAkB,CAAC,kBAAkB,EACrC;IACE,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CAC7C,EACD,UAAU,CAAC,UAAU,CAmCnB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A metric server's props, as the form PVE wants.
|
|
3
|
+
*
|
|
4
|
+
* ★ SPLIT OUT OF metric-server.ts TO KEEP BOTH FILES UNDER THE 250-LINE CAP, and the seam is a
|
|
5
|
+
* real one rather than a convenient line number: this file answers "how does a declaration
|
|
6
|
+
* become a PVE form", and metric-server.ts answers "what is a metric server and when has it
|
|
7
|
+
* changed". Nothing here reads the cluster and nothing here decides a diff.
|
|
8
|
+
*
|
|
9
|
+
* ⚠️ THE `import type` BACK TO metric-server.ts IS A CYCLE ON PAPER ONLY. It is type-only, so it
|
|
10
|
+
* is erased before anything runs — `MetricServerProps` stays the resource's public shape, in the
|
|
11
|
+
* file that declares the resource, rather than being moved somewhere odd to dodge the arrow.
|
|
12
|
+
* metric-server-otel.ts imports `UNSET` from here and this file imports nothing back from it,
|
|
13
|
+
* so no runtime cycle exists either.
|
|
14
|
+
*/
|
|
15
|
+
import type { MetricServerProps } from './metric-server.ts';
|
|
16
|
+
/**
|
|
17
|
+
* ⚠️ "NOT SET" CANNOT BE 0 HERE, WHICH IS WHY IT IS -1. `timeout` has a minimum of 0 in PVE's
|
|
18
|
+
* schema, so a deliberate `timeout 0` exists; a provider using 0 as its absent-marker reads that
|
|
19
|
+
* zero as "unset" and never clears it. -1 is outside every one of these fields' ranges.
|
|
20
|
+
*/
|
|
21
|
+
export declare const UNSET = -1;
|
|
22
|
+
/**
|
|
23
|
+
* Every managed optional, per type: the value to send, or undefined for "clear it".
|
|
24
|
+
*
|
|
25
|
+
* ⛔ ONE TABLE FEEDS BOTH HALVES OF AN UPDATE, AND THAT IS THE POINT. A PUT THAT OMITS A FIELD DOES
|
|
26
|
+
* NOT CLEAR IT — PVE merges the form into the existing section — so a managed optional needs a
|
|
27
|
+
* matching `delete=` the moment its prop goes away, or `matches` reports an update on every plan
|
|
28
|
+
* forever. Deriving the form and the delete list from one map makes "managed but not clearable"
|
|
29
|
+
* impossible to write here, which a separate clear-list would not.
|
|
30
|
+
* ⛔ NOTHING SET OUT OF BAND MAY BE LISTED HERE, `token` FIRST AMONG THEM: a field in this map is
|
|
31
|
+
* CLEARED whenever it is undeclared, so adding the token would strip a working target's
|
|
32
|
+
* credential on the next plan — metrics stop, nothing errors, the graph goes flat. `otel-headers`
|
|
33
|
+
* is absent for the same reason: it is where an OTLP server's bearer token lives.
|
|
34
|
+
* ⚠️ AND THE BRANCHES CANNOT BE ONE SHARED MAP. PVE validates a section against that plugin's own
|
|
35
|
+
* option set, so `path` on an influxdb server is a hard 400 and `delete=path` there answers "no
|
|
36
|
+
* such option" — neither is an ignored hint. The opentelemetry plugin has no `mtu` and no
|
|
37
|
+
* `timeout` at all (its option list is `server`, `port`, `disable` and the `otel-*` family), so
|
|
38
|
+
* that branch carries neither.
|
|
39
|
+
* ⚠️ graphite's `proto` (udp or tcp) is deliberately absent: a transport chosen by hand stays put
|
|
40
|
+
* and no plan diffs it. Managing it means adding it HERE, where it is clearable by construction.
|
|
41
|
+
* `otel-resource-attributes` is absent for the reason metric-server-otel.ts gives.
|
|
42
|
+
*/
|
|
43
|
+
export declare const optional: (props: MetricServerProps) => Record<string, string | undefined>;
|
|
44
|
+
export declare const body: (props: MetricServerProps) => Record<string, string>;
|
|
45
|
+
/**
|
|
46
|
+
* An update's form: everything `body` sends, plus a `delete=` naming each managed optional that is
|
|
47
|
+
* no longer declared.
|
|
48
|
+
*
|
|
49
|
+
* ★ MOVED HERE FROM metric-server.ts UNCHANGED, so the test beside this file can reach the form an
|
|
50
|
+
* update really sends instead of re-deriving it and testing its own copy.
|
|
51
|
+
*/
|
|
52
|
+
export declare const update: (props: MetricServerProps) => Record<string, string>;
|
|
53
|
+
//# sourceMappingURL=metric-server-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metric-server-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/metric-server-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D;;;;GAIG;AACH,eAAO,MAAM,KAAK,KAAK,CAAC;AAIxB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,QAAQ,UAAW,iBAAiB,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAuBpF,CAAC;AAqCF,eAAO,MAAM,IAAI,UAAW,iBAAiB,2BAM5C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,UAAW,iBAAiB,2BAK9C,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface MetricServerOtelProps {
|
|
2
|
+
/**
|
|
3
|
+
* ⚠️ PVE'S DEFAULT IS `https`. `http` is for a receiver on the node itself, where the plaintext
|
|
4
|
+
* never leaves the host; anything further away belongs on `https`.
|
|
5
|
+
*/
|
|
6
|
+
'otel-protocol'?: 'http' | 'https';
|
|
7
|
+
/** Unset is PVE's `/v1/metrics`. */
|
|
8
|
+
'otel-path'?: string;
|
|
9
|
+
/** Unset is PVE's `gzip`, sent as `Content-Encoding: gzip`. */
|
|
10
|
+
'otel-compression'?: 'none' | 'gzip';
|
|
11
|
+
/**
|
|
12
|
+
* Per-request HTTP timeout, 1-10 seconds; unset is PVE's 5.
|
|
13
|
+
* ⚠️ pvestatd WAITS THIS LONG, PER REQUEST, AGAINST A RECEIVER THAT HANGS — the send is inline in
|
|
14
|
+
* its update loop (`send`, line 635) — so this is also how long a broken receiver can stretch
|
|
15
|
+
* one status cycle.
|
|
16
|
+
*/
|
|
17
|
+
'otel-timeout'?: number;
|
|
18
|
+
/** Minimum 1024; unset is PVE's 10000000. pvestatd splits one flush into requests under it. */
|
|
19
|
+
'otel-max-body-size'?: number;
|
|
20
|
+
/** ⚠️ An unset `otel-verify-ssl` means VERIFY — PVE's default, and the safe one. */
|
|
21
|
+
'otel-verify-ssl'?: boolean;
|
|
22
|
+
/** ⛔ `never` ON PURPOSE — see the ⛔ in the header. The compile error is the feature. */
|
|
23
|
+
'otel-headers'?: never;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* ⚠️ THE SAME RULES AS THE REST OF `MetricServerAttributes`. The strings report `''` when the
|
|
27
|
+
* section carries none — PVE's default is then what the target uses — the numbers report `UNSET`
|
|
28
|
+
* for the same reason, and `otel-verify-ssl` reports its default directly, because "absent"
|
|
29
|
+
* there means the target verifies.
|
|
30
|
+
*/
|
|
31
|
+
export interface MetricServerOtelAttributes {
|
|
32
|
+
'otel-compression': string;
|
|
33
|
+
'otel-max-body-size': number;
|
|
34
|
+
'otel-path': string;
|
|
35
|
+
'otel-protocol': string;
|
|
36
|
+
'otel-timeout': number;
|
|
37
|
+
'otel-verify-ssl': boolean;
|
|
38
|
+
}
|
|
39
|
+
/** The `otel-*` half of a live section. Read for every type; compared only for this one. */
|
|
40
|
+
export declare const otelAttributes: (live: Record<string, unknown>) => MetricServerOtelAttributes;
|
|
41
|
+
/**
|
|
42
|
+
* True when every managed `otel-*` field already says what the declaration says.
|
|
43
|
+
*
|
|
44
|
+
* ⛔ EVERY FIELD `optional` SENDS OR CLEARS IS COMPARED HERE, AND NOTHING ELSE IS. A field sent but
|
|
45
|
+
* not compared is drift a plan can never show; a field compared but not sent is an update the
|
|
46
|
+
* PUT it triggers can never satisfy, reported forever.
|
|
47
|
+
*/
|
|
48
|
+
export declare const otelMatches: (attributes: MetricServerOtelAttributes, props: MetricServerOtelProps) => boolean;
|
|
49
|
+
//# sourceMappingURL=metric-server-otel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metric-server-otel.d.ts","sourceRoot":"","sources":["../../src/proxmox/metric-server-otel.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+FAA+F;IAC/F,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oFAAoF;IACpF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,wFAAwF;IACxF,cAAc,CAAC,EAAE,KAAK,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,4FAA4F;AAC5F,eAAO,MAAM,cAAc,SAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,0BAO7D,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,eACV,0BAA0B,SAC/B,qBAAqB,KAC3B,OAMqE,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Proxmox.MetricServer` — where the cluster ships its metrics, declared.
|
|
3
|
+
*
|
|
4
|
+
* ★ THE FAILURE THIS PREVENTS IS A SILENT ONE, WHICH IS THE WHOLE ARGUMENT FOR DECLARING IT.
|
|
5
|
+
* Undeclared, the target exists only as a section of `/etc/pve/status.cfg`: rebuild a node,
|
|
6
|
+
* re-add one to the cluster, or restore a config from before it was configured, and the cluster
|
|
7
|
+
* stops shipping. Nothing fails, no task errors, no alert fires — the graphs go flat, and the
|
|
8
|
+
* first to find out is whoever went looking for a number that was not there.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ CREATE IS `POST cluster/metrics/server/{id}` — THE OBJECT'S OWN PATH — SO `collection()`
|
|
11
|
+
* RETURNS THE SAME STRING AS `path()`, AND THAT IS NOT A TYPO. MEASURED: a POST to the
|
|
12
|
+
* collection answers "Method 'POST /cluster/metrics/server' not implemented", while the id path
|
|
13
|
+
* gets as far as a permission check (`/`, Sys.Modify); the published schema agrees, giving the
|
|
14
|
+
* collection a GET and nothing else. `createForm` omits `id` for the same reason — it is already
|
|
15
|
+
* the last segment of the path being POSTed to, and a second copy can only disagree with it.
|
|
16
|
+
*
|
|
17
|
+
* ⛔ THE `token` IS WRITE-ONLY AND MUST NEVER BECOME AN ATTRIBUTE. Alchemy persists attributes
|
|
18
|
+
* UNENCRYPTED, so one that reached state would outlive the change that set it, in the state
|
|
19
|
+
* store and in every backup of it. It is `never` in the props below — declaring one is a COMPILE
|
|
20
|
+
* ERROR rather than a leak found months later — and absent from `optional`, for the reason
|
|
21
|
+
* given there. Set it out of band; PVE never returns it on a read anyway. `otel-headers`, where an
|
|
22
|
+
* opentelemetry server's bearer token lives, gets the same treatment in metric-server-otel.ts.
|
|
23
|
+
*
|
|
24
|
+
* ⚠️ PRIVILEGES, AND THIS IS A BIGGER ASK THAN IT LOOKS. Read and diff are fine under an auditor
|
|
25
|
+
* lease — the single-object GET checks `Sys.Audit` on `/` — while create, update and delete all
|
|
26
|
+
* check `Sys.Modify` on `/` and answer "Permission check failed (/, Sys.Modify)" until the role
|
|
27
|
+
* is widened. Widen it knowingly: the ACL path is the ROOT and there is no `/metrics` object to
|
|
28
|
+
* scope to, so `Sys.Modify` also buys datacenter options, notification targets and every other
|
|
29
|
+
* cluster-wide config write. A separate role for metric writes is the narrower answer.
|
|
30
|
+
*/
|
|
31
|
+
import { Resource } from 'alchemy';
|
|
32
|
+
import * as Provider from 'alchemy/Provider';
|
|
33
|
+
import { type MetricServerOtelAttributes, type MetricServerOtelProps } from './metric-server-otel.ts';
|
|
34
|
+
import { type PveRequirements, type WithTarget } from './resource.ts';
|
|
35
|
+
/**
|
|
36
|
+
* PVE's status plugins. Which one a server is decides which fields it will even accept.
|
|
37
|
+
*
|
|
38
|
+
* ★ `opentelemetry` IS OFFERED SINCE 2026-09-14, AND THE REASON IT WAS NOT STILL HOLDS FOR ANY FIELD
|
|
39
|
+
* LEFT OUT. Its whole configuration is the `otel-*` family; declared without managing that family
|
|
40
|
+
* it would build a target whose every meaningful setting sat outside the graph, and report `noop`
|
|
41
|
+
* over it. metric-server-otel.ts manages every `otel-*` field but two, and says why for each.
|
|
42
|
+
*/
|
|
43
|
+
export type MetricServerType = 'graphite' | 'influxdb' | 'opentelemetry';
|
|
44
|
+
export interface MetricServerProps extends WithTarget, MetricServerOtelProps {
|
|
45
|
+
/** ⚠️ A `pve-configid` — a letter, then letters, digits, `-` and `_`. A rejected one fails with
|
|
46
|
+
* "invalid configuration ID", which reads as a broken request rather than as a naming rule. */
|
|
47
|
+
id: string;
|
|
48
|
+
/**
|
|
49
|
+
* ⛔ CREATE-TIME ONLY. The PUT schema has no `type` parameter at all: a section's type is fixed
|
|
50
|
+
* when it is written, so the ⛔ in `attributes` turns a changed type into a refusal rather than
|
|
51
|
+
* a silent no-op over the wrong target.
|
|
52
|
+
*/
|
|
53
|
+
type: MetricServerType;
|
|
54
|
+
/** ⚠️ REQUIRED ON EVERY WRITE, UPDATE INCLUDED — see `required`. */
|
|
55
|
+
server: string;
|
|
56
|
+
port: number;
|
|
57
|
+
/** Keep the section but stop shipping. Unset is an ENABLED target, not an absent one. */
|
|
58
|
+
disable?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* graphite and influxdb only: UDP MTU (512-65536) and socket/HTTP timeout. Unset leaves PVE's
|
|
61
|
+
* defaults, 1500 and 1. ⚠️ opentelemetry has neither; its timeout is `otel-timeout`.
|
|
62
|
+
*/
|
|
63
|
+
mtu?: number;
|
|
64
|
+
timeout?: number;
|
|
65
|
+
/** graphite only: the root path metrics are published under, e.g. `proxmox.mycluster`. */
|
|
66
|
+
path?: string;
|
|
67
|
+
/**
|
|
68
|
+
* influxdb only. `udp` is PVE's default and writes line protocol; `http`/`https` use the v2 API,
|
|
69
|
+
* the only place `organization` and `bucket` mean anything. An unset `verify-certificate` means
|
|
70
|
+
* VERIFY — PVE's default, and the safe one.
|
|
71
|
+
* ⚠️ PVE's hyphenated names are kept rather than camelCased, so nothing between here and the form
|
|
72
|
+
* body has to remember a mapping.
|
|
73
|
+
*/
|
|
74
|
+
influxdbproto?: 'udp' | 'http' | 'https';
|
|
75
|
+
organization?: string;
|
|
76
|
+
bucket?: string;
|
|
77
|
+
'api-path-prefix'?: string;
|
|
78
|
+
'max-body-size'?: number;
|
|
79
|
+
'verify-certificate'?: boolean;
|
|
80
|
+
/** ⛔ `never` ON PURPOSE — see the ⛔ in the header. The compile error is the feature. */
|
|
81
|
+
token?: never;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* ⛔ NO `digest`, ON PURPOSE. PVE returns one with every read, but it is the digest of the WHOLE
|
|
85
|
+
* `status.cfg` rather than of this section — declaring a SECOND metric server would rewrite this
|
|
86
|
+
* one's stored attributes, and comparing it would report an update on a target nobody touched.
|
|
87
|
+
* ⛔ And no `token`, for the reason the header gives at length.
|
|
88
|
+
* ⚠️ `mtu`, `timeout` and `max-body-size` report `UNSET` when the section carries none, i.e. when
|
|
89
|
+
* PVE's own default is what the target will use; `verify-certificate` reports that default
|
|
90
|
+
* directly, because "absent" there means the target verifies. `port` reports 0 only for a
|
|
91
|
+
* malformed section — PVE requires a port — so a plan should say so loudly. The `otel-*` half
|
|
92
|
+
* follows the same rules; see metric-server-otel.ts.
|
|
93
|
+
*/
|
|
94
|
+
export interface MetricServerAttributes extends MetricServerOtelAttributes {
|
|
95
|
+
id: string;
|
|
96
|
+
type: MetricServerType;
|
|
97
|
+
server: string;
|
|
98
|
+
port: number;
|
|
99
|
+
disable: boolean;
|
|
100
|
+
mtu: number;
|
|
101
|
+
timeout: number;
|
|
102
|
+
path: string;
|
|
103
|
+
influxdbproto: string;
|
|
104
|
+
organization: string;
|
|
105
|
+
bucket: string;
|
|
106
|
+
'api-path-prefix': string;
|
|
107
|
+
'max-body-size': number;
|
|
108
|
+
'verify-certificate': boolean;
|
|
109
|
+
}
|
|
110
|
+
export interface ProxmoxMetricServer extends Resource<'Proxmox.MetricServer', MetricServerProps, MetricServerAttributes, never, PveRequirements> {
|
|
111
|
+
}
|
|
112
|
+
export declare const ProxmoxMetricServer: import("alchemy").ResourceClass<ProxmoxMetricServer>;
|
|
113
|
+
/**
|
|
114
|
+
* ⛔ THE EMPTY `list` FROM `pveHandlers` EARNS ITS KEEP HERE. `GET cluster/metrics/server` answers
|
|
115
|
+
* with every target the cluster already ships to, including the one somebody configured by hand
|
|
116
|
+
* years ago; adopting that is how a later `alchemy destroy` silences a graph nobody declared.
|
|
117
|
+
* ⚠️ AND NOTHING BRAKES THIS DESTROY. A pool refuses while it holds guests, a container while it
|
|
118
|
+
* runs; a metric server just leaves `status.cfg`, the cluster stops shipping on the next
|
|
119
|
+
* interval, and no guest or task is affected. The plan diff is the only warning anyone gets —
|
|
120
|
+
* the top of this file again, this time caused by a deploy.
|
|
121
|
+
*/
|
|
122
|
+
export declare const ProxmoxMetricServerProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxMetricServer>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
123
|
+
//# sourceMappingURL=metric-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metric-server.d.ts","sourceRoot":"","sources":["../../src/proxmox/metric-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAG3B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,UAAU,GAAG,eAAe,CAAC;AAEzE,MAAM,WAAW,iBAAkB,SAAQ,UAAU,EAAE,qBAAqB;IAC1E;qGACiG;IACjG,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,IAAI,EAAE,gBAAgB,CAAC;IACvB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,wFAAwF;IACxF,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,sBAAuB,SAAQ,0BAA0B;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAoB,SAAQ,QAAQ,CACnD,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,mBAAmB,sDAAwD,CAAC;AA0EzF;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,yIACyD,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How this package finds out what a node has STAGED, and whether the cluster survived an apply.
|
|
3
|
+
*
|
|
4
|
+
* ★ SPLIT OUT OF network-apply.ts TO KEEP BOTH FILES UNDER THE 250-LINE CAP, and the seam is a real
|
|
5
|
+
* one rather than a convenient line number: this file answers "what is true on the cluster right
|
|
6
|
+
* now", network-apply.ts answers "what does the resource do about it". Nothing here decides a
|
|
7
|
+
* diff, and the only write in either file is the apply itself.
|
|
8
|
+
*
|
|
9
|
+
* ⛔ THE PENDING STATE IS NOT IN `data`, WHICH IS WHY THIS FILE DOES ITS OWN FETCH. MEASURED in the
|
|
10
|
+
* cluster's own source on n2, 2026-09-13 — not inferred from documentation:
|
|
11
|
+
* PVE/API2/Network.pm my $tmp = PVE::INotify::read_file('interfaces', 1);
|
|
12
|
+
* $rpcenv->set_result_attrib('changes', $changes) if $changes;
|
|
13
|
+
* PVE/HTTPServer.pm if (my $diff = $rpcenv->get_result_attrib('changes')) {
|
|
14
|
+
* $resp->{changes} = $diff;
|
|
15
|
+
* }
|
|
16
|
+
* So the answer is `{"data":[…interfaces…],"changes":"<unified diff>"}`: `changes` is a SIBLING
|
|
17
|
+
* of `data`, set only when the diff is non-empty. `client.ts`'s `pve()` returns `body.data` and
|
|
18
|
+
* drops the envelope, so the one readable pending signal is invisible to every other resource in
|
|
19
|
+
* this package. Without the fetch below, `Proxmox.NetworkApply` could not diff honestly at all.
|
|
20
|
+
* ★ `pveEnvelopeWith` in client.ts now carries the same member failover as every other call.
|
|
21
|
+
*
|
|
22
|
+
* ⛔ AND THE INTERFACE ROWS CANNOT TELL YOU EITHER. MEASURED in PVE/INotify.pm `read_file`: when
|
|
23
|
+
* `/etc/network/interfaces.new` exists, THAT is the file that gets parsed, so
|
|
24
|
+
* `GET /nodes/{node}/network` answers with the STAGED config and a node about to be reconfigured
|
|
25
|
+
* looks identical to one already running it. Same trap `sdn-apply.ts` documents for `?running=1`.
|
|
26
|
+
*
|
|
27
|
+
* ⚠️ `active` IS NOT A PENDING SIGNAL, AND THE OBVIOUS SHORTCUT IS MEASURABLY WRONG. On n2 and n3,
|
|
28
|
+
* with nothing staged anywhere (VERIFIED 2026-09-13: `/etc/network/interfaces.new` absent on n2,
|
|
29
|
+
* n3 and n4), `wlp91s0` already comes back with no `active` key at all. Counting interfaces that
|
|
30
|
+
* are not up as "pending" would report an update on two of the three nodes forever.
|
|
31
|
+
*
|
|
32
|
+
* ⚠️ ONE THING GENUINELY CANNOT BE SEEN FROM HERE, AND IT IS SMALL. The diff is computed as
|
|
33
|
+
* `diff -b -N -u`, so a staged file differing from the live one ONLY in whitespace produces no
|
|
34
|
+
* `changes` at all. This module reports that node as settled while `interfaces.new` still sits
|
|
35
|
+
* there waiting for the next reload anybody triggers. The file's existence is not exposed by the
|
|
36
|
+
* API in any other form, so the alternative is not a better read — it is SSH.
|
|
37
|
+
*/
|
|
38
|
+
import * as Effect from 'effect/Effect';
|
|
39
|
+
import { type PveCredential, type PveTarget } from './credentials.ts';
|
|
40
|
+
/** What the cluster looked like the moment it was asked. Never persisted — see network-apply.ts. */
|
|
41
|
+
export type ClusterHealth = {
|
|
42
|
+
quorate: boolean;
|
|
43
|
+
offline: readonly string[];
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Changed lines in a unified diff.
|
|
47
|
+
*
|
|
48
|
+
* ⚠️ A NON-EMPTY DIFF IS NEVER REPORTED AS ZERO, WHICH IS WHAT `Math.max` IS FOR. The `+++`/`---`
|
|
49
|
+
* headers have to be skipped, and a removed line whose own text starts with `---` is skipped with
|
|
50
|
+
* them; a staged change consisting of nothing else would otherwise count 0 and be reported as
|
|
51
|
+
* "settled", which is the exact lie this resource exists to prevent. The count is informational —
|
|
52
|
+
* the resource only ever compares it to zero — so an occasional undercount of 1 is harmless while
|
|
53
|
+
* an undercount to zero is not.
|
|
54
|
+
*/
|
|
55
|
+
export declare const pendingLines: (diff: string) => number;
|
|
56
|
+
/** How many staged lines this node is carrying. Zero is the only settled value. */
|
|
57
|
+
export declare const pendingCount: (target: PveTarget, node: string) => Effect.Effect<number, Error, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
58
|
+
/**
|
|
59
|
+
* Why the cluster is not healthy, or `undefined` when it is.
|
|
60
|
+
*
|
|
61
|
+
* ★ A REASON RATHER THAN A BOOLEAN, BECAUSE THE CALLER'S ONLY USE FOR IT IS A REFUSAL MESSAGE.
|
|
62
|
+
* "The deploy stopped because the cluster was degraded" is not actionable at three in the
|
|
63
|
+
* morning; "quorate=true offline=[n3]" is. The two callers in network-apply.ts ask this before
|
|
64
|
+
* the reload and again after it, and the second answer is the one that stops the chain from
|
|
65
|
+
* reaching the next node.
|
|
66
|
+
*
|
|
67
|
+
* ⚠️ A MEMBER OFFLINE FOR AN UNRELATED REASON BLOCKS EVERY APPLY, AND THAT IS THE INTENDED
|
|
68
|
+
* BEHAVIOUR RATHER THAN AN OVERSIGHT. A node down for maintenance is one failure away from the
|
|
69
|
+
* pools losing min_size; reloading another node's networking while it is out is the move that
|
|
70
|
+
* completes the outage. Bring it back, or apply by hand with the cluster in front of you.
|
|
71
|
+
*/
|
|
72
|
+
export declare const degradedReason: (target: PveTarget) => Effect.Effect<string | undefined, Error, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
73
|
+
/**
|
|
74
|
+
* ⛔ NOT AN EXITSTATUS PVE CAN RETURN, AND THAT IS THE POINT. The caller compares against `'OK'`;
|
|
75
|
+
* these two say WHY the answer is not OK without needing a second branch for "we do not know".
|
|
76
|
+
*/
|
|
77
|
+
export declare const UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
|
|
78
|
+
/**
|
|
79
|
+
* Wait for one `srvreload` task and answer its exitstatus.
|
|
80
|
+
*
|
|
81
|
+
* ⛔ THE APPLY IS ASYNCHRONOUS AND ITS 200 MEANS NOTHING. MEASURED: `reload_network_config` ends
|
|
82
|
+
* `return $rpcenv->fork_worker('srvreload', 'networking', $authuser, $worker)`, so the PUT
|
|
83
|
+
* returns a UPID the instant the worker is forked — before `ifreload -a` has run, let alone
|
|
84
|
+
* succeeded. Waiting for the task is the only way to learn the outcome.
|
|
85
|
+
*
|
|
86
|
+
* ⛔ AND IT MUST BE POLLED WITH THE CREDENTIAL THAT STARTED IT. The task-status schema says
|
|
87
|
+
* `"user": "all"` with the note "needs 'Sys.Audit' on '/nodes/<node>' if they are not the owner
|
|
88
|
+
* of the task". Every mint returns a NEW token id, so a second mint is a different identity and
|
|
89
|
+
* is not the owner — which is why this takes a `PveCredential` and the caller keeps one lease
|
|
90
|
+
* across both calls, instead of widening the provisioning role to read its own tasks.
|
|
91
|
+
*/
|
|
92
|
+
export declare const awaitTask: (target: PveTarget, credential: PveCredential, node: string, upid: string) => Effect.Effect<string, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
93
|
+
//# sourceMappingURL=network-apply-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-apply-read.d.ts","sourceRoot":"","sources":["../../src/proxmox/network-apply-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAatE,oGAAoG;AACpG,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AA0B7E;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,SAAU,MAAM,WAWxC,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,YAAY,WAAY,SAAS,QAAQ,MAAM,uFACH,CAAC;AAiC1D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,WAAY,SAAS,mGAO7C,CAAC;AAEJ;;;GAGG;AACH,eAAO,MAAM,WAAW,0FACiE,CAAC;AAY1F;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,WACZ,SAAS,cACL,aAAa,QACnB,MAAM,QACN,MAAM,uFAgCV,CAAC"}
|