@homeflare/alchemy 0.14.0 → 0.19.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/README.md +29 -0
- package/dist/linux/directory-lifecycle.d.ts +50 -0
- package/dist/linux/directory-lifecycle.d.ts.map +1 -0
- package/dist/linux/directory.d.ts +19 -0
- package/dist/linux/directory.d.ts.map +1 -0
- package/dist/linux/fake-linux-host.d.ts +35 -0
- package/dist/linux/fake-linux-host.d.ts.map +1 -0
- package/dist/linux/fake-systemd.d.ts +34 -0
- package/dist/linux/fake-systemd.d.ts.map +1 -0
- package/dist/linux/index.d.ts +27 -0
- package/dist/linux/index.d.ts.map +1 -0
- package/dist/linux/index.js +1554 -0
- package/dist/linux/index.js.map +37 -0
- package/dist/linux/providers.d.ts +17 -0
- package/dist/linux/providers.d.ts.map +1 -0
- package/dist/linux/region.d.ts +43 -0
- package/dist/linux/region.d.ts.map +1 -0
- package/dist/linux/remote-file-form.d.ts +47 -0
- package/dist/linux/remote-file-form.d.ts.map +1 -0
- package/dist/linux/remote-file-lifecycle.d.ts +36 -0
- package/dist/linux/remote-file-lifecycle.d.ts.map +1 -0
- package/dist/linux/remote-file-plan.d.ts +33 -0
- package/dist/linux/remote-file-plan.d.ts.map +1 -0
- package/dist/linux/remote-file.d.ts +28 -0
- package/dist/linux/remote-file.d.ts.map +1 -0
- package/dist/linux/ssh-command.d.ts +68 -0
- package/dist/linux/ssh-command.d.ts.map +1 -0
- package/dist/linux/ssh-runner.d.ts +22 -0
- package/dist/linux/ssh-runner.d.ts.map +1 -0
- package/dist/linux/ssh-scripts.d.ts +27 -0
- package/dist/linux/ssh-scripts.d.ts.map +1 -0
- package/dist/linux/systemctl.d.ts +67 -0
- package/dist/linux/systemctl.d.ts.map +1 -0
- package/dist/linux/unit-form.d.ts +78 -0
- package/dist/linux/unit-form.d.ts.map +1 -0
- package/dist/linux/unit-handlers.d.ts +15 -0
- package/dist/linux/unit-handlers.d.ts.map +1 -0
- package/dist/linux/unit-lifecycle.d.ts +44 -0
- package/dist/linux/unit-lifecycle.d.ts.map +1 -0
- package/dist/linux/unit-settle.d.ts +31 -0
- package/dist/linux/unit-settle.d.ts.map +1 -0
- package/dist/linux/unit.d.ts +35 -0
- package/dist/linux/unit.d.ts.map +1 -0
- package/dist/netbox/client.d.ts +52 -0
- package/dist/netbox/client.d.ts.map +1 -0
- package/dist/netbox/constraint-guard.d.ts +26 -0
- package/dist/netbox/constraint-guard.d.ts.map +1 -0
- package/dist/netbox/constraints.d.ts +76 -0
- package/dist/netbox/constraints.d.ts.map +1 -0
- package/dist/netbox/generated/constraints/index.d.ts +19 -0
- package/dist/netbox/generated/constraints/index.d.ts.map +1 -0
- package/dist/netbox/generated/constraints/netbox-ipam.d.ts +21 -0
- package/dist/netbox/generated/constraints/netbox-ipam.d.ts.map +1 -0
- package/dist/netbox/index.d.ts +17 -0
- package/dist/netbox/index.d.ts.map +1 -0
- package/dist/netbox/index.js +331 -0
- package/dist/netbox/index.js.map +18 -0
- package/dist/netbox/prefix-form.d.ts +54 -0
- package/dist/netbox/prefix-form.d.ts.map +1 -0
- package/dist/netbox/prefix.d.ts +80 -0
- package/dist/netbox/prefix.d.ts.map +1 -0
- package/dist/netbox/resource.d.ts +94 -0
- package/dist/netbox/resource.d.ts.map +1 -0
- package/dist/netbox/values.d.ts +24 -0
- package/dist/netbox/values.d.ts.map +1 -0
- package/dist/openbao/index.d.ts +10 -3
- package/dist/openbao/index.d.ts.map +1 -1
- package/dist/proxmox/acl.d.ts.map +1 -1
- package/dist/proxmox/api-token-form.d.ts.map +1 -1
- package/dist/proxmox/apply-endpoints.d.ts +30 -0
- package/dist/proxmox/apply-endpoints.d.ts.map +1 -0
- package/dist/proxmox/backup-job.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon-form.d.ts +29 -1
- package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
- package/dist/proxmox/ceph-flag.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +19 -0
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool.d.ts.map +1 -1
- package/dist/proxmox/constraint-guard.d.ts +28 -0
- package/dist/proxmox/constraint-guard.d.ts.map +1 -0
- package/dist/proxmox/constraints.d.ts +94 -0
- package/dist/proxmox/constraints.d.ts.map +1 -0
- package/dist/proxmox/firewall-alias.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/index.d.ts +19 -0
- package/dist/proxmox/generated/constraints/index.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pbs-config.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pbs-config.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-access.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-access.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-pools.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-pools.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-storage.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-storage.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/access-users.d.ts +137 -0
- package/dist/proxmox/generated/pbs/access-users.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/access.d.ts +171 -0
- package/dist/proxmox/generated/pbs/access.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/admin-datastore-store.d.ts +252 -0
- package/dist/proxmox/generated/pbs/admin-datastore-store.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/admin-metrics.d.ts +147 -0
- package/dist/proxmox/generated/pbs/admin-metrics.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/admin.d.ts +217 -0
- package/dist/proxmox/generated/pbs/admin.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/backup.d.ts +114 -0
- package/dist/proxmox/generated/pbs/backup.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-access-pam.d.ts +218 -0
- package/dist/proxmox/generated/pbs/config-access-pam.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-access.d.ts +203 -0
- package/dist/proxmox/generated/pbs/config-access.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-datastore.d.ts +195 -0
- package/dist/proxmox/generated/pbs/config-datastore.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-media-pool.d.ts +207 -0
- package/dist/proxmox/generated/pbs/config-media-pool.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-notifications-matchers.d.ts +159 -0
- package/dist/proxmox/generated/pbs/config-notifications-matchers.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-notifications.d.ts +199 -0
- package/dist/proxmox/generated/pbs/config-notifications.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-remote.d.ts +175 -0
- package/dist/proxmox/generated/pbs/config-remote.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-sync.d.ts +145 -0
- package/dist/proxmox/generated/pbs/config-sync.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-tape.d.ts +200 -0
- package/dist/proxmox/generated/pbs/config-tape.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config-verify.d.ts +77 -0
- package/dist/proxmox/generated/pbs/config-verify.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/config.d.ts +119 -0
- package/dist/proxmox/generated/pbs/config.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/nodes-node-dns.d.ts +178 -0
- package/dist/proxmox/generated/pbs/nodes-node-dns.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/nodes-node-services.d.ts +205 -0
- package/dist/proxmox/generated/pbs/nodes-node-services.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/nodes-node.d.ts +166 -0
- package/dist/proxmox/generated/pbs/nodes-node.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/nodes.d.ts +171 -0
- package/dist/proxmox/generated/pbs/nodes.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/ping.d.ts +18 -0
- package/dist/proxmox/generated/pbs/ping.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/pull.d.ts +37 -0
- package/dist/proxmox/generated/pbs/pull.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/push.d.ts +36 -0
- package/dist/proxmox/generated/pbs/push.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/reader.d.ts +41 -0
- package/dist/proxmox/generated/pbs/reader.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/root.d.ts +16 -0
- package/dist/proxmox/generated/pbs/root.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/status.d.ts +54 -0
- package/dist/proxmox/generated/pbs/status.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/tape-drive.d.ts +181 -0
- package/dist/proxmox/generated/pbs/tape-drive.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/tape-media.d.ts +126 -0
- package/dist/proxmox/generated/pbs/tape-media.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/tape.d.ts +90 -0
- package/dist/proxmox/generated/pbs/tape.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs/version.d.ts +20 -0
- package/dist/proxmox/generated/pbs/version.d.ts.map +1 -0
- package/dist/proxmox/generated/pbs.d.ts +44 -662
- package/dist/proxmox/generated/pbs.d.ts.map +1 -1
- package/dist/proxmox/generated/pve/access-roles.d.ts +164 -0
- package/dist/proxmox/generated/pve/access-roles.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/access-users.d.ts +152 -0
- package/dist/proxmox/generated/pve/access-users.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/access.d.ts +221 -0
- package/dist/proxmox/generated/pve/access.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-acme-plugins-id.d.ts +45 -0
- package/dist/proxmox/generated/pve/cluster-acme-plugins-id.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-acme-plugins.d.ts +47 -0
- package/dist/proxmox/generated/pve/cluster-acme-plugins.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-acme-tos.d.ts +240 -0
- package/dist/proxmox/generated/pve/cluster-acme-tos.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-bulk-action.d.ts +200 -0
- package/dist/proxmox/generated/pve/cluster-bulk-action.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-firewall-refs.d.ts +109 -0
- package/dist/proxmox/generated/pve/cluster-firewall-refs.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-firewall.d.ts +225 -0
- package/dist/proxmox/generated/pve/cluster-firewall.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-ha.d.ts +199 -0
- package/dist/proxmox/generated/pve/cluster-ha.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-jobs.d.ts +183 -0
- package/dist/proxmox/generated/pve/cluster-jobs.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-metrics.d.ts +110 -0
- package/dist/proxmox/generated/pve/cluster-metrics.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-notifications-endpoints.d.ts +224 -0
- package/dist/proxmox/generated/pve/cluster-notifications-endpoints.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-notifications.d.ts +91 -0
- package/dist/proxmox/generated/pve/cluster-notifications.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-options.d.ts +85 -0
- package/dist/proxmox/generated/pve/cluster-options.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.d.ts +48 -0
- package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models.d.ts +45 -0
- package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-replication.d.ts +130 -0
- package/dist/proxmox/generated/pve/cluster-replication.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-sdn-fabrics.d.ts +220 -0
- package/dist/proxmox/generated/pve/cluster-sdn-fabrics.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-sdn-ipams.d.ts +229 -0
- package/dist/proxmox/generated/pve/cluster-sdn-ipams.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-sdn-vnets-vnet.d.ts +229 -0
- package/dist/proxmox/generated/pve/cluster-sdn-vnets-vnet.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-sdn-vnets.d.ts +51 -0
- package/dist/proxmox/generated/pve/cluster-sdn-vnets.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-sdn-zones.d.ts +225 -0
- package/dist/proxmox/generated/pve/cluster-sdn-zones.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster-sdn.d.ts +202 -0
- package/dist/proxmox/generated/pve/cluster-sdn.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/cluster.d.ts +69 -0
- package/dist/proxmox/generated/pve/cluster.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-ceph.d.ts +167 -0
- package/dist/proxmox/generated/pve/nodes-node-ceph.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-config.d.ts +43 -0
- package/dist/proxmox/generated/pve/nodes-node-config.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-disks.d.ts +225 -0
- package/dist/proxmox/generated/pve/nodes-node-disks.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-firewall.d.ts +145 -0
- package/dist/proxmox/generated/pve/nodes-node-firewall.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-hardware.d.ts +195 -0
- package/dist/proxmox/generated/pve/nodes-node-hardware.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.d.ts +191 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.d.ts +33 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.d.ts +56 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-resize.d.ts +28 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-resize.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.d.ts +186 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid.d.ts +191 -0
- package/dist/proxmox/generated/pve/nodes-node-lxc-vmid.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-network.d.ts +150 -0
- package/dist/proxmox/generated/pve/nodes-node-network.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-config.d.ts +301 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-config.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.d.ts +170 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.d.ts +144 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.d.ts +34 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.d.ts +137 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-status.d.ts +179 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-status.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid.d.ts +143 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu-vmid.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu.d.ts +158 -0
- package/dist/proxmox/generated/pve/nodes-node-qemu.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-replication.d.ts +187 -0
- package/dist/proxmox/generated/pve/nodes-node-replication.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-services.d.ts +115 -0
- package/dist/proxmox/generated/pve/nodes-node-services.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-storage-storage.d.ts +202 -0
- package/dist/proxmox/generated/pve/nodes-node-storage-storage.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-storage.d.ts +40 -0
- package/dist/proxmox/generated/pve/nodes-node-storage.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-subscription.d.ts +173 -0
- package/dist/proxmox/generated/pve/nodes-node-subscription.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node-vzdump.d.ts +97 -0
- package/dist/proxmox/generated/pve/nodes-node-vzdump.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes-node.d.ts +207 -0
- package/dist/proxmox/generated/pve/nodes-node.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/nodes.d.ts +236 -0
- package/dist/proxmox/generated/pve/nodes.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/pools.d.ts +82 -0
- package/dist/proxmox/generated/pve/pools.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/storage.d.ts +159 -0
- package/dist/proxmox/generated/pve/storage.d.ts.map +1 -0
- package/dist/proxmox/generated/pve/version.d.ts +21 -0
- package/dist/proxmox/generated/pve/version.d.ts.map +1 -0
- package/dist/proxmox/generated/pve.d.ts +69 -4766
- package/dist/proxmox/generated/pve.d.ts.map +1 -1
- package/dist/proxmox/group.d.ts.map +1 -1
- package/dist/proxmox/ha-resource.d.ts.map +1 -1
- package/dist/proxmox/ha-rule.d.ts.map +1 -1
- package/dist/proxmox/index.d.ts +6 -1
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +1483 -300
- package/dist/proxmox/index.js.map +70 -45
- package/dist/proxmox/lxc-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/metric-server-form.d.ts +11 -0
- package/dist/proxmox/metric-server-form.d.ts.map +1 -1
- package/dist/proxmox/metric-server.d.ts.map +1 -1
- package/dist/proxmox/network-apply.d.ts.map +1 -1
- package/dist/proxmox/node-network-form.d.ts +15 -0
- package/dist/proxmox/node-network-form.d.ts.map +1 -1
- package/dist/proxmox/node-network.d.ts.map +1 -1
- package/dist/proxmox/notification-matcher.d.ts.map +1 -1
- package/dist/proxmox/notification-target-endpoint.d.ts +26 -0
- package/dist/proxmox/notification-target-endpoint.d.ts.map +1 -0
- package/dist/proxmox/notification-target-form.d.ts +7 -0
- package/dist/proxmox/notification-target-form.d.ts.map +1 -1
- package/dist/proxmox/notification-target.d.ts.map +1 -1
- package/dist/proxmox/pbs-datastore-endpoint.d.ts +22 -0
- package/dist/proxmox/pbs-datastore-endpoint.d.ts.map +1 -0
- package/dist/proxmox/pbs-datastore.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-matcher.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-target-endpoint.d.ts +29 -0
- package/dist/proxmox/pbs-notification-target-endpoint.d.ts.map +1 -0
- package/dist/proxmox/pbs-notification-target-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/pbs-prune-job.d.ts.map +1 -1
- package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -1
- package/dist/proxmox/pbs-verify-job.d.ts.map +1 -1
- package/dist/proxmox/pool.d.ts.map +1 -1
- package/dist/proxmox/provision-baseline.d.ts +30 -5
- package/dist/proxmox/provision-baseline.d.ts.map +1 -1
- package/dist/proxmox/qemu.d.ts +10 -0
- package/dist/proxmox/qemu.d.ts.map +1 -1
- package/dist/proxmox/replication-job.d.ts.map +1 -1
- package/dist/proxmox/resource-guard.d.ts +15 -0
- package/dist/proxmox/resource-guard.d.ts.map +1 -0
- package/dist/proxmox/resource-spec.d.ts +131 -0
- package/dist/proxmox/resource-spec.d.ts.map +1 -0
- package/dist/proxmox/resource.d.ts +17 -90
- package/dist/proxmox/resource.d.ts.map +1 -1
- package/dist/proxmox/role.d.ts.map +1 -1
- package/dist/proxmox/sdn-apply.d.ts.map +1 -1
- package/dist/proxmox/sdn-subnet.d.ts.map +1 -1
- package/dist/proxmox/sdn-vnet.d.ts.map +1 -1
- package/dist/proxmox/sdn-zone.d.ts.map +1 -1
- package/dist/proxmox/storage.d.ts.map +1 -1
- package/dist/proxmox/user.d.ts.map +1 -1
- package/dist/proxmox/zfs-pool-write.d.ts +11 -0
- package/dist/proxmox/zfs-pool-write.d.ts.map +1 -1
- package/dist/proxmox/zfs-pool.d.ts.map +1 -1
- package/docs/linux-host-measured.md +56 -0
- package/docs/linux-host.md +186 -0
- package/docs/netbox.md +103 -0
- package/docs/provision-baseline.md +34 -7
- package/docs/proxmox-lxc.md +40 -0
- package/package.json +9 -1
- package/src/linux/directory-lifecycle.ts +220 -0
- package/src/linux/directory.test.ts +132 -0
- package/src/linux/directory.ts +71 -0
- package/src/linux/fake-linux-host.ts +197 -0
- package/src/linux/fake-systemd.ts +103 -0
- package/src/linux/index.ts +32 -0
- package/src/linux/providers.ts +26 -0
- package/src/linux/region.test.ts +89 -0
- package/src/linux/region.ts +118 -0
- package/src/linux/remote-file-form.ts +96 -0
- package/src/linux/remote-file-lifecycle.test.ts +191 -0
- package/src/linux/remote-file-lifecycle.ts +161 -0
- package/src/linux/remote-file-plan.ts +154 -0
- package/src/linux/remote-file.ts +88 -0
- package/src/linux/ssh-command.test.ts +140 -0
- package/src/linux/ssh-command.ts +99 -0
- package/src/linux/ssh-runner.ts +188 -0
- package/src/linux/ssh-scripts.ts +105 -0
- package/src/linux/systemctl.ts +145 -0
- package/src/linux/unit-form.ts +183 -0
- package/src/linux/unit-handlers.ts +73 -0
- package/src/linux/unit-lifecycle.test.ts +220 -0
- package/src/linux/unit-lifecycle.ts +193 -0
- package/src/linux/unit-settle.ts +110 -0
- package/src/linux/unit.ts +81 -0
- package/src/netbox/client.test.ts +67 -0
- package/src/netbox/client.ts +146 -0
- package/src/netbox/constraint-guard.ts +57 -0
- package/src/netbox/constraints.test.ts +114 -0
- package/src/netbox/constraints.ts +152 -0
- package/src/netbox/generated/constraints/index.ts +23 -0
- package/src/netbox/generated/constraints/netbox-ipam.ts +32 -0
- package/src/netbox/index.ts +34 -0
- package/src/netbox/prefix-form.test.ts +127 -0
- package/src/netbox/prefix-form.ts +84 -0
- package/src/netbox/prefix.ts +136 -0
- package/src/netbox/resource.ts +208 -0
- package/src/netbox/values.test.ts +66 -0
- package/src/netbox/values.ts +40 -0
- package/src/openbao/index-types.test.ts +87 -0
- package/src/openbao/index.ts +15 -3
- package/src/proxmox/acl.ts +2 -0
- package/src/proxmox/api-token-form.ts +5 -0
- package/src/proxmox/apply-endpoints.ts +34 -0
- package/src/proxmox/backup-job.ts +2 -0
- package/src/proxmox/ceph-daemon-form.ts +56 -2
- package/src/proxmox/ceph-daemon.ts +10 -21
- package/src/proxmox/ceph-flag.ts +1 -0
- package/src/proxmox/ceph-fs.ts +1 -0
- package/src/proxmox/ceph-osd-write.ts +30 -4
- package/src/proxmox/ceph-pool.ts +10 -0
- package/src/proxmox/constraint-guard.ts +53 -0
- package/src/proxmox/constraints-dialect.test.ts +165 -0
- package/src/proxmox/constraints-forms.test.ts +220 -0
- package/src/proxmox/constraints-host-forms.test.ts +132 -0
- package/src/proxmox/constraints-live.test.ts +155 -0
- package/src/proxmox/constraints-node-forms.test.ts +188 -0
- package/src/proxmox/constraints-required.test.ts +172 -0
- package/src/proxmox/constraints.test.ts +205 -0
- package/src/proxmox/constraints.ts +160 -0
- package/src/proxmox/firewall-alias.ts +5 -0
- package/src/proxmox/generated/constraints/index.ts +55 -0
- package/src/proxmox/generated/constraints/pbs-config.ts +203 -0
- package/src/proxmox/generated/constraints/pve-access.ts +69 -0
- package/src/proxmox/generated/constraints/pve-cluster-backup.ts +74 -0
- package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +27 -0
- package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +35 -0
- package/src/proxmox/generated/constraints/pve-cluster-ha.ts +55 -0
- package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +59 -0
- package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +80 -0
- package/src/proxmox/generated/constraints/pve-cluster-replication.ts +43 -0
- package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +90 -0
- package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +57 -0
- package/src/proxmox/generated/constraints/pve-nodes-disks.ts +31 -0
- package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +82 -0
- package/src/proxmox/generated/constraints/pve-nodes-network.ts +77 -0
- package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +125 -0
- package/src/proxmox/generated/constraints/pve-pools.ts +31 -0
- package/src/proxmox/generated/constraints/pve-storage.ts +80 -0
- package/src/proxmox/generated/pbs/access-users.ts +137 -0
- package/src/proxmox/generated/pbs/access.ts +232 -0
- package/src/proxmox/generated/pbs/admin-datastore-store.ts +238 -0
- package/src/proxmox/generated/pbs/admin-metrics.ts +147 -0
- package/src/proxmox/generated/pbs/admin.ts +225 -0
- package/src/proxmox/generated/pbs/backup.ts +121 -0
- package/src/proxmox/generated/pbs/config-access-pam.ts +228 -0
- package/src/proxmox/generated/pbs/config-access.ts +228 -0
- package/src/proxmox/generated/pbs/config-datastore.ts +217 -0
- package/src/proxmox/generated/pbs/config-media-pool.ts +232 -0
- package/src/proxmox/generated/pbs/config-notifications-matchers.ts +187 -0
- package/src/proxmox/generated/pbs/config-notifications.ts +221 -0
- package/src/proxmox/generated/pbs/config-remote.ts +192 -0
- package/src/proxmox/generated/pbs/config-sync.ts +167 -0
- package/src/proxmox/generated/pbs/config-tape.ts +226 -0
- package/src/proxmox/generated/pbs/config-verify.ts +87 -0
- package/src/proxmox/generated/pbs/config.ts +135 -0
- package/src/proxmox/generated/pbs/nodes-node-dns.ts +229 -0
- package/src/proxmox/generated/pbs/nodes-node-services.ts +181 -0
- package/src/proxmox/generated/pbs/nodes-node.ts +244 -0
- package/src/proxmox/generated/pbs/nodes.ts +160 -0
- package/src/proxmox/generated/pbs/ping.ts +16 -0
- package/src/proxmox/generated/pbs/pull.ts +37 -0
- package/src/proxmox/generated/pbs/push.ts +36 -0
- package/src/proxmox/generated/pbs/reader.ts +41 -0
- package/src/proxmox/generated/pbs/root.ts +16 -0
- package/src/proxmox/generated/pbs/status.ts +50 -0
- package/src/proxmox/generated/pbs/tape-drive.ts +220 -0
- package/src/proxmox/generated/pbs/tape-media.ts +133 -0
- package/src/proxmox/generated/pbs/tape.ts +92 -0
- package/src/proxmox/generated/pbs/version.ts +16 -0
- package/src/proxmox/generated/pbs.ts +44 -787
- package/src/proxmox/generated/pve/access-roles.ts +168 -0
- package/src/proxmox/generated/pve/access-users.ts +155 -0
- package/src/proxmox/generated/pve/access.ts +217 -0
- package/src/proxmox/generated/pve/cluster-acme-plugins-id.ts +367 -0
- package/src/proxmox/generated/pve/cluster-acme-plugins.ts +366 -0
- package/src/proxmox/generated/pve/cluster-acme-tos.ts +232 -0
- package/src/proxmox/generated/pve/cluster-bulk-action.ts +227 -0
- package/src/proxmox/generated/pve/cluster-firewall-refs.ts +110 -0
- package/src/proxmox/generated/pve/cluster-firewall.ts +236 -0
- package/src/proxmox/generated/pve/cluster-ha.ts +203 -0
- package/src/proxmox/generated/pve/cluster-jobs.ts +190 -0
- package/src/proxmox/generated/pve/cluster-metrics.ts +116 -0
- package/src/proxmox/generated/pve/cluster-notifications-endpoints.ts +244 -0
- package/src/proxmox/generated/pve/cluster-notifications.ts +99 -0
- package/src/proxmox/generated/pve/cluster-options.ts +189 -0
- package/src/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.ts +272 -0
- package/src/proxmox/generated/pve/cluster-qemu-custom-cpu-models.ts +268 -0
- package/src/proxmox/generated/pve/cluster-replication.ts +127 -0
- package/src/proxmox/generated/pve/cluster-sdn-fabrics.ts +218 -0
- package/src/proxmox/generated/pve/cluster-sdn-ipams.ts +229 -0
- package/src/proxmox/generated/pve/cluster-sdn-vnets-vnet.ts +245 -0
- package/src/proxmox/generated/pve/cluster-sdn-vnets.ts +49 -0
- package/src/proxmox/generated/pve/cluster-sdn-zones.ts +224 -0
- package/src/proxmox/generated/pve/cluster-sdn.ts +201 -0
- package/src/proxmox/generated/pve/cluster.ts +71 -0
- package/src/proxmox/generated/pve/nodes-node-ceph.ts +167 -0
- package/src/proxmox/generated/pve/nodes-node-config.ts +56 -0
- package/src/proxmox/generated/pve/nodes-node-disks.ts +237 -0
- package/src/proxmox/generated/pve/nodes-node-firewall.ts +239 -0
- package/src/proxmox/generated/pve/nodes-node-hardware.ts +215 -0
- package/src/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.ts +232 -0
- package/src/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.ts +1059 -0
- package/src/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.ts +49 -0
- package/src/proxmox/generated/pve/nodes-node-lxc-vmid-resize.ts +285 -0
- package/src/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.ts +184 -0
- package/src/proxmox/generated/pve/nodes-node-lxc-vmid.ts +240 -0
- package/src/proxmox/generated/pve/nodes-node-network.ts +234 -0
- package/src/proxmox/generated/pve/nodes-node-qemu-vmid-config.ts +441 -0
- package/src/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.ts +215 -0
- package/src/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.ts +145 -0
- package/src/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.ts +664 -0
- package/src/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.ts +188 -0
- package/src/proxmox/generated/pve/nodes-node-qemu-vmid-status.ts +233 -0
- package/src/proxmox/generated/pve/nodes-node-qemu-vmid.ts +187 -0
- package/src/proxmox/generated/pve/nodes-node-qemu.ts +204 -0
- package/src/proxmox/generated/pve/nodes-node-replication.ts +187 -0
- package/src/proxmox/generated/pve/nodes-node-services.ts +221 -0
- package/src/proxmox/generated/pve/nodes-node-storage-storage.ts +226 -0
- package/src/proxmox/generated/pve/nodes-node-storage.ts +40 -0
- package/src/proxmox/generated/pve/nodes-node-subscription.ts +168 -0
- package/src/proxmox/generated/pve/nodes-node-vzdump.ts +96 -0
- package/src/proxmox/generated/pve/nodes-node.ts +211 -0
- package/src/proxmox/generated/pve/nodes.ts +235 -0
- package/src/proxmox/generated/pve/pools.ts +78 -0
- package/src/proxmox/generated/pve/storage.ts +213 -0
- package/src/proxmox/generated/pve/version.ts +21 -0
- package/src/proxmox/generated/pve.ts +69 -7403
- package/src/proxmox/group.ts +2 -0
- package/src/proxmox/ha-resource.ts +5 -0
- package/src/proxmox/ha-rule.ts +2 -0
- package/src/proxmox/index.ts +12 -0
- package/src/proxmox/lxc-interior.test.ts +77 -0
- package/src/proxmox/lxc-lifecycle.ts +48 -9
- package/src/proxmox/metric-server-form.ts +10 -0
- package/src/proxmox/metric-server.ts +11 -2
- package/src/proxmox/network-apply.ts +4 -0
- package/src/proxmox/node-network-form.ts +19 -0
- package/src/proxmox/node-network.ts +9 -3
- package/src/proxmox/notification-matcher.ts +5 -0
- package/src/proxmox/notification-target-endpoint.ts +46 -0
- package/src/proxmox/notification-target-form.ts +11 -0
- package/src/proxmox/notification-target.ts +5 -2
- package/src/proxmox/pbs-datastore-endpoint.ts +29 -0
- package/src/proxmox/pbs-datastore.ts +8 -1
- package/src/proxmox/pbs-notification-matcher.ts +5 -0
- package/src/proxmox/pbs-notification-target-endpoint.ts +45 -0
- package/src/proxmox/pbs-notification-target-lifecycle.ts +16 -14
- package/src/proxmox/pbs-prune-job.ts +2 -0
- package/src/proxmox/pbs-sync-job-form.ts +2 -0
- package/src/proxmox/pbs-verify-job.ts +2 -0
- package/src/proxmox/pool.ts +2 -0
- package/src/proxmox/provision-baseline.test.ts +38 -0
- package/src/proxmox/provision-baseline.ts +73 -14
- package/src/proxmox/provision-bootstrap.test.ts +51 -0
- package/src/proxmox/qemu.ts +9 -1
- package/src/proxmox/replication-job.ts +5 -0
- package/src/proxmox/resource-guard.ts +61 -0
- package/src/proxmox/resource-spec.ts +129 -0
- package/src/proxmox/resource.ts +52 -93
- package/src/proxmox/role.ts +2 -0
- package/src/proxmox/sdn-apply.ts +4 -0
- package/src/proxmox/sdn-subnet.ts +5 -0
- package/src/proxmox/sdn-vnet.ts +2 -0
- package/src/proxmox/sdn-zone.ts +2 -0
- package/src/proxmox/storage.ts +2 -0
- package/src/proxmox/user.ts +2 -0
- package/src/proxmox/zfs-pool-write.ts +12 -0
- package/src/proxmox/zfs-pool.ts +2 -1
|
@@ -193,6 +193,8 @@ const handlers = pveHandlers<PbsVerifyJobProps, PbsVerifyJobAttributes>({
|
|
|
193
193
|
* ⚠️ `rechecks` IS ABSENT HERE ON PURPOSE. It is a rendering of the two fields on the lines
|
|
194
194
|
* above; comparing it too would report the same drift twice.
|
|
195
195
|
*/
|
|
196
|
+
/** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
|
|
197
|
+
endpoint: { create: 'pbs:POST /config/verify', update: 'pbs:PUT /config/verify/{id}' },
|
|
196
198
|
matches: (attributes, props) =>
|
|
197
199
|
attributes.store === props.store &&
|
|
198
200
|
// ⚠️ `null` IS COMPARED AGAINST `''`, NOT SKIPPED. A parked job is a declaration like any
|
package/src/proxmox/pool.ts
CHANGED
|
@@ -71,6 +71,8 @@ const handlers = pveHandlers<PoolProps, PoolAttributes>({
|
|
|
71
71
|
},
|
|
72
72
|
collection: () => 'pools',
|
|
73
73
|
createForm: poolCreateForm,
|
|
74
|
+
/** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
|
|
75
|
+
endpoint: { create: 'pve:POST /pools', update: 'pve:PUT /pools/{poolid}' },
|
|
74
76
|
matches: (attributes, props) => attributes.comment === (props.comment ?? ''),
|
|
75
77
|
path: (props) => `pools/${props.poolid}`,
|
|
76
78
|
updateForm: poolUpdateForm,
|
|
@@ -84,4 +84,42 @@ describe('provisionBaseline', () => {
|
|
|
84
84
|
test('refuses one user for both lanes', () => {
|
|
85
85
|
expect(() => provisionBaseline({ readUser: 'hf-provision@pve' })).toThrow(/one user/);
|
|
86
86
|
});
|
|
87
|
+
|
|
88
|
+
test('a comment per object, each defaulting to `comment` on its own', () => {
|
|
89
|
+
// \u2605 THE EXISTING-CLUSTER CASE: the group and the read user already carry their own live
|
|
90
|
+
// comments, and only the provision user is new. One shared comment could not say this.
|
|
91
|
+
const baseline = provisionBaseline({
|
|
92
|
+
comment: 'shared',
|
|
93
|
+
groupComment: '',
|
|
94
|
+
provisionComment: 'mint target: provision (ops)',
|
|
95
|
+
readComment: 'mint target: read (ops)',
|
|
96
|
+
});
|
|
97
|
+
expect(baseline.group.comment).toBe('');
|
|
98
|
+
expect(baseline.users.map((u) => u.comment)).toEqual([
|
|
99
|
+
'mint target: provision (ops)',
|
|
100
|
+
'mint target: read (ops)',
|
|
101
|
+
]);
|
|
102
|
+
// Overriding one leaves the others on `comment`; the generic case is still one string.
|
|
103
|
+
const one = provisionBaseline({ comment: 'shared', provisionComment: 'only this' });
|
|
104
|
+
expect([one.group.comment, ...one.users.map((u) => u.comment)]).toEqual([
|
|
105
|
+
'shared',
|
|
106
|
+
'only this',
|
|
107
|
+
'shared',
|
|
108
|
+
]);
|
|
109
|
+
expect(provisionBaseline({ comment: 'shared' }).group.comment).toBe('shared');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('every comment is refused by its own field name', () => {
|
|
113
|
+
const attempt = () =>
|
|
114
|
+
provisionBaseline({ groupComment: "it's", provisionComment: 'q{x}', readComment: '$(id)' });
|
|
115
|
+
expect(attempt).toThrow(/groupComment.*provisionComment.*readComment/);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('readComment goes with its lane: unchecked, and unused, when readUser is null', () => {
|
|
119
|
+
// ⚠️ Nothing would ever paste it, so refusing it would be a refusal over a field the caller
|
|
120
|
+
// is not using. The lane it belongs to is gone.
|
|
121
|
+
const none = provisionBaseline({ readComment: "would need quoting'", readUser: null });
|
|
122
|
+
expect(none.users.map((u) => u.lane)).toEqual(['provision']);
|
|
123
|
+
expect(() => provisionBaseline({ readComment: "would need quoting'" })).toThrow(/readComment/);
|
|
124
|
+
});
|
|
87
125
|
});
|
|
@@ -54,7 +54,7 @@ export const PROVISION_PRIVILEGES: readonly string[] = Object.freeze([
|
|
|
54
54
|
]);
|
|
55
55
|
|
|
56
56
|
/** The names a baseline uses. Every field has a generic default (`PROVISION_DEFAULTS`). */
|
|
57
|
-
export interface
|
|
57
|
+
export interface CoreProvisionNames {
|
|
58
58
|
/** The role holding `PROVISION_PRIVILEGES` on `/`. */
|
|
59
59
|
readonly role?: string | undefined;
|
|
60
60
|
/** The user OpenBao's `provision` role mints tokens for, realm-qualified. */
|
|
@@ -69,11 +69,41 @@ export interface ProvisionNames {
|
|
|
69
69
|
readonly comment?: string | undefined;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
/** Every name, resolved: what `PROVISION_DEFAULTS` holds and what a baseline is built from. */
|
|
72
|
+
/** Every core name, resolved: what `PROVISION_DEFAULTS` holds and what a baseline is built from. */
|
|
73
73
|
export type ResolvedProvisionNames = {
|
|
74
|
-
readonly [K in keyof
|
|
74
|
+
readonly [K in keyof CoreProvisionNames]-?: Exclude<CoreProvisionNames[K], undefined>;
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* `CoreProvisionNames` plus a comment per object, each defaulting to `comment`.
|
|
79
|
+
*
|
|
80
|
+
* ⛔ WHY PER OBJECT: AN EXISTING CLUSTER IS THE NORMAL CASE, NOT THE EXCEPTION. One `comment` for
|
|
81
|
+
* three objects can only describe a cluster this baseline made. On one that already has a mint
|
|
82
|
+
* group and a read user — with their own live comments, which a stack elsewhere may already
|
|
83
|
+
* declare — a single comment makes `provisionBootstrap` rewrite objects nobody asked it to
|
|
84
|
+
* touch, and the next deploy of that stack writes them back. Measured on an estate cluster
|
|
85
|
+
* 2026-09-22, where `hf-mint` had NO comment and `hf-read@pve` named its own mount.
|
|
86
|
+
* ★ Overriding one does not change the others: `comment` stays the default for every object that
|
|
87
|
+
* has no override, so the generic case is still one string.
|
|
88
|
+
* ⚠️ Each is checked like `comment` is, and a `null` `readUser` drops `readComment` with its lane.
|
|
89
|
+
*/
|
|
90
|
+
export interface ProvisionNames extends CoreProvisionNames {
|
|
91
|
+
/** The mint group's comment. Defaults to `comment`. */
|
|
92
|
+
readonly groupComment?: string | undefined;
|
|
93
|
+
/** The provision user's comment. Defaults to `comment`. */
|
|
94
|
+
readonly provisionComment?: string | undefined;
|
|
95
|
+
/** The read user's comment. Defaults to `comment`. Ignored when `readUser` is `null`. */
|
|
96
|
+
readonly readComment?: string | undefined;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The resolved comment for each object a baseline holds. */
|
|
100
|
+
export type ProvisionComments = {
|
|
101
|
+
readonly [K in 'group' | ProvisionLane]: string;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/** Which credential lane a user or a grant belongs to — the OpenBao role that mints for it. */
|
|
105
|
+
export type ProvisionLane = 'provision' | 'read';
|
|
106
|
+
|
|
77
107
|
/** ★ Generic, kit-prefixed names: nothing here is any one estate's. */
|
|
78
108
|
export const PROVISION_DEFAULTS: ResolvedProvisionNames = Object.freeze({
|
|
79
109
|
comment:
|
|
@@ -85,9 +115,6 @@ export const PROVISION_DEFAULTS: ResolvedProvisionNames = Object.freeze({
|
|
|
85
115
|
role: 'HfProvisioner',
|
|
86
116
|
});
|
|
87
117
|
|
|
88
|
-
/** Which credential lane a user or a grant belongs to — the OpenBao role that mints for it. */
|
|
89
|
-
export type ProvisionLane = 'provision' | 'read';
|
|
90
|
-
|
|
91
118
|
/** A baseline, resolved: exactly what the declaration holds and the bootstrap makes. */
|
|
92
119
|
export interface ProvisionBaseline {
|
|
93
120
|
readonly role: { readonly roleid: string; readonly privs: readonly string[] };
|
|
@@ -113,9 +140,13 @@ export interface ProvisionBaseline {
|
|
|
113
140
|
*/
|
|
114
141
|
const ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
115
142
|
const USERID = /^[A-Za-z0-9][A-Za-z0-9._-]*@[A-Za-z][A-Za-z0-9._-]*$/;
|
|
116
|
-
const COMMENT = /^[A-Za-z0-9 ._
|
|
143
|
+
const COMMENT = /^[A-Za-z0-9 ._,:()@/+-]*$/;
|
|
117
144
|
|
|
118
|
-
const problems = (
|
|
145
|
+
const problems = (
|
|
146
|
+
names: ResolvedProvisionNames,
|
|
147
|
+
comments: ProvisionComments,
|
|
148
|
+
given: ProvisionNames,
|
|
149
|
+
): string[] => {
|
|
119
150
|
const found: string[] = [];
|
|
120
151
|
if (!ID.test(names.role)) found.push(`role \`${names.role}\` is not a PVE role id`);
|
|
121
152
|
if (!ID.test(names.mintGroup)) found.push(`mintGroup \`${names.mintGroup}\` is not a group id`);
|
|
@@ -129,20 +160,48 @@ const problems = (names: ResolvedProvisionNames): string[] => {
|
|
|
129
160
|
}
|
|
130
161
|
}
|
|
131
162
|
if (names.readUser === names.provisionUser) found.push('readUser and provisionUser are one user');
|
|
132
|
-
|
|
133
|
-
|
|
163
|
+
// ⛔ EVERY comment THE BASELINE WILL HOLD, not just the shared one: each is pasted into `sh` and
|
|
164
|
+
// into a Perl `q{}`. ⚠️ `readComment` only when there is a read lane — a `null` `readUser`
|
|
165
|
+
// drops the user, so nothing would ever be pasted.
|
|
166
|
+
// ★ NAMED BY WHERE THE VALUE CAME FROM, and said once. A bad shared `comment` is one problem
|
|
167
|
+
// called `comment`, not three called after overrides the caller never passed.
|
|
168
|
+
const source = (override: string | undefined, field: string) =>
|
|
169
|
+
override === undefined ? 'comment' : field;
|
|
170
|
+
const checked: (readonly [string, string])[] = [
|
|
171
|
+
[source(given.groupComment, 'groupComment'), comments.group],
|
|
172
|
+
[source(given.provisionComment, 'provisionComment'), comments.provision],
|
|
173
|
+
];
|
|
174
|
+
if (names.readUser !== null) {
|
|
175
|
+
checked.push([source(given.readComment, 'readComment'), comments.read]);
|
|
176
|
+
}
|
|
177
|
+
const said = new Set<string>();
|
|
178
|
+
for (const [field, comment] of checked) {
|
|
179
|
+
if (COMMENT.test(comment) || said.has(field)) continue;
|
|
180
|
+
said.add(field);
|
|
181
|
+
found.push(`${field} holds a character the bootstrap will not quote`);
|
|
182
|
+
}
|
|
134
183
|
return found;
|
|
135
184
|
};
|
|
136
185
|
|
|
137
186
|
/** Resolve `names` over the defaults and check them. Throws with every problem at once. */
|
|
138
187
|
export const provisionBaseline = (names: ProvisionNames = {}): ProvisionBaseline => {
|
|
188
|
+
// ⚠️ The per-object comments are taken out first: they are not core names, so they must not land
|
|
189
|
+
// in `resolved`, which `PROVISION_DEFAULTS` types and a caller may build a literal of.
|
|
190
|
+
const { groupComment, provisionComment, readComment, ...core } = names;
|
|
139
191
|
// ⚠️ An explicit `undefined` means "the default", not "blank": spread alone would keep it.
|
|
140
|
-
const given = Object.entries(
|
|
192
|
+
const given = Object.entries(core).filter(([, value]) => value !== undefined);
|
|
141
193
|
const resolved: ResolvedProvisionNames = {
|
|
142
194
|
...PROVISION_DEFAULTS,
|
|
143
195
|
...Object.fromEntries(given),
|
|
144
196
|
};
|
|
145
|
-
|
|
197
|
+
// ★ `?? resolved.comment`, so an override changes ONE object and the generic case stays one
|
|
198
|
+
// string. ⚠️ `??` and not `||`: an empty comment is a real value — a live object with none.
|
|
199
|
+
const comments: ProvisionComments = {
|
|
200
|
+
group: groupComment ?? resolved.comment,
|
|
201
|
+
provision: provisionComment ?? resolved.comment,
|
|
202
|
+
read: readComment ?? resolved.comment,
|
|
203
|
+
};
|
|
204
|
+
const found = problems(resolved, comments, names);
|
|
146
205
|
if (found.length > 0) throw new Error(`provision baseline: ${found.join('; ')}`);
|
|
147
206
|
const lanes: [ProvisionLane, string, string][] = [
|
|
148
207
|
['provision', resolved.provisionUser, resolved.role],
|
|
@@ -150,10 +209,10 @@ export const provisionBaseline = (names: ProvisionNames = {}): ProvisionBaseline
|
|
|
150
209
|
if (resolved.readUser !== null) lanes.push(['read', resolved.readUser, resolved.readRole]);
|
|
151
210
|
return {
|
|
152
211
|
grants: lanes.map(([lane, userid, roleid]) => ({ lane, roleid, userid })),
|
|
153
|
-
group: { comment:
|
|
212
|
+
group: { comment: comments.group, groupid: resolved.mintGroup },
|
|
154
213
|
role: { privs: PROVISION_PRIVILEGES, roleid: resolved.role },
|
|
155
214
|
users: lanes.map(([lane, userid]) => ({
|
|
156
|
-
comment:
|
|
215
|
+
comment: comments[lane],
|
|
157
216
|
groups: [resolved.mintGroup],
|
|
158
217
|
lane,
|
|
159
218
|
userid,
|
|
@@ -113,6 +113,57 @@ describe('run against a cluster', () => {
|
|
|
113
113
|
expect(run.state.acl.map((g) => g.ugid)).toEqual(['hf-provision@pve']);
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
+
test('an EXISTING cluster: only the new object is written, comments and all', async () => {
|
|
117
|
+
// \u2605 THE CASE ONE SHARED COMMENT COULD NOT DESCRIBE. The cluster already has the mint group
|
|
118
|
+
// (no comment at all) and the read user (its own wording), both of them declared elsewhere
|
|
119
|
+
// at those live values. Only the provision user is new. With per-object comments the script
|
|
120
|
+
// writes exactly that user and its grant -- it does not touch the two that already match,
|
|
121
|
+
// so nothing is left for another stack's next deploy to write back.
|
|
122
|
+
const existing: CliState = {
|
|
123
|
+
acl: [{ path: '/', propagate: 1, roleid: 'PVEAuditor', type: 'user', ugid: 'hf-read@pve' }],
|
|
124
|
+
// \u26a0\ufe0f '' IS "no comment live": the fake's view drops an empty one, as PVE does.
|
|
125
|
+
groups: { 'hf-mint': { comment: '' } },
|
|
126
|
+
roles: { ...freshCluster().roles, Provisioner: ['VM.Audit'] },
|
|
127
|
+
users: { 'hf-read@pve': { ...lane(['hf-mint']), comment: 'mint target: read (ops)' } },
|
|
128
|
+
};
|
|
129
|
+
const run = await runScript(
|
|
130
|
+
provisionBootstrap({
|
|
131
|
+
groupComment: '',
|
|
132
|
+
provisionComment: 'mint target: provision (ops)',
|
|
133
|
+
readComment: 'mint target: read (ops)',
|
|
134
|
+
role: 'Provisioner',
|
|
135
|
+
}),
|
|
136
|
+
existing,
|
|
137
|
+
);
|
|
138
|
+
expect(run.code).toBe(0);
|
|
139
|
+
expect(run.stdout).toContain('group hf-mint: ok');
|
|
140
|
+
expect(run.stdout).toContain('user hf-read@pve: ok');
|
|
141
|
+
// The only writes: the role widened to the baseline, the new user, and its grant.
|
|
142
|
+
expect(run.writes.map((w) => w.split(' ').slice(0, 3).join(' '))).toEqual([
|
|
143
|
+
'pveum role modify',
|
|
144
|
+
'pveum user add',
|
|
145
|
+
'pveum acl modify',
|
|
146
|
+
]);
|
|
147
|
+
expect(run.state.groups['hf-mint']).toEqual({ comment: '' });
|
|
148
|
+
expect(run.state.users['hf-read@pve']?.comment).toBe('mint target: read (ops)');
|
|
149
|
+
expect(run.state.users['hf-provision@pve']?.comment).toBe('mint target: provision (ops)');
|
|
150
|
+
expect(run.state.roles['Provisioner']).toEqual([...PROVISION_PRIVILEGES]);
|
|
151
|
+
|
|
152
|
+
// \u26d4 NEGATIVE CONTROL, so this test can fail: the SAME cluster with one shared comment
|
|
153
|
+
// rewrites both objects that already matched. That is the write per-object comments exist
|
|
154
|
+
// to avoid, and it is what another stack's next deploy would put back.
|
|
155
|
+
const shared = await runScript(
|
|
156
|
+
provisionBootstrap({ comment: 'mint target: provision (ops)', role: 'Provisioner' }),
|
|
157
|
+
existing,
|
|
158
|
+
);
|
|
159
|
+
expect(shared.code).toBe(0);
|
|
160
|
+
expect(shared.writes.map((w) => w.split(' ').slice(0, 3).join(' '))).toContain(
|
|
161
|
+
'pveum group modify',
|
|
162
|
+
);
|
|
163
|
+
expect(shared.state.groups['hf-mint']).toEqual({ comment: 'mint target: provision (ops)' });
|
|
164
|
+
expect(shared.state.users['hf-read@pve']?.comment).toBe('mint target: provision (ops)');
|
|
165
|
+
});
|
|
166
|
+
|
|
116
167
|
test("a site's own names flow through every step", async () => {
|
|
117
168
|
const names = {
|
|
118
169
|
mintGroup: 'mint',
|
package/src/proxmox/qemu.ts
CHANGED
|
@@ -54,6 +54,9 @@ export interface ProxmoxVm extends Resource<
|
|
|
54
54
|
|
|
55
55
|
export const ProxmoxVm = Resource<ProxmoxVm>('Proxmox.Vm');
|
|
56
56
|
|
|
57
|
+
/** ★ Exported so the constraint proof can run the REAL create form, not a retyped copy of it. */
|
|
58
|
+
export const createForm = (props: VmProps) => ({ ...shape(props), vmid: String(props.vmid) });
|
|
59
|
+
|
|
57
60
|
const shape = (props: VmProps) => ({
|
|
58
61
|
cores: String(props.cores ?? 1),
|
|
59
62
|
memory: String(props.memory ?? 512),
|
|
@@ -74,7 +77,12 @@ const handlers = pveHandlers<VmProps, VmAttributes>({
|
|
|
74
77
|
vmid: props.vmid,
|
|
75
78
|
}),
|
|
76
79
|
collection: (props) => `nodes/${props.node}/qemu`,
|
|
77
|
-
createForm
|
|
80
|
+
createForm,
|
|
81
|
+
/** The vendor rules both forms are checked against at plan time — resource-spec.ts. */
|
|
82
|
+
endpoint: {
|
|
83
|
+
create: 'pve:POST /nodes/{node}/qemu',
|
|
84
|
+
update: 'pve:PUT /nodes/{node}/qemu/{vmid}/config',
|
|
85
|
+
},
|
|
78
86
|
matches: (attributes, props) =>
|
|
79
87
|
attributes.name === (props.name ?? `vm${String(props.vmid)}`) &&
|
|
80
88
|
attributes.memory === (props.memory ?? 512) &&
|
|
@@ -224,6 +224,11 @@ const handlers = pveHandlers<ReplicationJobProps, ReplicationJobAttributes>({
|
|
|
224
224
|
* that is busy deleting itself, and matching that would be a noop over a vanishing object. It
|
|
225
225
|
* settles because `updateBody` actually clears the marker — see there.
|
|
226
226
|
*/
|
|
227
|
+
/** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
|
|
228
|
+
endpoint: {
|
|
229
|
+
create: 'pve:POST /cluster/replication',
|
|
230
|
+
update: 'pve:PUT /cluster/replication/{id}',
|
|
231
|
+
},
|
|
227
232
|
matches: (attributes, props) =>
|
|
228
233
|
attributes.remove_job === '' &&
|
|
229
234
|
attributes.schedule === (props.schedule ?? DEFAULT_SCHEDULE) &&
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A spec's two forms, checked against the vendor's own tables before either goes on the wire.
|
|
3
|
+
*
|
|
4
|
+
* ★ A FILE OF ITS OWN BECAUSE resource.ts REACHED THE 250-LINE CAP, and the seam is the same one
|
|
5
|
+
* resource-spec.ts cuts on: that file says what a PVE object DECLARES, resource.ts says how one
|
|
6
|
+
* is read and written, and this one says what makes a declaration legal. `constraint-guard.ts`
|
|
7
|
+
* is the layer below — it owns the lookup and the refusal; this owns which form to check when.
|
|
8
|
+
*/
|
|
9
|
+
import * as Effect from 'effect/Effect';
|
|
10
|
+
import { guardForm } from './constraint-guard.ts';
|
|
11
|
+
import type { PveSpec, WithApiTarget } from './resource-spec.ts';
|
|
12
|
+
|
|
13
|
+
export const specGuards = <Props extends WithApiTarget, Attributes>(
|
|
14
|
+
spec: PveSpec<Props, Attributes>,
|
|
15
|
+
) => {
|
|
16
|
+
/** ⚠️ A function for the two families whose endpoint is a prop — see `PveSpec['endpoint']`. */
|
|
17
|
+
const endpointsOf = (props: Props) =>
|
|
18
|
+
typeof spec.endpoint === 'function' ? spec.endpoint(props) : spec.endpoint;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The create form against its own endpoint's table.
|
|
22
|
+
*
|
|
23
|
+
* ⛔ `presence` MEANS "A CREATE IS REALLY ABOUT TO HAPPEN", NOT "THIS IS THE CREATE FORM", AND
|
|
24
|
+
* THE DIFFERENCE IS A WHOLE FAMILY. `Proxmox.NotificationTarget` cannot send gotify's `token`
|
|
25
|
+
* or smtp's `password` — they are write-only secrets and props are persisted to the state
|
|
26
|
+
* store unencrypted (notification-target.ts's third ⛔) — so PVE's `token: required` is
|
|
27
|
+
* permanently unsatisfiable here. The documented way to run one is to create it out of band
|
|
28
|
+
* with its secret and then DECLARE it, which is an adopt and then updates forever after.
|
|
29
|
+
* Requiring the create form's parameters on that path would refuse a deploy that has worked
|
|
30
|
+
* all along, which is the one failure worse than the 400 this feature removes.
|
|
31
|
+
* ⚠️ VALUE RULES STILL RUN ON EVERY PLAN, presence or not: a 129-character comment is wrong
|
|
32
|
+
* whether it is being created or edited, and that is the case this whole feature exists for.
|
|
33
|
+
*
|
|
34
|
+
* ⛔ THE FORM IS BUILT ONLY WHEN THERE IS A TABLE TO CHECK IT AGAINST. Calling `spec.createForm`
|
|
35
|
+
* unconditionally would run every family's form builder on every diff — work nobody asked
|
|
36
|
+
* for, and a new way for a builder that throws on an update-only path to break a plan it
|
|
37
|
+
* never touched.
|
|
38
|
+
*/
|
|
39
|
+
const guardCreate = (props: Props, presence: boolean): Effect.Effect<void> =>
|
|
40
|
+
Effect.suspend(() => {
|
|
41
|
+
const create = endpointsOf(props)?.create;
|
|
42
|
+
return create === undefined
|
|
43
|
+
? Effect.void
|
|
44
|
+
: guardForm(create, spec.createForm(props), presence);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* ⛔ NEVER WITH PRESENCE. An update form is deliberately PARTIAL — `formToSend` sends the fields
|
|
49
|
+
* that changed and nothing else — so requiring the vendor's required parameters here would
|
|
50
|
+
* refuse every ordinary edit. Value rules (length, range, enum, pattern) apply to both forms.
|
|
51
|
+
*/
|
|
52
|
+
const guardUpdate = (props: Props): Effect.Effect<void> =>
|
|
53
|
+
Effect.suspend(() => {
|
|
54
|
+
const update = endpointsOf(props)?.update;
|
|
55
|
+
if (update === undefined) return Effect.void;
|
|
56
|
+
const form = spec.updateForm?.(props);
|
|
57
|
+
return form === undefined ? Effect.void : guardForm(update, form, false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return { guardCreate, guardUpdate };
|
|
61
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHAT A PVE OBJECT DECLARES: one shape for every one of them, so the provider can cover Proxmox
|
|
3
|
+
* rather than a corner of it. The four operations that read this spec are in resource.ts.
|
|
4
|
+
*
|
|
5
|
+
* ⛔ THE ALTERNATIVE IS TWENTY COPIES OF THE SAME 130 LINES. Proxmox exposes LXC, QEMU, storage,
|
|
6
|
+
* pools, users, groups, roles, ACLs, API tokens, SDN zones/vnets/subnets, firewall rules and
|
|
7
|
+
* groups, HA resources, backup and replication jobs, metric servers and notification targets.
|
|
8
|
+
* Each is the same four operations over a different path and a different form body. Written by
|
|
9
|
+
* hand, resource number six is where someone quietly drops the read-back or the isResolved guard
|
|
10
|
+
* and nobody notices until a plan lies.
|
|
11
|
+
*
|
|
12
|
+
* ★ SO THE FOUR OPERATIONS LIVE HERE, ONCE, AND A RESOURCE DECLARES ONLY WHAT IS DIFFERENT:
|
|
13
|
+
* where it lives, how to recognise it, and which fields are mutable. A new PVE object should be
|
|
14
|
+
* thirty lines, not a hundred and thirty.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ EVERY PVE ANSWER IS WRAPPED IN `{"data": ...}` AND A FAILED CALL CAN STILL BE HTTP 200 with
|
|
17
|
+
* `{"data": null}`. That is why `reconcile` below READS BACK and refuses when the object is still
|
|
18
|
+
* absent, rather than trusting a status code — see the ⛔ in that function.
|
|
19
|
+
*/
|
|
20
|
+
import type * as HttpClient from 'effect/unstable/http/HttpClient';
|
|
21
|
+
import type { PveForm } from './client.ts';
|
|
22
|
+
import type { EndpointKey } from './constraints.ts';
|
|
23
|
+
import type { ApiTarget, PbsTarget, PveRole, PveTarget } from './credentials.ts';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* ★ WHY SEVERAL FAMILIES HERE DECLARE `defaultRemovalPolicy: 'retain'`, WRITTEN ONCE.
|
|
27
|
+
*
|
|
28
|
+
* Alchemy's own convention: a few resource types default to retain "because their contents are
|
|
29
|
+
* irreplaceable" — `GitHub.Repository` and `Cloudflare.Zone` do — and those opt into deletion
|
|
30
|
+
* with `destroy()`. `retain` means the engine SKIPS `provider.delete` entirely when a resource
|
|
31
|
+
* is orphaned or destroyed: the state row is dropped, the cluster object lives on.
|
|
32
|
+
*
|
|
33
|
+
* So the PVE families whose contents cannot be rebuilt from a line of TypeScript — CephOsd,
|
|
34
|
+
* CephPool, CephFs, CephDaemon, ZfsPool, Storage, NodeNetwork — carry that default. Their
|
|
35
|
+
* `delete` is FULLY IMPLEMENTED and runs the moment a caller opts in with
|
|
36
|
+
* `.pipe(RemovalPolicy.destroy())`. This is deliberately the Terraform `prevent_destroy` shape
|
|
37
|
+
* rather than a stubbed-out operation: a `delete` that silently does nothing lies to whoever is
|
|
38
|
+
* reading the plan, and the lie is discovered at the worst possible time.
|
|
39
|
+
*
|
|
40
|
+
* ⚠️ THE POLICY IS A DECORATION, NOT A PROP, so changing it produces NO DIFF — the resource plans
|
|
41
|
+
* as a noop and the deploy re-commits the row's policy in place. A policy change therefore takes
|
|
42
|
+
* effect from the very next deploy even though the plan shows nothing.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* ⛔ A RESOURCE IS PINNED TO ITS PRODUCT; ONLY THE FACTORY TAKES EITHER. The two hosts are the same
|
|
47
|
+
* two strings, so without a required discriminant TypeScript would accept a PBS host wherever a
|
|
48
|
+
* PVE one belongs — silently, with every call 401ing and `read` folding that into "absent". The
|
|
49
|
+
* whole argument is on `scheme` in credentials.ts.
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* ★ WHAT EVERY OPERATION IN THIS PACKAGE NEEDS FROM THE RUNTIME, NAMED ONCE.
|
|
53
|
+
*
|
|
54
|
+
* `HttpClient`, for both halves of every call: the credential is minted from OpenBao's HTTP API
|
|
55
|
+
* and the PVE call goes through the same client. That is what Alchemy's own providers do
|
|
56
|
+
* (src/Hetzner/Providers.ts builds on `FetchHttpClient.layer`, and there is no bare `fetch` in
|
|
57
|
+
* its Docker, Kubernetes or GitHub providers).
|
|
58
|
+
* ★ `ChildProcessSpawner` WAS HERE UNTIL 2026-09-14, while the mint shelled out to `bao`. The HTTP
|
|
59
|
+
* client replaced that (credentials.ts), so the requirement went with it.
|
|
60
|
+
*
|
|
61
|
+
* ⚠️ SPELLED OUT AT EACH OF THE FORTY-ODD RESOURCES this would be a union nobody keeps in step —
|
|
62
|
+
* one file left on the old shape is a type error at the stack, far from the cause. Named here,
|
|
63
|
+
* adding a third service later is one edit.
|
|
64
|
+
*/
|
|
65
|
+
export type PveRequirements = HttpClient.HttpClient;
|
|
66
|
+
|
|
67
|
+
export type WithTarget = { target: PveTarget };
|
|
68
|
+
export type WithPbsTarget = { target: PbsTarget };
|
|
69
|
+
export type WithApiTarget = { target: ApiTarget };
|
|
70
|
+
|
|
71
|
+
export type PveSpec<Props extends WithApiTarget, Attributes> = {
|
|
72
|
+
/** `pools/lab`, `nodes/node-b/lxc/101` — where ONE object is read, updated and deleted. */
|
|
73
|
+
readonly path: (props: Props) => string;
|
|
74
|
+
/** `pools`, `nodes/node-b/lxc` — where a NEW one is POSTed. */
|
|
75
|
+
readonly collection: (props: Props) => string;
|
|
76
|
+
/** Live JSON to attributes. Returning undefined means "this is not really there". */
|
|
77
|
+
readonly attributes: (live: Record<string, unknown>, props: Props) => Attributes | undefined;
|
|
78
|
+
/** The form PVE wants on create. ⚠️ PVE takes form encoding, not JSON. Arrays: client.ts. */
|
|
79
|
+
readonly createForm: (props: Props) => PveForm;
|
|
80
|
+
/**
|
|
81
|
+
* The form for an update, or undefined when the object has no mutable fields.
|
|
82
|
+
*
|
|
83
|
+
* ⚠️ SOME PVE OBJECTS CANNOT BE UPDATED AT ALL. Returning undefined makes a changed prop a
|
|
84
|
+
* REPLACE rather than a silent no-op, which is the honest answer for an immutable object.
|
|
85
|
+
*/
|
|
86
|
+
readonly updateForm?: (props: Props) => PveForm;
|
|
87
|
+
/** True when live already matches props. Decides noop vs update. */
|
|
88
|
+
readonly matches: (attributes: Attributes, props: Props) => boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Which lease reads this family. Defaults to `read`, the 3600s auditor-shaped one.
|
|
91
|
+
*
|
|
92
|
+
* ⛔ THREE FAMILIES SET THIS TO `provision`, AND THE FAILURE IT AVOIDS IS SILENT. PVE gates some
|
|
93
|
+
* SINGLE-OBJECT reads on the allocate privilege rather than the audit one — `/storage/{id}`,
|
|
94
|
+
* `/cluster/sdn/zones/{zone}`, `/cluster/sdn/vnets/{vnet}` — while their COLLECTION reads
|
|
95
|
+
* accept audit, so nothing looks wrong until a resource reads one object. `read` below folds
|
|
96
|
+
* every failure into `undefined`, right for a 404 and wrong for a 403, so the plan says create
|
|
97
|
+
* and PVE answers that the object already exists. Measured both ways on `local`, and written
|
|
98
|
+
* up with the alternative that was rejected, in docs/privileges.md.
|
|
99
|
+
*/
|
|
100
|
+
readonly readRole?: PveRole;
|
|
101
|
+
/**
|
|
102
|
+
* The vendor endpoints this family writes, as the generated tables key them —
|
|
103
|
+
* `'pbs:POST /config/verify'`, `'pve:PUT /cluster/sdn/zones/{zone}'`.
|
|
104
|
+
*
|
|
105
|
+
* ⛔ DECLARING IT IS WHAT MAKES THE VENDOR'S OWN LIMITS RUN AT PLAN TIME. Without it the family
|
|
106
|
+
* behaves exactly as it did on 2026-09-22, when `deploy:pbs` adopted ten objects and then
|
|
107
|
+
* failed its one create on a `maxLength` PBS publishes and our generated `comment?: string`
|
|
108
|
+
* does not carry. `codegen/constraints.ts` scans this package for these strings, so a key that
|
|
109
|
+
* names an endpoint the vendor does not have stops the GENERATOR rather than a deploy.
|
|
110
|
+
* ⚠️ The spelling is the vendor's own path TEMPLATE, braces and all — not `spec.path(props)`,
|
|
111
|
+
* which has the ids substituted in.
|
|
112
|
+
*
|
|
113
|
+
* ⚠️ A FUNCTION FOR THE TWO FAMILIES WHOSE ENDPOINT IS CHOSEN BY A PROP, AND FOR NO OTHER
|
|
114
|
+
* REASON. `Proxmox.NotificationTarget` POSTs to one of four `endpoints/{type}` paths and
|
|
115
|
+
* `Proxmox.CephDaemon` to one of `ceph/mds|mgr|mon`, each with its own parameter schema, so a
|
|
116
|
+
* single key would table the wrong rules for three declarations out of four.
|
|
117
|
+
* ⛔ EVERY KEY THE FUNCTION CAN RETURN STILL HAS TO EXIST AS A LITERAL IN THIS PACKAGE'S
|
|
118
|
+
* SOURCE. `codegen/constraints.ts` finds keys by scanning text, so a key assembled from a
|
|
119
|
+
* template literal is tabled by nothing and `constraintsFor` throws on the deploy that first
|
|
120
|
+
* reaches it. Write the keys out in a record and index it — see `ceph-endpoints.ts`.
|
|
121
|
+
*/
|
|
122
|
+
readonly endpoint?: EndpointPair | ((props: Props) => EndpointPair);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/** The two endpoints a family writes. Either may be absent — see `PveSpec['endpoint']`. */
|
|
126
|
+
export type EndpointPair = {
|
|
127
|
+
readonly create?: EndpointKey;
|
|
128
|
+
readonly update?: EndpointKey;
|
|
129
|
+
};
|