@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.
Files changed (417) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/cloudflare/client.d.ts +45 -0
  4. package/dist/cloudflare/client.d.ts.map +1 -0
  5. package/dist/cloudflare/index.d.ts +11 -0
  6. package/dist/cloudflare/index.d.ts.map +1 -0
  7. package/dist/cloudflare/index.js +129 -0
  8. package/dist/cloudflare/index.js.map +13 -0
  9. package/dist/cloudflare/lock-rules.d.ts +50 -0
  10. package/dist/cloudflare/lock-rules.d.ts.map +1 -0
  11. package/dist/cloudflare/providers.d.ts +19 -0
  12. package/dist/cloudflare/providers.d.ts.map +1 -0
  13. package/dist/cloudflare/r2-bucket-lock.d.ts +100 -0
  14. package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -0
  15. package/dist/forgejo/branch-protection-form.d.ts +19 -0
  16. package/dist/forgejo/branch-protection-form.d.ts.map +1 -0
  17. package/dist/forgejo/branch-protection.d.ts +47 -0
  18. package/dist/forgejo/branch-protection.d.ts.map +1 -0
  19. package/dist/forgejo/client.d.ts +37 -0
  20. package/dist/forgejo/client.d.ts.map +1 -0
  21. package/dist/forgejo/index.d.ts +18 -0
  22. package/dist/forgejo/index.d.ts.map +1 -0
  23. package/dist/forgejo/index.js +479 -0
  24. package/dist/forgejo/index.js.map +21 -0
  25. package/dist/forgejo/org-actions-secrets.d.ts +45 -0
  26. package/dist/forgejo/org-actions-secrets.d.ts.map +1 -0
  27. package/dist/forgejo/org-label.d.ts +46 -0
  28. package/dist/forgejo/org-label.d.ts.map +1 -0
  29. package/dist/forgejo/org-team.d.ts +42 -0
  30. package/dist/forgejo/org-team.d.ts.map +1 -0
  31. package/dist/forgejo/repo-webhook-form.d.ts +27 -0
  32. package/dist/forgejo/repo-webhook-form.d.ts.map +1 -0
  33. package/dist/forgejo/repo-webhook.d.ts +46 -0
  34. package/dist/forgejo/repo-webhook.d.ts.map +1 -0
  35. package/dist/forgejo/repository.d.ts +45 -0
  36. package/dist/forgejo/repository.d.ts.map +1 -0
  37. package/dist/forgejo/resource.d.ts +83 -0
  38. package/dist/forgejo/resource.d.ts.map +1 -0
  39. package/dist/forgejo/team-member.d.ts +39 -0
  40. package/dist/forgejo/team-member.d.ts.map +1 -0
  41. package/dist/forgejo/values.d.ts +24 -0
  42. package/dist/forgejo/values.d.ts.map +1 -0
  43. package/dist/index.d.ts +18 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +3 -0
  46. package/dist/index.js.map +9 -0
  47. package/dist/openbao/auth-role-form.d.ts +38 -0
  48. package/dist/openbao/auth-role-form.d.ts.map +1 -0
  49. package/dist/openbao/auth-role.d.ts +20 -0
  50. package/dist/openbao/auth-role.d.ts.map +1 -0
  51. package/dist/openbao/bao-address.d.ts +72 -0
  52. package/dist/openbao/bao-address.d.ts.map +1 -0
  53. package/dist/openbao/bao-http.d.ts +71 -0
  54. package/dist/openbao/bao-http.d.ts.map +1 -0
  55. package/dist/openbao/bao-status.d.ts +74 -0
  56. package/dist/openbao/bao-status.d.ts.map +1 -0
  57. package/dist/openbao/cloudflare-group-scope.d.ts +73 -0
  58. package/dist/openbao/cloudflare-group-scope.d.ts.map +1 -0
  59. package/dist/openbao/cloudflare-parity-catalog.d.ts +28 -0
  60. package/dist/openbao/cloudflare-parity-catalog.d.ts.map +1 -0
  61. package/dist/openbao/cloudflare-parity-snapshot.d.ts +31 -0
  62. package/dist/openbao/cloudflare-parity-snapshot.d.ts.map +1 -0
  63. package/dist/openbao/cloudflare-parity.d.ts +14 -0
  64. package/dist/openbao/cloudflare-parity.d.ts.map +1 -0
  65. package/dist/openbao/cloudflare-permission-groups-solve.d.ts +85 -0
  66. package/dist/openbao/cloudflare-permission-groups-solve.d.ts.map +1 -0
  67. package/dist/openbao/cloudflare-permission-groups.d.ts +87 -0
  68. package/dist/openbao/cloudflare-permission-groups.d.ts.map +1 -0
  69. package/dist/openbao/cloudflare-policy.d.ts +65 -0
  70. package/dist/openbao/cloudflare-policy.d.ts.map +1 -0
  71. package/dist/openbao/cloudflare-role-form.d.ts +110 -0
  72. package/dist/openbao/cloudflare-role-form.d.ts.map +1 -0
  73. package/dist/openbao/cloudflare-role-wire.d.ts +27 -0
  74. package/dist/openbao/cloudflare-role-wire.d.ts.map +1 -0
  75. package/dist/openbao/cloudflare-role.d.ts +35 -0
  76. package/dist/openbao/cloudflare-role.d.ts.map +1 -0
  77. package/dist/openbao/cloudflare-roles-config.d.ts +67 -0
  78. package/dist/openbao/cloudflare-roles-config.d.ts.map +1 -0
  79. package/dist/openbao/cloudflare-roles-expand.d.ts +76 -0
  80. package/dist/openbao/cloudflare-roles-expand.d.ts.map +1 -0
  81. package/dist/openbao/digest.d.ts +24 -0
  82. package/dist/openbao/digest.d.ts.map +1 -0
  83. package/dist/openbao/fake-bao.d.ts +40 -0
  84. package/dist/openbao/fake-bao.d.ts.map +1 -0
  85. package/dist/openbao/forgejo-bootstrap-parse.d.ts +46 -0
  86. package/dist/openbao/forgejo-bootstrap-parse.d.ts.map +1 -0
  87. package/dist/openbao/forgejo-bootstrap.d.ts +29 -0
  88. package/dist/openbao/forgejo-bootstrap.d.ts.map +1 -0
  89. package/dist/openbao/index.d.ts +18 -0
  90. package/dist/openbao/index.d.ts.map +1 -0
  91. package/dist/openbao/index.js +1158 -0
  92. package/dist/openbao/index.js.map +33 -0
  93. package/dist/openbao/mount-form.d.ts +60 -0
  94. package/dist/openbao/mount-form.d.ts.map +1 -0
  95. package/dist/openbao/mount-wire.d.ts +24 -0
  96. package/dist/openbao/mount-wire.d.ts.map +1 -0
  97. package/dist/openbao/mount.d.ts +20 -0
  98. package/dist/openbao/mount.d.ts.map +1 -0
  99. package/dist/openbao/pki-role-form.d.ts +118 -0
  100. package/dist/openbao/pki-role-form.d.ts.map +1 -0
  101. package/dist/openbao/pki-role.d.ts +50 -0
  102. package/dist/openbao/pki-role.d.ts.map +1 -0
  103. package/dist/openbao/policy-assembly.d.ts +13 -0
  104. package/dist/openbao/policy-assembly.d.ts.map +1 -0
  105. package/dist/openbao/policy-wire.d.ts +41 -0
  106. package/dist/openbao/policy-wire.d.ts.map +1 -0
  107. package/dist/openbao/policy.d.ts +83 -0
  108. package/dist/openbao/policy.d.ts.map +1 -0
  109. package/dist/openbao/proxmox-role-form.d.ts +92 -0
  110. package/dist/openbao/proxmox-role-form.d.ts.map +1 -0
  111. package/dist/openbao/proxmox-role.d.ts +47 -0
  112. package/dist/openbao/proxmox-role.d.ts.map +1 -0
  113. package/dist/openbao/ssh-role-form.d.ts +99 -0
  114. package/dist/openbao/ssh-role-form.d.ts.map +1 -0
  115. package/dist/openbao/ssh-role.d.ts +43 -0
  116. package/dist/openbao/ssh-role.d.ts.map +1 -0
  117. package/dist/proxmox/acl.d.ts +72 -0
  118. package/dist/proxmox/acl.d.ts.map +1 -0
  119. package/dist/proxmox/api-token-form.d.ts +59 -0
  120. package/dist/proxmox/api-token-form.d.ts.map +1 -0
  121. package/dist/proxmox/api-token.d.ts +159 -0
  122. package/dist/proxmox/api-token.d.ts.map +1 -0
  123. package/dist/proxmox/backup-job.d.ts +112 -0
  124. package/dist/proxmox/backup-job.d.ts.map +1 -0
  125. package/dist/proxmox/ceph-daemon-form.d.ts +70 -0
  126. package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -0
  127. package/dist/proxmox/ceph-daemon.d.ts +162 -0
  128. package/dist/proxmox/ceph-daemon.d.ts.map +1 -0
  129. package/dist/proxmox/ceph-flag.d.ts +131 -0
  130. package/dist/proxmox/ceph-flag.d.ts.map +1 -0
  131. package/dist/proxmox/ceph-fs-wire.d.ts +106 -0
  132. package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -0
  133. package/dist/proxmox/ceph-fs.d.ts +124 -0
  134. package/dist/proxmox/ceph-fs.d.ts.map +1 -0
  135. package/dist/proxmox/ceph-osd-tree.d.ts +154 -0
  136. package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -0
  137. package/dist/proxmox/ceph-osd-write.d.ts +36 -0
  138. package/dist/proxmox/ceph-osd-write.d.ts.map +1 -0
  139. package/dist/proxmox/ceph-osd.d.ts +102 -0
  140. package/dist/proxmox/ceph-osd.d.ts.map +1 -0
  141. package/dist/proxmox/ceph-pool-form.d.ts +217 -0
  142. package/dist/proxmox/ceph-pool-form.d.ts.map +1 -0
  143. package/dist/proxmox/ceph-pool-settle.d.ts +39 -0
  144. package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -0
  145. package/dist/proxmox/ceph-pool.d.ts +48 -0
  146. package/dist/proxmox/ceph-pool.d.ts.map +1 -0
  147. package/dist/proxmox/client.d.ts +64 -0
  148. package/dist/proxmox/client.d.ts.map +1 -0
  149. package/dist/proxmox/credentials.d.ts +153 -0
  150. package/dist/proxmox/credentials.d.ts.map +1 -0
  151. package/dist/proxmox/firewall-alias-form.d.ts +98 -0
  152. package/dist/proxmox/firewall-alias-form.d.ts.map +1 -0
  153. package/dist/proxmox/firewall-alias.d.ts +141 -0
  154. package/dist/proxmox/firewall-alias.d.ts.map +1 -0
  155. package/dist/proxmox/generated/pbs.d.ts +388 -0
  156. package/dist/proxmox/generated/pbs.d.ts.map +1 -0
  157. package/dist/proxmox/generated/pve.d.ts +4713 -0
  158. package/dist/proxmox/generated/pve.d.ts.map +1 -0
  159. package/dist/proxmox/group.d.ts +104 -0
  160. package/dist/proxmox/group.d.ts.map +1 -0
  161. package/dist/proxmox/ha-resource.d.ts +104 -0
  162. package/dist/proxmox/ha-resource.d.ts.map +1 -0
  163. package/dist/proxmox/ha-rule-form.d.ts +103 -0
  164. package/dist/proxmox/ha-rule-form.d.ts.map +1 -0
  165. package/dist/proxmox/ha-rule.d.ts +156 -0
  166. package/dist/proxmox/ha-rule.d.ts.map +1 -0
  167. package/dist/proxmox/index.d.ts +43 -0
  168. package/dist/proxmox/index.d.ts.map +1 -0
  169. package/dist/proxmox/index.js +2322 -0
  170. package/dist/proxmox/index.js.map +70 -0
  171. package/dist/proxmox/lease-cache.d.ts +98 -0
  172. package/dist/proxmox/lease-cache.d.ts.map +1 -0
  173. package/dist/proxmox/lxc.d.ts +59 -0
  174. package/dist/proxmox/lxc.d.ts.map +1 -0
  175. package/dist/proxmox/members.d.ts +56 -0
  176. package/dist/proxmox/members.d.ts.map +1 -0
  177. package/dist/proxmox/metric-server-form.d.ts +53 -0
  178. package/dist/proxmox/metric-server-form.d.ts.map +1 -0
  179. package/dist/proxmox/metric-server-otel.d.ts +49 -0
  180. package/dist/proxmox/metric-server-otel.d.ts.map +1 -0
  181. package/dist/proxmox/metric-server.d.ts +123 -0
  182. package/dist/proxmox/metric-server.d.ts.map +1 -0
  183. package/dist/proxmox/network-apply-read.d.ts +93 -0
  184. package/dist/proxmox/network-apply-read.d.ts.map +1 -0
  185. package/dist/proxmox/network-apply.d.ts +102 -0
  186. package/dist/proxmox/network-apply.d.ts.map +1 -0
  187. package/dist/proxmox/node-network-form.d.ts +128 -0
  188. package/dist/proxmox/node-network-form.d.ts.map +1 -0
  189. package/dist/proxmox/node-network.d.ts +173 -0
  190. package/dist/proxmox/node-network.d.ts.map +1 -0
  191. package/dist/proxmox/notification-target-form.d.ts +44 -0
  192. package/dist/proxmox/notification-target-form.d.ts.map +1 -0
  193. package/dist/proxmox/notification-target.d.ts +146 -0
  194. package/dist/proxmox/notification-target.d.ts.map +1 -0
  195. package/dist/proxmox/pbs-datastore-form.d.ts +147 -0
  196. package/dist/proxmox/pbs-datastore-form.d.ts.map +1 -0
  197. package/dist/proxmox/pbs-datastore-guard.d.ts +55 -0
  198. package/dist/proxmox/pbs-datastore-guard.d.ts.map +1 -0
  199. package/dist/proxmox/pbs-datastore.d.ts +140 -0
  200. package/dist/proxmox/pbs-datastore.d.ts.map +1 -0
  201. package/dist/proxmox/pbs-prune-job-form.d.ts +97 -0
  202. package/dist/proxmox/pbs-prune-job-form.d.ts.map +1 -0
  203. package/dist/proxmox/pbs-prune-job.d.ts +168 -0
  204. package/dist/proxmox/pbs-prune-job.d.ts.map +1 -0
  205. package/dist/proxmox/pbs-sync-job-form.d.ts +83 -0
  206. package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -0
  207. package/dist/proxmox/pbs-sync-job.d.ts +246 -0
  208. package/dist/proxmox/pbs-sync-job.d.ts.map +1 -0
  209. package/dist/proxmox/pbs-verify-job-form.d.ts +114 -0
  210. package/dist/proxmox/pbs-verify-job-form.d.ts.map +1 -0
  211. package/dist/proxmox/pbs-verify-job.d.ts +145 -0
  212. package/dist/proxmox/pbs-verify-job.d.ts.map +1 -0
  213. package/dist/proxmox/pool.d.ts +42 -0
  214. package/dist/proxmox/pool.d.ts.map +1 -0
  215. package/dist/proxmox/qemu.d.ts +46 -0
  216. package/dist/proxmox/qemu.d.ts.map +1 -0
  217. package/dist/proxmox/replication-job-form.d.ts +71 -0
  218. package/dist/proxmox/replication-job-form.d.ts.map +1 -0
  219. package/dist/proxmox/replication-job.d.ts +162 -0
  220. package/dist/proxmox/replication-job.d.ts.map +1 -0
  221. package/dist/proxmox/resource.d.ts +157 -0
  222. package/dist/proxmox/resource.d.ts.map +1 -0
  223. package/dist/proxmox/role.d.ts +97 -0
  224. package/dist/proxmox/role.d.ts.map +1 -0
  225. package/dist/proxmox/sdn-apply-read.d.ts +80 -0
  226. package/dist/proxmox/sdn-apply-read.d.ts.map +1 -0
  227. package/dist/proxmox/sdn-apply.d.ts +63 -0
  228. package/dist/proxmox/sdn-apply.d.ts.map +1 -0
  229. package/dist/proxmox/sdn-subnet-form.d.ts +111 -0
  230. package/dist/proxmox/sdn-subnet-form.d.ts.map +1 -0
  231. package/dist/proxmox/sdn-subnet.d.ts +161 -0
  232. package/dist/proxmox/sdn-subnet.d.ts.map +1 -0
  233. package/dist/proxmox/sdn-vnet.d.ts +113 -0
  234. package/dist/proxmox/sdn-vnet.d.ts.map +1 -0
  235. package/dist/proxmox/sdn-zone.d.ts +126 -0
  236. package/dist/proxmox/sdn-zone.d.ts.map +1 -0
  237. package/dist/proxmox/storage.d.ts +120 -0
  238. package/dist/proxmox/storage.d.ts.map +1 -0
  239. package/dist/proxmox/user.d.ts +107 -0
  240. package/dist/proxmox/user.d.ts.map +1 -0
  241. package/dist/proxmox/values.d.ts +134 -0
  242. package/dist/proxmox/values.d.ts.map +1 -0
  243. package/dist/proxmox/zfs-pool-write.d.ts +76 -0
  244. package/dist/proxmox/zfs-pool-write.d.ts.map +1 -0
  245. package/dist/proxmox/zfs-pool.d.ts +146 -0
  246. package/dist/proxmox/zfs-pool.d.ts.map +1 -0
  247. package/dist/talos/credentials.d.ts +30 -0
  248. package/dist/talos/credentials.d.ts.map +1 -0
  249. package/dist/talos/index.d.ts +15 -0
  250. package/dist/talos/index.d.ts.map +1 -0
  251. package/dist/talos/index.js +392 -0
  252. package/dist/talos/index.js.map +16 -0
  253. package/dist/talos/kubeconfig.d.ts +53 -0
  254. package/dist/talos/kubeconfig.d.ts.map +1 -0
  255. package/dist/talos/resource.d.ts +32 -0
  256. package/dist/talos/resource.d.ts.map +1 -0
  257. package/dist/talos/talos-bootstrap.d.ts +27 -0
  258. package/dist/talos/talos-bootstrap.d.ts.map +1 -0
  259. package/dist/talos/talos-cluster-health.d.ts +36 -0
  260. package/dist/talos/talos-cluster-health.d.ts.map +1 -0
  261. package/dist/talos/talos-machine-config.d.ts +41 -0
  262. package/dist/talos/talos-machine-config.d.ts.map +1 -0
  263. package/dist/talos/talosctl.d.ts +29 -0
  264. package/dist/talos/talosctl.d.ts.map +1 -0
  265. package/dist/talos/values.d.ts +20 -0
  266. package/dist/talos/values.d.ts.map +1 -0
  267. package/package.json +57 -0
  268. package/src/cloudflare/client.ts +76 -0
  269. package/src/cloudflare/index.ts +10 -0
  270. package/src/cloudflare/lock-rules.ts +60 -0
  271. package/src/cloudflare/providers.ts +23 -0
  272. package/src/cloudflare/r2-bucket-lock.ts +220 -0
  273. package/src/forgejo/branch-protection-form.ts +29 -0
  274. package/src/forgejo/branch-protection.ts +101 -0
  275. package/src/forgejo/client.ts +136 -0
  276. package/src/forgejo/index.ts +17 -0
  277. package/src/forgejo/org-actions-secrets.ts +99 -0
  278. package/src/forgejo/org-label.ts +100 -0
  279. package/src/forgejo/org-team.ts +105 -0
  280. package/src/forgejo/repo-webhook-form.ts +47 -0
  281. package/src/forgejo/repo-webhook.ts +118 -0
  282. package/src/forgejo/repository.ts +126 -0
  283. package/src/forgejo/resource.ts +171 -0
  284. package/src/forgejo/team-member.ts +97 -0
  285. package/src/forgejo/values.test.ts +48 -0
  286. package/src/forgejo/values.ts +61 -0
  287. package/src/index.ts +18 -0
  288. package/src/openbao/auth-role-form.ts +112 -0
  289. package/src/openbao/auth-role.ts +101 -0
  290. package/src/openbao/bao-address.test.ts +89 -0
  291. package/src/openbao/bao-address.ts +97 -0
  292. package/src/openbao/bao-http-gate.test.ts +88 -0
  293. package/src/openbao/bao-http-unix.test.ts +70 -0
  294. package/src/openbao/bao-http.test.ts +161 -0
  295. package/src/openbao/bao-http.ts +185 -0
  296. package/src/openbao/bao-status.test.ts +114 -0
  297. package/src/openbao/bao-status.ts +137 -0
  298. package/src/openbao/cloudflare-group-scope.test.ts +103 -0
  299. package/src/openbao/cloudflare-group-scope.ts +83 -0
  300. package/src/openbao/cloudflare-parity-catalog.ts +104 -0
  301. package/src/openbao/cloudflare-parity-snapshot.ts +84 -0
  302. package/src/openbao/cloudflare-parity.ts +152 -0
  303. package/src/openbao/cloudflare-permission-groups-solve.test.ts +171 -0
  304. package/src/openbao/cloudflare-permission-groups-solve.ts +197 -0
  305. package/src/openbao/cloudflare-permission-groups.test.ts +369 -0
  306. package/src/openbao/cloudflare-permission-groups.ts +299 -0
  307. package/src/openbao/cloudflare-policy.ts +180 -0
  308. package/src/openbao/cloudflare-role-form.test.ts +177 -0
  309. package/src/openbao/cloudflare-role-form.ts +183 -0
  310. package/src/openbao/cloudflare-role-wire.test.ts +132 -0
  311. package/src/openbao/cloudflare-role-wire.ts +41 -0
  312. package/src/openbao/cloudflare-role.ts +189 -0
  313. package/src/openbao/cloudflare-roles-config.ts +230 -0
  314. package/src/openbao/cloudflare-roles-expand-bucket.test.ts +134 -0
  315. package/src/openbao/cloudflare-roles-expand.ts +231 -0
  316. package/src/openbao/digest.ts +26 -0
  317. package/src/openbao/fake-bao.ts +84 -0
  318. package/src/openbao/forgejo-bootstrap-parse.test.ts +76 -0
  319. package/src/openbao/forgejo-bootstrap-parse.ts +90 -0
  320. package/src/openbao/forgejo-bootstrap.ts +181 -0
  321. package/src/openbao/index.ts +17 -0
  322. package/src/openbao/mount-form.ts +147 -0
  323. package/src/openbao/mount-wire.test.ts +108 -0
  324. package/src/openbao/mount-wire.ts +79 -0
  325. package/src/openbao/mount.ts +132 -0
  326. package/src/openbao/pki-role-form.ts +248 -0
  327. package/src/openbao/pki-role.ts +202 -0
  328. package/src/openbao/policy-assembly.test.ts +28 -0
  329. package/src/openbao/policy-assembly.ts +13 -0
  330. package/src/openbao/policy-wire.test.ts +90 -0
  331. package/src/openbao/policy-wire.ts +53 -0
  332. package/src/openbao/policy.ts +212 -0
  333. package/src/openbao/proxmox-role-form.ts +174 -0
  334. package/src/openbao/proxmox-role.ts +214 -0
  335. package/src/openbao/ssh-role-form.ts +248 -0
  336. package/src/openbao/ssh-role.ts +240 -0
  337. package/src/proxmox/acl.ts +267 -0
  338. package/src/proxmox/api-token-form.ts +122 -0
  339. package/src/proxmox/api-token.ts +222 -0
  340. package/src/proxmox/backup-job.ts +213 -0
  341. package/src/proxmox/ceph-daemon-form.ts +84 -0
  342. package/src/proxmox/ceph-daemon.ts +243 -0
  343. package/src/proxmox/ceph-flag.ts +249 -0
  344. package/src/proxmox/ceph-fs-wire.ts +246 -0
  345. package/src/proxmox/ceph-fs.ts +249 -0
  346. package/src/proxmox/ceph-osd-tree.ts +193 -0
  347. package/src/proxmox/ceph-osd-write.ts +76 -0
  348. package/src/proxmox/ceph-osd.ts +244 -0
  349. package/src/proxmox/ceph-pool-form.ts +249 -0
  350. package/src/proxmox/ceph-pool-settle.ts +70 -0
  351. package/src/proxmox/ceph-pool.ts +212 -0
  352. package/src/proxmox/client.test.ts +185 -0
  353. package/src/proxmox/client.ts +240 -0
  354. package/src/proxmox/credentials.test.ts +144 -0
  355. package/src/proxmox/credentials.ts +254 -0
  356. package/src/proxmox/firewall-alias-form.ts +112 -0
  357. package/src/proxmox/firewall-alias.ts +208 -0
  358. package/src/proxmox/generated/pbs.ts +461 -0
  359. package/src/proxmox/generated/pve.ts +7344 -0
  360. package/src/proxmox/group.ts +199 -0
  361. package/src/proxmox/ha-resource.ts +169 -0
  362. package/src/proxmox/ha-rule-form.ts +185 -0
  363. package/src/proxmox/ha-rule.ts +240 -0
  364. package/src/proxmox/index.ts +42 -0
  365. package/src/proxmox/lease-cache.test.ts +163 -0
  366. package/src/proxmox/lease-cache.ts +131 -0
  367. package/src/proxmox/lxc.ts +117 -0
  368. package/src/proxmox/members.test.ts +54 -0
  369. package/src/proxmox/members.ts +174 -0
  370. package/src/proxmox/metric-server-form.ts +128 -0
  371. package/src/proxmox/metric-server-otel.ts +99 -0
  372. package/src/proxmox/metric-server.ts +214 -0
  373. package/src/proxmox/network-apply-read.ts +228 -0
  374. package/src/proxmox/network-apply.ts +244 -0
  375. package/src/proxmox/node-network-form.ts +213 -0
  376. package/src/proxmox/node-network.ts +243 -0
  377. package/src/proxmox/notification-target-form.ts +104 -0
  378. package/src/proxmox/notification-target.ts +222 -0
  379. package/src/proxmox/pbs-datastore-form.ts +248 -0
  380. package/src/proxmox/pbs-datastore-guard.ts +105 -0
  381. package/src/proxmox/pbs-datastore.ts +271 -0
  382. package/src/proxmox/pbs-prune-job-form.ts +208 -0
  383. package/src/proxmox/pbs-prune-job.ts +227 -0
  384. package/src/proxmox/pbs-sync-job-form.ts +234 -0
  385. package/src/proxmox/pbs-sync-job.ts +258 -0
  386. package/src/proxmox/pbs-verify-job-form.ts +131 -0
  387. package/src/proxmox/pbs-verify-job.ts +227 -0
  388. package/src/proxmox/pool.test.ts +42 -0
  389. package/src/proxmox/pool.ts +80 -0
  390. package/src/proxmox/qemu.ts +89 -0
  391. package/src/proxmox/replication-job-form.ts +89 -0
  392. package/src/proxmox/replication-job.ts +248 -0
  393. package/src/proxmox/resource.ts +257 -0
  394. package/src/proxmox/role.ts +161 -0
  395. package/src/proxmox/sdn-apply-read.test.ts +152 -0
  396. package/src/proxmox/sdn-apply-read.ts +189 -0
  397. package/src/proxmox/sdn-apply.ts +154 -0
  398. package/src/proxmox/sdn-subnet-form.ts +156 -0
  399. package/src/proxmox/sdn-subnet.ts +238 -0
  400. package/src/proxmox/sdn-vnet.ts +228 -0
  401. package/src/proxmox/sdn-zone.ts +246 -0
  402. package/src/proxmox/storage.ts +245 -0
  403. package/src/proxmox/user.ts +214 -0
  404. package/src/proxmox/values.test.ts +193 -0
  405. package/src/proxmox/values.ts +203 -0
  406. package/src/proxmox/zfs-pool-write.ts +130 -0
  407. package/src/proxmox/zfs-pool.ts +253 -0
  408. package/src/talos/credentials.ts +136 -0
  409. package/src/talos/index.ts +14 -0
  410. package/src/talos/kubeconfig.ts +170 -0
  411. package/src/talos/resource.ts +31 -0
  412. package/src/talos/talos-bootstrap.ts +109 -0
  413. package/src/talos/talos-cluster-health.ts +119 -0
  414. package/src/talos/talos-machine-config.ts +146 -0
  415. package/src/talos/talosctl.ts +94 -0
  416. package/src/talos/values.test.ts +80 -0
  417. package/src/talos/values.ts +70 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Where a Ceph daemon lives on the API, and what a declaration of one looks like as a PVE form.
3
+ *
4
+ * ★ SPLIT OUT OF ceph-daemon.ts TO KEEP BOTH FILES UNDER THE 250-LINE CAP, and the seam is a real
5
+ * one rather than a convenient line number — the same seam metric-server-form.ts cuts on.
6
+ * This file answers "how does a declaration address ONE daemon" — which URL, which body, and
7
+ * which row of the collection's answer is it. ceph-daemon.ts answers "what does the cluster
8
+ * say about that daemon, and when has it changed". Nothing here calls the API and nothing
9
+ * here decides a diff; `findRow` picks a row out of an answer its caller already fetched.
10
+ *
11
+ * ⛔ THE TWO PATHS ARE DIFFERENT AND THAT IS THE WHOLE REASON THIS FILE HAS TWO OF THEM. MEASURED
12
+ * on n2, 2026-09-13: there is no GET on the id path — `pvesh get /nodes/n2/ceph/mon/n2` answers
13
+ * "No 'get' handler defined" — while POST and DELETE are registered ONLY there. So the read uses
14
+ * `collectionPath` and the two writes use `daemonPath`, and swapping either one is a silent
15
+ * 501: a create that never lands, or a destroy that reports failure while the daemon runs on.
16
+ *
17
+ * ⚠️ THE `import type` BACK TO ceph-daemon.ts IS A CYCLE ON PAPER ONLY — type-only, so it is
18
+ * erased before anything runs. `CephDaemonProps` stays the resource's public shape, in the file
19
+ * that declares the resource.
20
+ *
21
+ * ⛔ POST AND DELETE RETURN A UPID, NOT AN OBJECT — both are `protected` task endpoints whose
22
+ * schema `returns` is a bare string. REASONED, NOT MEASURED: this cluster is read-only to me, so
23
+ * no create was ever run. The consequence to expect is that `reconcile` reads back immediately
24
+ * after the POST, and if the worker has not yet written ceph.conf the read-back still says
25
+ * absent and reconcile dies with "the write returned no error but the object is still absent".
26
+ * That refusal is honest — nothing is recorded for an object that is not there — and a second
27
+ * deploy converges once the task has finished, but it is a confusing FIRST-RUN failure. Watch
28
+ * the task in the PVE UI before concluding the create failed.
29
+ *
30
+ */
31
+ import type { CephDaemonProps } from './ceph-daemon.ts';
32
+ /**
33
+ * PVE defaults the id to the nodename for all three kinds, and that default is resolved HERE
34
+ * rather than left to PVE, because the id is a PATH SEGMENT: create, delete and the row lookup in
35
+ * ceph-daemon.ts all need the same string, and a default resolved on the far side would leave
36
+ * three call sites guessing. Live on this cluster every daemon's name equals its node.
37
+ */
38
+ export declare const daemonId: (props: CephDaemonProps) => string;
39
+ /**
40
+ * The read path. ⚠️ `{node}` HERE IS ONLY THE NODE BEING ASKED, not a filter. MEASURED:
41
+ * `GET /nodes/n2/ceph/mon` returns n2, n3 AND n4, and `GET /nodes/n3/ceph/mon` returns the same
42
+ * three IN A DIFFERENT ORDER — [n4,n2,n3] from n2 against [n3,n2,n4] from n3. A caller that took
43
+ * row zero, or assumed the list was this node's daemons, would be wrong on both counts.
44
+ */
45
+ export declare const collectionPath: (props: CephDaemonProps) => string;
46
+ /** The write path: POST creates here, DELETE destroys here. Never read from — see the ⛔ above. */
47
+ export declare const daemonPath: (props: CephDaemonProps) => string;
48
+ /**
49
+ * The create body, which is EMPTY for a mgr and nearly empty for the other two.
50
+ *
51
+ * ⚠️ THE ID IS NOT SENT, because it is already the last segment of the path being POSTed to — the
52
+ * same reasoning as metric-server.ts, where a second copy of the key can only disagree with the
53
+ * first. PVE's schema does accept `monid`/`id`/`name` as body parameters; the path wins, so
54
+ * sending one would be a second source of truth for the object's identity and nothing else.
55
+ *
56
+ * ⚠️ AND THE BRANCHES CANNOT BE ONE SHARED BODY. `hotstandby` is an mds parameter and
57
+ * `mon-address` a mon one; each POST schema lists only its own, so the wrong field is a 400
58
+ * rather than an ignored hint. Both are create-only — the ⛔s on those props say why neither is
59
+ * ever compared afterwards.
60
+ */
61
+ export declare const createForm: (props: CephDaemonProps) => Record<string, string>;
62
+ /**
63
+ * ⚠️ THE COLLECTION ANSWERS AN ARRAY while the factory types `attributes`' first parameter as the
64
+ * `Record<string, unknown>` every other PVE read is shaped like — the same mismatch acl.ts
65
+ * carries, handled the same way: narrow the rows, trust none of them, and match on `name`.
66
+ * ⚠️ MATCHED ON `name` ALONE, NEVER ON POSITION — the list comes back in a different order
67
+ * depending on which node was asked. See the ⚠️ on `collectionPath` above.
68
+ */
69
+ export declare const findRow: (live: unknown, props: CephDaemonProps) => Record<string, unknown> | undefined;
70
+ //# sourceMappingURL=ceph-daemon-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-daemon-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,UAAW,eAAe,WAA6B,CAAC;AAE7E;;;;;GAKG;AACH,eAAO,MAAM,cAAc,UAAW,eAAe,WAA6C,CAAC;AAEnG,kGAAkG;AAClG,eAAO,MAAM,UAAU,UAAW,eAAe,WAAkD,CAAC;AAEpG;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,UAAW,eAAe,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAMxE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,SAAU,OAAO,SAAS,eAAe,wCAGV,CAAC"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * `Proxmox.CephDaemon` — a Ceph monitor, manager or metadata server on one node.
3
+ *
4
+ * ★ ONE RESOURCE FOR THREE KINDS, AND THE SCHEMAS WERE CHECKED BEFORE THAT WAS DECIDED. Parsed
5
+ * from `/usr/share/pve-docs/api-viewer/apidoc.js` on n2, 2026-09-13: mon, mgr and mds each
6
+ * expose GET on the collection and POST + DELETE on the id below it, each returns
7
+ * name/host/state/addr/ceph_version*, and the only divergence is the create parameter
8
+ * (`mon-address` / none / `hotstandby`) and the read-only extras (mon: quorum, rank; mds: rank,
9
+ * fs_name, standby_replay). Three near-identical files would have carried the traps below three
10
+ * times over and let them drift — the argument resource.ts already makes for the factory itself.
11
+ *
12
+ * ⛔ THE ONLY GET IS THE COLLECTION'S, AND IT ANSWERS FOR THE WHOLE CLUSTER. MEASURED:
13
+ * `GET /nodes/n2/ceph/mon` returns n2, n3 AND n4, and `GET /nodes/n3/ceph/mon` returns the same
14
+ * three IN A DIFFERENT ORDER — [n4,n2,n3] from n2, [n3,n2,n4] from n3 — so a row is found by
15
+ * `name` and NEVER by position, and the `{node}` in the path is only the node being ASKED.
16
+ * MEASURED too: there is no GET on the id path at all; `pvesh get /nodes/n2/ceph/mon/n2` answers
17
+ * "No 'get' handler defined for '/nodes/n2/ceph/mon/n2'", and mgr and mds answer the same.
18
+ * That is why `path()` below is the COLLECTION, and that in turn is why `delete` is the one
19
+ * handler this file writes by hand: `pveOperations.destroy` sends its DELETE to `spec.path`,
20
+ * which here would be the collection — a 501 reported as a failed destroy, with the daemon still
21
+ * running. Same shape and same rule as the override in acl.ts: do not "restore symmetry" by
22
+ * pointing it back at `ops.destroy`.
23
+ *
24
+ * ⛔ WHAT A DESTROY ACTUALLY DOES, BECAUSE THE PLAN LINE SAYS ONLY "delete". REASONED FROM PVE'S
25
+ * AND CEPH'S DOCUMENTED BEHAVIOUR, NOT MEASURED — nothing on this cluster was destroyed to find
26
+ * out, and nothing should be to check. `mon`: stops ceph-mon@id, removes it from the monmap and
27
+ * strips its section from ceph.conf. THREE MONS TOLERATE ONE LOSS; TWO TOLERATE NONE. Removing
28
+ * two in one deploy — or removing the mon on the node whose API is serving the call — loses
29
+ * quorum, and a cluster without mon quorum BLOCKS every RBD and CephFS I/O rather than erroring
30
+ * it, so on this cluster every guest on `cephtb4` hangs.
31
+ * `mds`: destroying a STANDBY is a non-event; destroying the ACTIVE one fails CephFS over,
32
+ * and with no standby left `cephfs-tb4` goes unavailable. `mgr`: no guest I/O depends on it, but
33
+ * the last one takes the PG autoscaler, the dashboard and PVE's own Ceph status with it.
34
+ * Live on 2026-09-13: mon, mgr AND mds on each of n2, n3, n4.
35
+ *
36
+ * ★ AND THE ONLY WAY TO REACH THAT DESTROY IS TO DELETE THE DECLARATION. `matches` is deliberately
37
+ * total (see its ⛔), so this resource CANNOT plan a `replace` — which is the one action that
38
+ * would tear down a live mon off the back of an edited field rather than a removed line.
39
+ *
40
+ * ⚠️ THE PRIVILEGES ARE ASYMMETRIC AND THE READ SIDE IS THE CHEAP ONE. The GET checks `any` of
41
+ * `Sys.Audit`/`Datastore.Audit` on `/`, and PVEAuditor holds both (MEASURED:
42
+ * `GET /access/roles/PVEAuditor`), so the mount's `read` role can see this family — unlike
43
+ * `Proxmox.Storage`, which 403s under that lease. POST and DELETE both check `Sys.Modify` on
44
+ * `/`, and MEASURED on this cluster `LXCProvisioner` already holds it, so the provision lane
45
+ * needs no widening for once. ⚠️ `Sys.Modify` on the ROOT path is broad — it also buys
46
+ * datacenter options and every other cluster-wide config write — so it is worth knowing that
47
+ * this credential already has it rather than discovering it the next time something is scoped.
48
+ */
49
+ import { Resource } from 'alchemy';
50
+ import * as Provider from 'alchemy/Provider';
51
+ import { type PveRequirements, type WithTarget } from './resource.ts';
52
+ /**
53
+ * Which Ceph daemon this is. The discriminant picks the collection, the create parameters and
54
+ * which of the read-only extras below will even be populated.
55
+ *
56
+ * ⚠️ `osd` IS NOT HERE AND MUST NOT BE ADDED TO THIS UNION. `/nodes/{node}/ceph/osd` takes a disk
57
+ * device, wipes it, and its DELETE has a `cleanup` flag — a create that destroys data on the way
58
+ * in is a different resource with a different set of refusals, not a fourth case in this one.
59
+ */
60
+ export type CephDaemonKind = 'mon' | 'mgr' | 'mds';
61
+ export interface CephDaemonProps extends WithTarget {
62
+ kind: CephDaemonKind;
63
+ /**
64
+ * The node the daemon RUNS on. Identity — a daemon cannot be moved, only destroyed and rebuilt.
65
+ * ⚠️ It is also the node whose API is asked, and the read is only as available as that node: a
66
+ * node that is down — or has no Ceph installed, or answers 403 — reads as nothing at all,
67
+ * because `pveOperations.read` folds EVERY failure into "absent" (a 404 is a legitimate answer
68
+ * there and it cannot tell the two apart). Its daemons then plan as `update`, and reconcile
69
+ * POSTs a create for a mon that already exists. PVE refuses that with "monitor already
70
+ * exists", and the read-back refuses again — so it fails loudly rather than damaging anything,
71
+ * but the message will point at the daemon rather than at the node that would not answer.
72
+ */
73
+ node: string;
74
+ /**
75
+ * The daemon id. PVE defaults it to the nodename, and `daemonId` in ceph-daemon-form.ts resolves
76
+ * that default HERE rather than leaving it to PVE, because the id is a PATH SEGMENT: create,
77
+ * delete and the row lookup all need the same string, and a default resolved on the far side
78
+ * would leave three call sites guessing. Live on this cluster every daemon's name is its node.
79
+ */
80
+ name?: string;
81
+ /**
82
+ * mon only. Overrides the autodetected monitor IP; must sit in Ceph's public network — on this
83
+ * cluster that is 10.20.11.0/24, carried by `vmbr1.11`.
84
+ * ⛔ CREATE-ONLY AND NEVER COMPARED. PVE takes a bare ip-list on write and hands back `addr` as
85
+ * `10.20.11.12:6789/0` — an address, a port and a nonce. The two are not the same string and
86
+ * never will be, so diffing them would report a mismatch on every plan; with no PUT on this
87
+ * family that mismatch becomes a REPLACE, and a replace of a mon is the quorum loss in the
88
+ * header. Left out of `matches` on purpose.
89
+ */
90
+ 'mon-address'?: string;
91
+ /**
92
+ * mds only. Makes this standby replay the active MDS's journal for a faster failover.
93
+ * ⛔ CREATE-ONLY AND NEVER COMPARED, AND THE FIELD THAT LOOKS LIKE ITS READBACK IS NOT ONE.
94
+ * `standby_replay` in the list is the daemon's CURRENT state, not its configuration: MEASURED
95
+ * 2026-09-13, all three mds report `standby_replay: false`, n3 included — and n3 is the ACTIVE
96
+ * mds, which is not a standby at all and so can never report true however it was created.
97
+ * Comparing `hotstandby` to it would plan a replace against whichever mds Ceph happens to have
98
+ * elected, i.e. against a value no declaration controls.
99
+ * ⚠️ SET ON A mon OR mgr IT IS DROPPED RATHER THAN SENT, and `mon-address` likewise on an mds:
100
+ * each POST schema lists only its own parameter, so the wrong one is a 400 rather than an
101
+ * ignored hint. A field silently dropped is the lesser of the two, but it IS dropped.
102
+ */
103
+ hotstandby?: boolean;
104
+ }
105
+ /**
106
+ * Everything the cluster says about this daemon — reported, and (bar its identity) none of it
107
+ * compared. Read the ⛔ on `matches` for why that is the only safe split on this family.
108
+ */
109
+ export interface CephDaemonAttributes {
110
+ kind: CephDaemonKind;
111
+ node: string;
112
+ name: string;
113
+ /**
114
+ * The host Ceph says it runs on.
115
+ * ⚠️ REPORTED, NOT COMPARED, AND THAT IS A DELIBERATE BLIND SPOT. A daemon found under this name
116
+ * on a DIFFERENT node than `node` declares plans as `noop`, which does hide a misdeclaration.
117
+ * The alternative is worse: `host` is `optional` in the schema, so an absent one would read as
118
+ * a mismatch, and with no PUT a mismatch is a replace — i.e. a missing field in one API answer
119
+ * would destroy a live mon. When in doubt, out of `matches`; fix a wrong node by hand.
120
+ */
121
+ host: string;
122
+ /**
123
+ * mon `running`/`stopped`/`unknown`, mgr `active`/`standby`, mds `up:active`/`up:standby`/…
124
+ * ⛔ CEPH ELECTS THIS AND REWRITES IT WITHOUT ANYONE DECLARING ANYTHING. MEASURED: mgr n2 is
125
+ * `active` while n3 and n4 are `standby`; mds n3 is `up:active` while n2 and n4 are
126
+ * `up:standby`. Restart a daemon and the roles move. It is reported so a plan can show what is
127
+ * live and kept out of `matches` so that an election is never a diff.
128
+ * ⚠️ IT ALSO MEANS THIS RESOURCE DOES NOT MANAGE WHETHER THE DAEMON IS RUNNING. A configured but
129
+ * stopped daemon is still a row in the list, so it reads as present and plans `noop`.
130
+ */
131
+ state: string;
132
+ /** Ceph-formatted, e.g. `10.20.11.12:6789/0`. Reported; see `mon-address` for why never compared. */
133
+ addr: string;
134
+ /** `ceph_version_short`, e.g. `20.2.2`. Reported: a straggler after an upgrade is worth seeing. */
135
+ version: string;
136
+ /**
137
+ * mon rank in the monmap, mds rank in the filesystem, `-1` when the daemon has neither.
138
+ * ⛔ CEPH ASSIGNS IT AND NOTHING DECLARES IT. MEASURED: the mons are ranked n4=0, n3=1, n2=2 —
139
+ * monmap order, not declaration order — and the mds ranks are 0 for the active n3 and -1 for
140
+ * the two standbys. Rank moves when a daemon is added, removed or restarted.
141
+ */
142
+ rank: number;
143
+ /** mon only: in the current quorum. Reported. MEASURED: all three mons are in quorum. */
144
+ quorum: boolean;
145
+ /** mds only, and NOT the readback of `hotstandby` — see the ⛔ on that prop. */
146
+ standbyReplay: boolean;
147
+ /**
148
+ * mds only: the CephFS this daemon currently serves — `cephfs-tb4` here.
149
+ * ⛔ PRESENT ONLY ON THE ACTIVE MDS. MEASURED: n3 carries `fs_name`, n2 and n4 have no such key
150
+ * at all. So it is empty for two of three identical declarations, and comparing it would
151
+ * report work on exactly the daemons that are healthy standbys.
152
+ */
153
+ fsName: string;
154
+ /** A `ceph-<kind>@<id>` systemd unit is enabled on the host. Reported; absent reads as false. */
155
+ service: boolean;
156
+ }
157
+ export interface ProxmoxCephDaemon extends Resource<'Proxmox.CephDaemon', CephDaemonProps, CephDaemonAttributes, never, PveRequirements> {
158
+ }
159
+ /** ★ `retain` by default — a mon carrying quorum cannot be rebuilt. See the ★ in resource.ts. */
160
+ export declare const ProxmoxCephDaemon: import("alchemy").ResourceClass<ProxmoxCephDaemon>;
161
+ export declare const ProxmoxCephDaemonProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxCephDaemon>, never, import("effect/unstable/http/HttpClient").HttpClient>;
162
+ //# sourceMappingURL=ceph-daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-daemon.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEnD,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,cAAc,CAAC;IACrB;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,qGAAqG;IACrG,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,MAAM,EAAE,OAAO,CAAC;IAChB,+EAA+E;IAC/E,aAAa,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,oDAE5B,CAAC;AA+CH,eAAO,MAAM,yBAAyB,uIAoBnC,CAAC"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * `Proxmox.CephFlag` — one cluster-wide Ceph OSD flag, declared: `noout`, `pause`, `norebalance`.
3
+ *
4
+ * ★ ONE RESOURCE PER FLAG, NOT ONE CARRYING ALL ELEVEN, AND THE CLUSTER'S OWN API DECIDED IT.
5
+ * MEASURED on TB4 2026-09-13 (pve-manager 9.2.11, ceph tentacle 20.2.2) by reading
6
+ * `/usr/share/perl5/PVE/API2/Cluster/Ceph.pm` and the published schema in
7
+ * `/usr/share/pve-docs/api-viewer/apidoc.js`:
8
+ * · `PUT /cluster/ceph/flags` ends in `fork_worker('cephsetflags', ...)` and returns a STRING
9
+ * — a UPID. The bulk write is ASYNCHRONOUS, and this package has no task-polling machinery.
10
+ * · `PUT /cluster/ceph/flags/{flag}` calls `$rados->mon_command` inline and returns null. The
11
+ * per-flag write is SYNCHRONOUS.
12
+ * `pveOperations.reconcile` READS BACK after every write and refuses to record a value it did
13
+ * not see. Against the bulk endpoint that read-back races a worker which has not run yet, so it
14
+ * would record the OLD value as the new attributes — the one honesty mechanism in this package
15
+ * turned into a lie generator. Per-flag, the read-back means what it says.
16
+ * ★ THE SECOND REASON IS SMALLER AND STILL REAL. The bulk GET answers rows of
17
+ * `{name, description, value}`, and `description` is PVE's own English prose that no write
18
+ * accepts: compare it and you have a forever-update, report it and this provider is pretending
19
+ * to manage prose. `GET /cluster/ceph/flags/{flag}` answers a BARE BOOLEAN, so that trap
20
+ * cannot be written here at all. The brief's plural `Proxmox.CephFlags` became singular for
21
+ * those two reasons; the bulk endpoint is read by nothing in this package.
22
+ *
23
+ * ⛔ THESE ARE NOT CONFIGURATION. THEY ARE A HAND ON THE BRAKE, AND A DECLARATION CAN PULL IT OFF.
24
+ * `noout` is what a person sets before pulling a disk. A stack saying `value: false` reasserts
25
+ * that off on EVERY deploy — including a deploy somebody else runs, for an unrelated resource,
26
+ * twenty minutes into a maintenance window — and the plan line reads `Proxmox.CephFlag noout
27
+ * update`, which nobody reads as "ceph is about to start rebalancing 128 PGs across three nodes
28
+ * while a disk is out of the chassis".
29
+ * ★ SO `value` IS REQUIRED AND HAS NO DEFAULT, AND THAT IS THE MITIGATION. An optional `value`
30
+ * defaulting to false would make `CephFlag('noout', { flag: 'noout', target })` mean "clear
31
+ * it" — the dangerous direction, chosen by OMISSION. Here the dangerous sentence has to be
32
+ * typed out by a person. Do not add a default, and do not declare a flag merely to document
33
+ * that it is off: MEASURED 2026-09-13, all eleven flags on TB4 read 0, so eleven
34
+ * `value: false` lines would plan green forever and do nothing except take the brake off
35
+ * whenever somebody happens to apply them.
36
+ *
37
+ * ⛔ `delete` DOES NOTHING, ON PURPOSE, AND THE ASYMMETRY OF THE TWO FAILURES IS THE ARGUMENT.
38
+ * `flags/{flag}` has exactly two methods, GET and PUT, so the factory's `destroy` would answer
39
+ * "Method 'DELETE /cluster/ceph/flags/noout' not implemented" on every teardown — whatever this
40
+ * handler does is INVENTED. The obvious invention, "clear the flag", is refused: removing a line
41
+ * from a stack file, or Alchemy collecting an old generation after a replace, would silently
42
+ * take the brake off and nothing would warn. Leaving a flag set that nothing declares any more
43
+ * is the opposite kind of failure — ceph reports `HEALTH_WARN ... flag(s) set` for every one of
44
+ * these, on `ceph -s`, in the PVE UI and in the `pve_*` metrics this estate already scrapes.
45
+ * A silent destructive failure loses to a loud inert one.
46
+ * ⚠️ THE RESIDUAL RISK, NAMED RATHER THAN DENIED: deleting a `value: true` declaration LEAVES
47
+ * THE FLAG SET. Retire a maintenance window by flipping the line to `value: false` and
48
+ * deploying BEFORE the line is removed, or a `noout` outlives the window that needed it.
49
+ * ⚠️ REASONED, NOT MEASURED: that health warning was not observed, because observing it means
50
+ * setting a flag on a live cluster and this file was researched read-only. Undeclaring stops
51
+ * MANAGING a flag; to clear one, declare `value: false` and deploy, where a plan says so.
52
+ *
53
+ * ⛔ `pause` IS TWO CEPH FLAGS AND THIS RESOURCE READS ONLY ONE OF THEM. MEASURED in
54
+ * `PVE::Ceph::Tools::get_real_flag_name`, whose own comment reads "the 'pause' flag gets always
55
+ * set to both 'pauserd' and 'pausewr'": PVE writes both and then decides the flag is set by
56
+ * looking at `pauserd` alone. A cluster where somebody ran `ceph osd unset pauserd` by hand
57
+ * still has `pausewr` — writes blocked, guests hung — and this resource reports `value: false`
58
+ * and plans `noop` straight past it. It cannot express a half-pause, so never use it to prove
59
+ * one is gone; `ceph osd dump | head -1` can.
60
+ * ⛔ `pause` AND `noup` ARE ALSO THE TWO THAT TAKE THE CLUSTER DOWN FROM A TYPO. `pause: true`
61
+ * stops all reads and writes, so every guest on `cephtb4` — the cluster's only rbd pool,
62
+ * MEASURED 2026-09-13 — freezes on its root disk, and so does `cephfs-tb4`. `noup: true`
63
+ * stops a rebooted OSD from ever rejoining. Neither is undone by deleting the line.
64
+ *
65
+ * ⚠️ PRIVILEGES, AND THE WRITE ONE IS A BIG ASK. Both GETs check `Sys.Audit` on `/`; both PUTs
66
+ * check `Sys.Modify` on `/`, and all four carry `allowtoken => 1`, so an API token may make the
67
+ * call at all. There is no `/ceph` ACL object to scope to — the check names the ROOT path
68
+ * literally — so granting the provision role `Sys.Modify` here also buys datacenter options,
69
+ * metric servers, notification targets and every other cluster-wide write, exactly as
70
+ * metric-server.ts warns about its own family.
71
+ * ⚠️ REASONED, NOT MEASURED: nothing here was exercised under a minted lease, because a mint
72
+ * writes an API token into the cluster and the brief for this file was reads only. Expect
73
+ * "Permission check failed (/, Sys.Modify)" on the first deploy, and widen deliberately.
74
+ */
75
+ import { Resource } from 'alchemy';
76
+ import * as Provider from 'alchemy/Provider';
77
+ import { type PveRequirements, type WithTarget } from './resource.ts';
78
+ /**
79
+ * PVE's eleven flags, spelled as `PVE::Ceph::Tools::get_possible_osd_flags` spells them.
80
+ *
81
+ * ⚠️ THE ENUM IS CLOSED AND A TYPO IS A 400, WHICH IS WHY THIS IS A UNION AND NOT `string`. Both
82
+ * the GET and the PUT declare `additionalProperties => 0` over exactly this list.
83
+ * ⚠️ CEPH HAS FLAGS PVE DOES NOT MODEL, and four of them are always on. MEASURED on TB4:
84
+ * `ceph osd dump` reports `flags sortbitwise,recovery_deletes,purged_snapdirs,pglog_hardlimit`.
85
+ * PVE reads that same string and answers only about its own eleven, so the others can neither
86
+ * leak in here nor be set from here — `noautoscale` and `nosnaptrim` included.
87
+ * ⛔ IF SOMEBODY LATER "IMPROVES" THE READ BY PARSING `osd dump` DIRECTLY, those four become
88
+ * permanently-set flags that nothing declares: a forever-diff on a brand new cluster.
89
+ */
90
+ export type CephFlagName = 'nobackfill' | 'nodeep-scrub' | 'nodown' | 'noin' | 'noout' | 'norebalance' | 'norecover' | 'noscrub' | 'notieragent' | 'noup' | 'pause';
91
+ export interface CephFlagProps extends WithTarget {
92
+ /**
93
+ * Which flag. PVE's primary key here, and the last segment of the path.
94
+ *
95
+ * ⚠️ EDITING IT IN PLACE ORPHANS THE OLD FLAG RATHER THAN MOVING ANYTHING. `diff` reads the NEW
96
+ * path and reconcile writes it, while the old flag keeps whatever this stack last put there.
97
+ * There is deliberately no replace override for it — acl.ts needs one because its `delete`
98
+ * removes a real grant, and `delete` here is inert by design, so a replace would do exactly
99
+ * what an update already does. Declare a second resource and set the old one to `value: false`
100
+ * rather than renaming this one.
101
+ * ⛔ TWO RESOURCES DECLARING THE SAME FLAG ARE ONE CLUSTER OBJECT, and Alchemy sees two ids
102
+ * rather than a collision — the acl.ts hazard exactly. Disagreeing, they take turns winning
103
+ * and BOTH plan `update` for ever; agreeing, deleting either leaves the flag where the other
104
+ * put it. One declaration per flag per cluster.
105
+ */
106
+ flag: CephFlagName;
107
+ /**
108
+ * Set the flag (`true`) or clear it (`false`).
109
+ *
110
+ * ⛔ REQUIRED, WITH NO DEFAULT — see the second ⛔ in the header, which is the whole safety
111
+ * argument for this family. It is also the only field PVE accepts on this endpoint, and it is
112
+ * not optional in the schema either: omitting it from the form is a 400, not an untouched
113
+ * flag. (The BULK endpoint is the one where omission means "leave it alone"; this is not it.)
114
+ */
115
+ value: boolean;
116
+ }
117
+ export interface CephFlagAttributes {
118
+ /**
119
+ * ⚠️ REPORTED, NEVER COMPARED. It is the path key the read was made WITH, copied back out of
120
+ * props, so comparing it against props would be true by construction — the same reasoning
121
+ * acl.ts gives for the four identity fields it also declines to diff.
122
+ */
123
+ flag: CephFlagName;
124
+ /** Whether ceph has the flag set right now. The only field `matches` looks at. */
125
+ value: boolean;
126
+ }
127
+ export interface ProxmoxCephFlag extends Resource<'Proxmox.CephFlag', CephFlagProps, CephFlagAttributes, never, PveRequirements> {
128
+ }
129
+ export declare const ProxmoxCephFlag: import("alchemy").ResourceClass<ProxmoxCephFlag>;
130
+ export declare const ProxmoxCephFlagProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxCephFlag>, never, import("effect/unstable/http/HttpClient").HttpClient>;
131
+ //# sourceMappingURL=ceph-flag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-flag.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-flag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;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;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GACpB,YAAY,GACZ,cAAc,GACd,QAAQ,GACR,MAAM,GACN,OAAO,GACP,aAAa,GACb,WAAW,GACX,SAAS,GACT,aAAa,GACb,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C;;;;;;;;;;;;;OAaG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB;;;;;;;OAOG;IACH,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB,kFAAkF;IAClF,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,eAAgB,SAAQ,QAAQ,CAC/C,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,eAAe,kDAAgD,CAAC;AAqD7E,eAAO,MAAM,uBAAuB,qIA4CjC,CAAC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * The wire lane of `Proxmox.CephFs`: how a PVE answer becomes attributes, how a declaration becomes
3
+ * a PVE call, and how that call becomes a fact.
4
+ *
5
+ * ★ SPLIT OUT OF ceph-fs.ts TO KEEP BOTH FILES UNDER THE 250-LINE CAP, and the seam is a real one
6
+ * rather than a convenient line number. ceph-fs.ts answers "what is a CephFS, and when has it
7
+ * changed"; this file answers "what does PVE say, what does it want, and has it finished". On
8
+ * this family that is where all the strangeness lives — the read is an index and not an object,
9
+ * the paths are inverted, the delete takes its arguments in the query string, and both writes
10
+ * fork a worker — so keeping it in one place is what stops the next reader assuming the ordinary
11
+ * shape from the other nineteen resources. ⚠️ NOTHING HERE DECIDES A DIFF.
12
+ *
13
+ * ⚠️ THE `import type` BACK TO ceph-fs.ts IS A CYCLE ON PAPER ONLY. It is type-only and erased
14
+ * before anything runs, exactly as metric-server-form.ts imports `MetricServerProps`. The props
15
+ * stay the resource's public shape, declared in the file that declares the resource.
16
+ *
17
+ * ⛔ POST AND DELETE ANSWER WITH A UPID, NOT A RESULT — THE WRITE IS ASYNCHRONOUS AND A FAILED ONE
18
+ * IS STILL HTTP 200. Read from the cluster's own source, /usr/share/perl5/PVE/API2/Ceph/FS.pm on
19
+ * n2: `createfs` and `destroyfs` both end `return $rpcenv->fork_worker(...)`. Two different lies
20
+ * come out of trusting that status code. A read-back straight after the POST reports "still
21
+ * absent" about a filesystem that is being built as it says so — which is precisely the message
22
+ * `pveOperations.reconcile` would print, pointing at the wrong cause. And a worker that dies
23
+ * INSIDE — the pool create, or the add-storage step, both of which are wrapped in `eval` — is
24
+ * never reported to the caller at all. `settle` below is the answer to both.
25
+ * ⚠️ REASONED FROM THAT SOURCE, NOT MEASURED. Nothing was written to this cluster, so the race
26
+ * has not been observed; only the `fork_worker` that guarantees it is there.
27
+ *
28
+ * ⛔ A DELETE BODY IS SILENTLY DISCARDED BY PVE, SO `remove-pools` GOES IN THE QUERY STRING.
29
+ * MEASURED in /usr/share/perl5/PVE/APIServer/AnyEvent.pm on n2: line 928 reads the request
30
+ * content into params only `if ($method eq 'PUT' || $method eq 'POST')`, and line 1653 sends
31
+ * every other method down a branch that parses `$request->url->query()` and nothing else. So
32
+ * `pve(target, role, 'DELETE', path, form)` would send a body PVE never looks at: the flags would
33
+ * read as unset, the pools would quietly survive a delete that asked for them, and no error would
34
+ * be raised anywhere. sdn-apply.ts already puts `?pending=1` in the path for the same reason.
35
+ *
36
+ * ⚠️ THE TASK POLL RUNS ON THE `read` ROLE THOUGH IT SITS INSIDE reconcile, FOR TWO REASONS. It is
37
+ * a read, and resource.ts already mints `read` for its own read-back inside reconcile. And the
38
+ * leases differ where it matters: `provision` is 300s and explicitly non-renewable, so a create
39
+ * that waits out a slow worker on that lease can expire mid-poll, while `read` is 3600s.
40
+ *
41
+ * ⛔ THE POLLER IS NEVER THE TASK'S OWNER, WHICH COSTS A PRIVILEGE, AND THIS ONE IS MEASURED
42
+ * RATHER THAN FEARED. client.ts mints a fresh credential per call and the mount vends a NEW
43
+ * token id each time, so the token reading the status is never the token recorded in the UPID —
44
+ * and PVE compares them exactly. /usr/share/perl5/PVE/API2/Tasks.pm on n2, `$check_task_user`:
45
+ * `return $user eq $fulltoken || $user eq $task->{user};`, above it the comment "token only sees
46
+ * token tasks, user sees user + token tasks". Token B of the same user matches neither branch.
47
+ * So the fallback is the schema's other clause for `GET /nodes/{node}/tasks/{upid}/status`: "The
48
+ * user needs 'Sys.Audit' permissions on '/nodes/<node>' if they are not the owner of the task."
49
+ * Grant it on the `read` role, or every create burns the full cap below and reports the wrong
50
+ * cause.
51
+ */
52
+ import * as Effect from 'effect/Effect';
53
+ import type { CephFsAttributes, CephFsProps } from './ceph-fs.ts';
54
+ /**
55
+ * This filesystem's row of the index, as attributes.
56
+ *
57
+ * ⚠️ `GET /nodes/{node}/ceph/fs` ANSWERS AN ARRAY, while the factory hands `attributes` the
58
+ * `Record<string, unknown>` every other PVE read is shaped like. Rows are narrowed rather than
59
+ * trusted, the same way acl.ts narrows its one flat grant list.
60
+ *
61
+ * ⛔ RETURNING undefined IS WHAT MAKES "ABSENT" MEAN ABSENT HERE, unlike acl.ts where the object is
62
+ * always present-but-unbound. A filesystem missing from the index has not been created, and
63
+ * `reconcile` takes the create branch on exactly that signal.
64
+ */
65
+ export declare const readRow: (live: Record<string, unknown>, props: CephFsProps) => CephFsAttributes | undefined;
66
+ /** ⚠️ `nodes/{n}/ceph/fs/{name}` — the POST and DELETE target, and NOT where a read goes. */
67
+ export declare const objectPath: (props: CephFsProps) => string;
68
+ /**
69
+ * ⚠️ `name` IS DELIBERATELY ABSENT FROM THE FORM. It is already the last segment of the path being
70
+ * POSTed to — the metric-server.ts case again — and a second copy can only ever disagree with it.
71
+ */
72
+ export declare const createForm: (props: CephFsProps) => Record<string, string>;
73
+ /**
74
+ * POST the create, then wait for the worker. ⛔ The caller still reads back; see ceph-fs.ts.
75
+ *
76
+ * ⚠️ A CREATE NEEDS A RUNNING *AND* A STANDBY MDS, and refuses BEFORE it forks -- "no running
77
+ * Metadata Server (MDS) found!" / "no standby Metadata Server (MDS) found!" are synchronous, so
78
+ * they surface as a failed POST rather than as a silent worker. TB4 has three (MEASURED: n3
79
+ * `up:active` for cephfs-tb4, n2 and n4 `up:standby`), so this is a note for a smaller cluster.
80
+ * ⚠️ BOTH WRITES CHECK `Sys.Modify` ON `/` -- the root, with the breadth metric-server.ts warns
81
+ * about: granting it buys datacenter options and every other cluster-wide config write too.
82
+ */
83
+ export declare const createFs: (props: CephFsProps) => Effect.Effect<undefined, Error, import("effect/unstable/http/HttpClient").HttpClient>;
84
+ /**
85
+ * DELETE the filesystem, then wait for the worker.
86
+ *
87
+ * ⛔ WHAT THIS TAKES AWAY DEPENDS ENTIRELY ON `remove-pools`, AND THE DEFAULT IS THE SAFE ONE. With
88
+ * it unset PVE removes the filesystem from the MDS map and LEAVES the two pools on disk: every
89
+ * mount breaks, but the bytes are still there for an operator to recover. With it set the pools
90
+ * go too and nothing is recoverable. Leaving it unset also means a later create of the SAME name
91
+ * fails with "ceph pools '<name>_data' and/or '<name>_metadata' already exist" -- that refusal is
92
+ * a BRAKE, not a bug, and it is the last thing standing between a mis-typed rename and the data.
93
+ */
94
+ export declare const destroyFs: (props: CephFsProps) => Effect.Effect<void, Error, import("effect/unstable/http/HttpClient").HttpClient>;
95
+ /**
96
+ * The two read-back failures, as messages rather than as guesses.
97
+ *
98
+ * ⛔ WAITING PROVES THE TASK ENDED; ONLY A READ PROVES THE FILESYSTEM DID OR DID NOT. `createfs`
99
+ * wraps its pool creates in an `eval` and CLEANS THEM UP on error before dying, so a worker can
100
+ * plausibly end having built and then removed everything it made. `destroyfs` refuses outright
101
+ * while a non-disabled `cephfs` storage still references the filesystem. Neither outcome is
102
+ * visible in a status code, which is why ceph-fs.ts reads back after both and dies with these.
103
+ */
104
+ export declare const notCreated: (props: CephFsProps) => Error;
105
+ export declare const notDestroyed: (props: CephFsProps) => Error;
106
+ //# sourceMappingURL=ceph-fs-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-fs-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAKlE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO,SACZ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SACtB,WAAW,KACjB,gBAAgB,GAAG,SAkBrB,CAAC;AAaF,6FAA6F;AAC7F,eAAO,MAAM,UAAU,UAAW,WAAW,WAAgD,CAAC;AAM9F;;;GAGG;AACH,eAAO,MAAM,UAAU,UAAW,WAAW,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAGnE,CAAC;AA2DH;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,UAAW,WAAW,0FAiBvC,CAAC;AAEL;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS,UAAW,WAAW,qFAQxC,CAAC;AAEL;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,UAAW,WAAW,UAK1C,CAAC;AAEJ,eAAO,MAAM,YAAY,UAAW,WAAW,UAK5C,CAAC"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * `Proxmox.CephFs` — a CephFS on the cluster's own Ceph. The filesystem a `cephfs` storage mounts.
3
+ *
4
+ * ⛔ A REPLACE OF THIS RESOURCE DESTROYS A LIVE FILESYSTEM, AND THERE IS NO PUT TO SAVE YOU FROM
5
+ * IT. MEASURED from the published schema on n2, 2026-09-13: `/nodes/{node}/ceph/fs/{name}` has
6
+ * exactly two methods, POST and DELETE. A CephFS cannot be edited in place, so `updateForm` is
7
+ * left undefined and anything the factory can see as changed becomes a REPLACE — and Alchemy's
8
+ * replace is create-then-delete, where the delete is `destroyfs`: the entry leaves the MDS map,
9
+ * every mount on every node breaks, and whether the bytes survive rests on `remove-pools` alone.
10
+ * ★ WHICH IS THE WHOLE REASON `matches` COMPARES NOTHING. Read its ⛔ before adding a field to
11
+ * it. On every other resource in this package a forever-diff is an annoying plan line; on this
12
+ * one it is a live filesystem destroyed on every deploy, forever, because a background daemon
13
+ * moved a number nobody declared.
14
+ *
15
+ * ⛔ THERE IS NO SINGLE-OBJECT READ, WHICH INVERTS `path` AND `collection`. MEASURED on n2:
16
+ * pvesh get /nodes/n2/ceph/fs/cephfs-tb4
17
+ * -> No 'get' handler defined for '/nodes/n2/ceph/fs/cephfs-tb4'
18
+ * `GET /nodes/{node}/ceph/fs` is a directory index and is the only read there is, so `path()`
19
+ * below returns the INDEX and `attributes` picks this filesystem out of the array client-side —
20
+ * the shape acl.ts uses for the one flat `GET /access/acl`. The POST goes to the `{name}` path,
21
+ * so `collection()` is the LONGER of the two strings, the mirror of metric-server.ts.
22
+ * ⚠️ AND THAT IS WHY `delete` AND `reconcile` ARE HAND-WRITTEN BELOW rather than taken from
23
+ * `pveHandlers`. `pveOperations.destroy` deletes `spec.path`, which here is the index:
24
+ * `DELETE /nodes/{node}/ceph/fs` is not a route, so a factory delete would fail every destroy
25
+ * while the filesystem stayed exactly where it was. `reconcile` is hand-written for a second,
26
+ * independent reason — the forked worker — set out in ceph-fs-wire.ts. acl.ts is the
27
+ * precedent for a family that genuinely does not fit; this is the second.
28
+ *
29
+ * ⛔ CREATING A CephFS CREATES TWO CEPH POOLS, AND A `Proxmox.CephPool` MUST NOT ALSO DECLARE THEM.
30
+ * `createfs` builds `<name>_data` and `<name>_metadata` itself and refuses outright if either
31
+ * exists ("ceph pools '…_data' and/or '…_metadata' already exist"). MEASURED on TB4: the live
32
+ * `cephfs-tb4` owns `cephfs-tb4_data` (id 6) and `cephfs-tb4_metadata` (id 7), both of which
33
+ * `GET /nodes/n2/ceph/pool` lists like any other pool — and `/nodes/{node}/ceph/pool/{name}` DOES
34
+ * have GET, PUT and DELETE, so a pool resource would be a clean `pveHandlers` fit and would
35
+ * adopt them without noticing. Declaring both is double management of one object: whichever
36
+ * reconciles first wins, and the loser either fails its create or PUTs `size`/`pg_num` onto pools
37
+ * this resource believes it owns. Declare the filesystem here and leave its two pools alone.
38
+ *
39
+ * ⚠️ `add-storage` IS A SECOND SIDE EFFECT AND IT LANDS IN storage.cfg. Set, `createfs` also calls
40
+ * `PVE::API2::Storage::Config->create` with type `cephfs`, content `backup,iso,vztmpl` and
41
+ * `fs-name <name>`. MEASURED: /etc/pve/storage.cfg on n2 holds exactly that — `cephfs:
42
+ * cephfs-tb4` / `content backup,vztmpl,iso` / `fs-name cephfs-tb4`. So a `Proxmox.Storage`
43
+ * declaring `cephfs-tb4` would be managing an entry this resource created. Declare ONE of them:
44
+ * either `add-storage` here and no storage resource, or `add-storage` off and a
45
+ * `Proxmox.Storage` that reads this resource's `name` attribute — which also gets the ordering
46
+ * right for free, because Alchemy orders by data flow.
47
+ *
48
+ * ⚠️ `node` IS A ROUTE, NOT IDENTITY, AND MUST NEVER BE DIFFED. A CephFS is cluster-wide; the node
49
+ * in the path only says which node PVE proxies the call to. MEASURED: `GET /nodes/n2/ceph/fs`,
50
+ * `…/n3/…` and `…/n4/…` returned the byte-identical array. So changing `node` plans `noop`, and
51
+ * two resources naming the same `name` on different nodes are the SAME filesystem — the vmid
52
+ * hazard from lxc.ts, with a filesystem on the end of it instead of a container.
53
+ *
54
+ * ⚠️ PRIVILEGES: the read lane needs `Sys.Audit` OR `Datastore.Audit` on `/`, which an auditor
55
+ * role already holds — unlike storage.ts, nothing needs widening before the first plan. The
56
+ * write side is in ceph-fs-wire.ts beside the calls, and in docs/privileges.md with the rest.
57
+ */
58
+ import { Resource } from 'alchemy';
59
+ import * as Provider from 'alchemy/Provider';
60
+ import { type PveRequirements, type WithTarget } from './resource.ts';
61
+ export interface CephFsProps extends WithTarget {
62
+ /** ⚠️ Which node answers the call, NOT which node holds the filesystem. See the header. */
63
+ node: string;
64
+ /**
65
+ * The filesystem name, and the cluster-wide primary key. PVE's pattern is `^[^:/\s]+$`.
66
+ * ⛔ CHANGING IT IS A REPLACE, WHICH DESTROYS THE OLD FILESYSTEM. `diff` says so explicitly
67
+ * below rather than letting the factory report a create-shaped `update` and orphan the old one.
68
+ */
69
+ name: string;
70
+ /**
71
+ * Placement groups for the backing data pool; the metadata pool gets a quarter of it, or 8 when
72
+ * this is under 32. PVE's default is 128.
73
+ *
74
+ * ⛔ CREATE-TIME ONLY, UNREADABLE, AND OWNED BY THE AUTOSCALER FROM THE SECOND IT LANDS. It is
75
+ * never compared — see the ⛔ on `matches` — and this is not caution, it is measured. TB4's
76
+ * `cephfs-tb4` was created with the default 128 (the arithmetic proves it: `cephfs-tb4_metadata`
77
+ * sits at 32, which is 128/4), and `cephfs-tb4_data` reads pg_num 32 TODAY. The autoscaler moved
78
+ * it by a factor of four, and it is not finished: `pg_autoscale_mode` is `on` for every pool on
79
+ * this cluster and `cephfs-tb4_metadata` already reports `pg_num_final: 16` against its live 32.
80
+ */
81
+ pg_num?: number;
82
+ /**
83
+ * Also write a `cephfs` storage entry for this filesystem. ⚠️ Create-time only and never read
84
+ * back — it is an ACTION, not a field. See the header for what it does to `Proxmox.Storage`.
85
+ */
86
+ 'add-storage'?: boolean;
87
+ /** ⛔ DELETE-TIME ONLY, AND IT ERASES THE DATA. Read the ⛔ on `destroyFs` before setting it. */
88
+ 'remove-pools'?: boolean;
89
+ /**
90
+ * Delete the pveceph-managed storage entries too. ⚠️ PVE refuses unless they are already
91
+ * disabled ("storage '…' is not disabled, make sure to disable and unmount the storage first"),
92
+ * so this fails the destroy rather than unmounting anything out from under a running guest.
93
+ */
94
+ 'remove-storages'?: boolean;
95
+ }
96
+ /**
97
+ * ⚠️ EVERY FIELD HERE IS REPORTED AND NONE IS COMPARED. They exist so a plan, and the state entry
98
+ * behind it, can say what the declaration actually points at — which pools hold the bytes.
99
+ */
100
+ export interface CephFsAttributes {
101
+ name: string;
102
+ /** The first data pool. PVE keeps it for compatibility; `data_pools` is the real answer. */
103
+ data_pool: string;
104
+ /**
105
+ * ⚠️ SORTED, AND IT IS A SET RATHER THAN A LIST. A CephFS can hold several data pools — added
106
+ * with `ceph fs add_data_pool`, which this resource has no way to express — and PVE reports
107
+ * them in the MDS map's own order. Sorting is what keeps this attribute stable across reads.
108
+ */
109
+ data_pools: string;
110
+ metadata_pool: string;
111
+ /**
112
+ * ⚠️ AN INTEGER THAT NAMES SOMETHING WRITTEN AS A NAME, AND THEREFORE A CLASSIC FOREVER-DIFF IF
113
+ * IT EVER REACHED `matches`. PVE answers `metadata_pool_id: 7` while every write in this family
114
+ * spells a pool by name. It is here to be read, never to be compared. `-1` means absent: the
115
+ * field is optional in the schema and older PVE omits it.
116
+ */
117
+ metadata_pool_id: number;
118
+ }
119
+ export interface ProxmoxCephFs extends Resource<'Proxmox.CephFs', CephFsProps, CephFsAttributes, never, PveRequirements> {
120
+ }
121
+ /** ★ `retain` by default — a filesystem holding data cannot be rebuilt. See the ★ in resource.ts. */
122
+ export declare const ProxmoxCephFs: import("alchemy").ResourceClass<ProxmoxCephFs>;
123
+ export declare const ProxmoxCephFsProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxCephFs>, never, import("effect/unstable/http/HttpClient").HttpClient>;
124
+ //# sourceMappingURL=ceph-fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-fs.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAW7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAiB,MAAM,eAAe,CAAC;AAErF,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+FAA+F;IAC/F,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,QAAQ,CAC7C,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,qGAAqG;AACrG,eAAO,MAAM,aAAa,gDAExB,CAAC;AA4BH,eAAO,MAAM,qBAAqB,mIA6E/B,CAAC"}