pvectl 0.2.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 (558) hide show
  1. checksums.yaml +7 -0
  2. data/.claude/rules/branch-before-changes.md +52 -0
  3. data/.claude/rules/documentation-updates.md +104 -0
  4. data/.claude/rules/git-workflow.md +84 -0
  5. data/.claude/rules/proxmox-api-docs.md +58 -0
  6. data/.claude/rules/rbs-signatures.md +80 -0
  7. data/.claude/rules/refactoring-as-design-option.md +35 -0
  8. data/.claude/scheduled_tasks.lock +1 -0
  9. data/.claude/settings.json +51 -0
  10. data/.mcp.json +8 -0
  11. data/.ruby-gemset +1 -0
  12. data/.ruby-version +1 -0
  13. data/CHANGELOG.md +138 -0
  14. data/CLAUDE.md +211 -0
  15. data/CODE_OF_CONDUCT.md +132 -0
  16. data/LICENSE.txt +21 -0
  17. data/README.md +143 -0
  18. data/Rakefile +8 -0
  19. data/docs/proxmox-api-update.sh +96 -0
  20. data/exe/pvectl +5 -0
  21. data/lib/pvectl/argv_preprocessor.rb +334 -0
  22. data/lib/pvectl/cli.rb +102 -0
  23. data/lib/pvectl/commands/apt.rb +389 -0
  24. data/lib/pvectl/commands/clone_container.rb +230 -0
  25. data/lib/pvectl/commands/clone_vm.rb +331 -0
  26. data/lib/pvectl/commands/cloudinit/command.rb +122 -0
  27. data/lib/pvectl/commands/cloudinit/dump.rb +94 -0
  28. data/lib/pvectl/commands/cloudinit/pending.rb +137 -0
  29. data/lib/pvectl/commands/cloudinit/regenerate.rb +79 -0
  30. data/lib/pvectl/commands/config/command.rb +65 -0
  31. data/lib/pvectl/commands/config/get_contexts.rb +68 -0
  32. data/lib/pvectl/commands/config/set_cluster.rb +103 -0
  33. data/lib/pvectl/commands/config/set_context.rb +136 -0
  34. data/lib/pvectl/commands/config/set_credentials.rb +181 -0
  35. data/lib/pvectl/commands/config/use_context.rb +69 -0
  36. data/lib/pvectl/commands/config/view.rb +67 -0
  37. data/lib/pvectl/commands/console.rb +93 -0
  38. data/lib/pvectl/commands/console_ct.rb +187 -0
  39. data/lib/pvectl/commands/console_vm.rb +187 -0
  40. data/lib/pvectl/commands/container_lifecycle_command.rb +77 -0
  41. data/lib/pvectl/commands/create_backup.rb +173 -0
  42. data/lib/pvectl/commands/create_container.rb +141 -0
  43. data/lib/pvectl/commands/create_resource_command.rb +244 -0
  44. data/lib/pvectl/commands/create_snapshot.rb +242 -0
  45. data/lib/pvectl/commands/create_vm.rb +267 -0
  46. data/lib/pvectl/commands/delete_backup.rb +139 -0
  47. data/lib/pvectl/commands/delete_command.rb +119 -0
  48. data/lib/pvectl/commands/delete_container.rb +30 -0
  49. data/lib/pvectl/commands/delete_snapshot.rb +248 -0
  50. data/lib/pvectl/commands/delete_vm.rb +127 -0
  51. data/lib/pvectl/commands/describe/command.rb +251 -0
  52. data/lib/pvectl/commands/edit_container.rb +56 -0
  53. data/lib/pvectl/commands/edit_dns.rb +149 -0
  54. data/lib/pvectl/commands/edit_hosts.rb +135 -0
  55. data/lib/pvectl/commands/edit_node.rb +54 -0
  56. data/lib/pvectl/commands/edit_resource_command.rb +180 -0
  57. data/lib/pvectl/commands/edit_vm.rb +154 -0
  58. data/lib/pvectl/commands/edit_volume.rb +189 -0
  59. data/lib/pvectl/commands/feature_command.rb +230 -0
  60. data/lib/pvectl/commands/feature_container.rb +21 -0
  61. data/lib/pvectl/commands/feature_vm.rb +94 -0
  62. data/lib/pvectl/commands/get/command.rb +360 -0
  63. data/lib/pvectl/commands/get/handlers/backups.rb +76 -0
  64. data/lib/pvectl/commands/get/handlers/capabilities.rb +107 -0
  65. data/lib/pvectl/commands/get/handlers/containers.rb +148 -0
  66. data/lib/pvectl/commands/get/handlers/disks.rb +107 -0
  67. data/lib/pvectl/commands/get/handlers/dns.rb +94 -0
  68. data/lib/pvectl/commands/get/handlers/hosts.rb +94 -0
  69. data/lib/pvectl/commands/get/handlers/nodes.rb +162 -0
  70. data/lib/pvectl/commands/get/handlers/services.rb +81 -0
  71. data/lib/pvectl/commands/get/handlers/snapshots.rb +97 -0
  72. data/lib/pvectl/commands/get/handlers/storage.rb +118 -0
  73. data/lib/pvectl/commands/get/handlers/subscription.rb +69 -0
  74. data/lib/pvectl/commands/get/handlers/tasks.rb +89 -0
  75. data/lib/pvectl/commands/get/handlers/templates.rb +175 -0
  76. data/lib/pvectl/commands/get/handlers/time.rb +118 -0
  77. data/lib/pvectl/commands/get/handlers/vms.rb +145 -0
  78. data/lib/pvectl/commands/get/handlers/volume.rb +134 -0
  79. data/lib/pvectl/commands/get/resource_handler.rb +63 -0
  80. data/lib/pvectl/commands/get/resource_registry.rb +18 -0
  81. data/lib/pvectl/commands/get/watch_loop.rb +129 -0
  82. data/lib/pvectl/commands/irreversible_command.rb +265 -0
  83. data/lib/pvectl/commands/logs/command.rb +275 -0
  84. data/lib/pvectl/commands/logs/handlers/journal.rb +46 -0
  85. data/lib/pvectl/commands/logs/handlers/syslog.rb +53 -0
  86. data/lib/pvectl/commands/logs/handlers/task_detail.rb +52 -0
  87. data/lib/pvectl/commands/logs/handlers/task_logs.rb +115 -0
  88. data/lib/pvectl/commands/logs/resource_handler.rb +46 -0
  89. data/lib/pvectl/commands/logs/resource_registry.rb +22 -0
  90. data/lib/pvectl/commands/migrate_command.rb +282 -0
  91. data/lib/pvectl/commands/migrate_container.rb +23 -0
  92. data/lib/pvectl/commands/migrate_vm.rb +122 -0
  93. data/lib/pvectl/commands/move_disk_command.rb +239 -0
  94. data/lib/pvectl/commands/move_disk_container.rb +21 -0
  95. data/lib/pvectl/commands/move_disk_vm.rb +127 -0
  96. data/lib/pvectl/commands/ping.rb +249 -0
  97. data/lib/pvectl/commands/pull.rb +342 -0
  98. data/lib/pvectl/commands/push.rb +352 -0
  99. data/lib/pvectl/commands/reset.rb +64 -0
  100. data/lib/pvectl/commands/resource_lifecycle_command.rb +277 -0
  101. data/lib/pvectl/commands/resource_registry.rb +73 -0
  102. data/lib/pvectl/commands/restart.rb +70 -0
  103. data/lib/pvectl/commands/restart_container.rb +18 -0
  104. data/lib/pvectl/commands/restore_backup.rb +236 -0
  105. data/lib/pvectl/commands/resume.rb +57 -0
  106. data/lib/pvectl/commands/rollback_snapshot.rb +228 -0
  107. data/lib/pvectl/commands/sendkey_vm.rb +205 -0
  108. data/lib/pvectl/commands/service.rb +293 -0
  109. data/lib/pvectl/commands/set_container.rb +50 -0
  110. data/lib/pvectl/commands/set_node.rb +52 -0
  111. data/lib/pvectl/commands/set_resource_command.rb +185 -0
  112. data/lib/pvectl/commands/set_vm.rb +136 -0
  113. data/lib/pvectl/commands/set_volume.rb +212 -0
  114. data/lib/pvectl/commands/shared_config_parsers.rb +126 -0
  115. data/lib/pvectl/commands/shared_flags.rb +155 -0
  116. data/lib/pvectl/commands/shutdown.rb +73 -0
  117. data/lib/pvectl/commands/shutdown_container.rb +18 -0
  118. data/lib/pvectl/commands/start.rb +79 -0
  119. data/lib/pvectl/commands/start_container.rb +18 -0
  120. data/lib/pvectl/commands/stop.rb +75 -0
  121. data/lib/pvectl/commands/stop_container.rb +18 -0
  122. data/lib/pvectl/commands/suspend.rb +64 -0
  123. data/lib/pvectl/commands/template_command.rb +205 -0
  124. data/lib/pvectl/commands/template_container.rb +27 -0
  125. data/lib/pvectl/commands/template_vm.rb +106 -0
  126. data/lib/pvectl/commands/top/command.rb +206 -0
  127. data/lib/pvectl/commands/top/handlers/containers.rb +61 -0
  128. data/lib/pvectl/commands/top/handlers/nodes.rb +61 -0
  129. data/lib/pvectl/commands/top/handlers/vms.rb +61 -0
  130. data/lib/pvectl/commands/top/resource_handler.rb +46 -0
  131. data/lib/pvectl/commands/top/resource_registry.rb +22 -0
  132. data/lib/pvectl/commands/unlink_disk_vm.rb +232 -0
  133. data/lib/pvectl/commands/vm_lifecycle_command.rb +77 -0
  134. data/lib/pvectl/commands/wakeonlan_node.rb +153 -0
  135. data/lib/pvectl/config/errors.rb +62 -0
  136. data/lib/pvectl/config/models/cluster.rb +180 -0
  137. data/lib/pvectl/config/models/context.rb +100 -0
  138. data/lib/pvectl/config/models/resolved_config.rb +171 -0
  139. data/lib/pvectl/config/models/user.rb +133 -0
  140. data/lib/pvectl/config/provider.rb +297 -0
  141. data/lib/pvectl/config/service.rb +300 -0
  142. data/lib/pvectl/config/store.rb +161 -0
  143. data/lib/pvectl/config/wizard.rb +309 -0
  144. data/lib/pvectl/config_serializer.rb +1034 -0
  145. data/lib/pvectl/connection/retry_handler.rb +161 -0
  146. data/lib/pvectl/connection.rb +157 -0
  147. data/lib/pvectl/console/terminal_session.rb +449 -0
  148. data/lib/pvectl/editor_session.rb +157 -0
  149. data/lib/pvectl/exit_codes.rb +43 -0
  150. data/lib/pvectl/formatters/base.rb +55 -0
  151. data/lib/pvectl/formatters/color_support.rb +90 -0
  152. data/lib/pvectl/formatters/json.rb +45 -0
  153. data/lib/pvectl/formatters/output_helper.rb +77 -0
  154. data/lib/pvectl/formatters/registry.rb +72 -0
  155. data/lib/pvectl/formatters/table.rb +235 -0
  156. data/lib/pvectl/formatters/wide.rb +93 -0
  157. data/lib/pvectl/formatters/yaml.rb +49 -0
  158. data/lib/pvectl/manifest_serializer.rb +142 -0
  159. data/lib/pvectl/models/apt_package.rb +107 -0
  160. data/lib/pvectl/models/backup.rb +173 -0
  161. data/lib/pvectl/models/base.rb +49 -0
  162. data/lib/pvectl/models/capability.rb +62 -0
  163. data/lib/pvectl/models/container.rb +205 -0
  164. data/lib/pvectl/models/container_operation_result.rb +27 -0
  165. data/lib/pvectl/models/dns_config.rb +54 -0
  166. data/lib/pvectl/models/hosts_file.rb +47 -0
  167. data/lib/pvectl/models/journal_entry.rb +16 -0
  168. data/lib/pvectl/models/network_interface.rb +85 -0
  169. data/lib/pvectl/models/node.rb +195 -0
  170. data/lib/pvectl/models/node_operation_result.rb +45 -0
  171. data/lib/pvectl/models/operation_result.rb +110 -0
  172. data/lib/pvectl/models/physical_disk.rb +193 -0
  173. data/lib/pvectl/models/service.rb +80 -0
  174. data/lib/pvectl/models/snapshot.rb +101 -0
  175. data/lib/pvectl/models/snapshot_description.rb +39 -0
  176. data/lib/pvectl/models/storage.rb +180 -0
  177. data/lib/pvectl/models/subscription.rb +87 -0
  178. data/lib/pvectl/models/syslog_entry.rb +17 -0
  179. data/lib/pvectl/models/task.rb +95 -0
  180. data/lib/pvectl/models/task_entry.rb +52 -0
  181. data/lib/pvectl/models/task_log_line.rb +17 -0
  182. data/lib/pvectl/models/time_config.rb +47 -0
  183. data/lib/pvectl/models/vm.rb +137 -0
  184. data/lib/pvectl/models/vm_operation_result.rb +27 -0
  185. data/lib/pvectl/models/volume.rb +133 -0
  186. data/lib/pvectl/models/volume_operation_result.rb +26 -0
  187. data/lib/pvectl/parsers/cloud_init_config.rb +92 -0
  188. data/lib/pvectl/parsers/disk_config.rb +97 -0
  189. data/lib/pvectl/parsers/lxc_mount_config.rb +98 -0
  190. data/lib/pvectl/parsers/lxc_net_config.rb +97 -0
  191. data/lib/pvectl/parsers/net_config.rb +95 -0
  192. data/lib/pvectl/parsers/smart_text.rb +42 -0
  193. data/lib/pvectl/plugin_loader.rb +157 -0
  194. data/lib/pvectl/presenters/apt_package.rb +99 -0
  195. data/lib/pvectl/presenters/backup.rb +128 -0
  196. data/lib/pvectl/presenters/base.rb +283 -0
  197. data/lib/pvectl/presenters/capability.rb +104 -0
  198. data/lib/pvectl/presenters/config/context.rb +80 -0
  199. data/lib/pvectl/presenters/container.rb +574 -0
  200. data/lib/pvectl/presenters/container_operation_result.rb +109 -0
  201. data/lib/pvectl/presenters/disk.rb +184 -0
  202. data/lib/pvectl/presenters/dns_config.rb +68 -0
  203. data/lib/pvectl/presenters/hosts_file.rb +61 -0
  204. data/lib/pvectl/presenters/journal_entry.rb +20 -0
  205. data/lib/pvectl/presenters/node.rb +762 -0
  206. data/lib/pvectl/presenters/node_operation_result.rb +50 -0
  207. data/lib/pvectl/presenters/operation_result.rb +61 -0
  208. data/lib/pvectl/presenters/service.rb +76 -0
  209. data/lib/pvectl/presenters/snapshot.rb +239 -0
  210. data/lib/pvectl/presenters/snapshot_operation_result.rb +125 -0
  211. data/lib/pvectl/presenters/storage.rb +329 -0
  212. data/lib/pvectl/presenters/subscription.rb +189 -0
  213. data/lib/pvectl/presenters/syslog_entry.rb +20 -0
  214. data/lib/pvectl/presenters/task_entry.rb +69 -0
  215. data/lib/pvectl/presenters/task_log_line.rb +20 -0
  216. data/lib/pvectl/presenters/template.rb +76 -0
  217. data/lib/pvectl/presenters/time_config.rb +86 -0
  218. data/lib/pvectl/presenters/top_container.rb +112 -0
  219. data/lib/pvectl/presenters/top_node.rb +115 -0
  220. data/lib/pvectl/presenters/top_presenter.rb +59 -0
  221. data/lib/pvectl/presenters/top_vm.rb +105 -0
  222. data/lib/pvectl/presenters/vm.rb +853 -0
  223. data/lib/pvectl/presenters/vm_operation_result.rb +109 -0
  224. data/lib/pvectl/presenters/volume.rb +136 -0
  225. data/lib/pvectl/presenters/volume_operation_result.rb +58 -0
  226. data/lib/pvectl/repositories/apt.rb +93 -0
  227. data/lib/pvectl/repositories/backup.rb +186 -0
  228. data/lib/pvectl/repositories/base.rb +110 -0
  229. data/lib/pvectl/repositories/capabilities.rb +96 -0
  230. data/lib/pvectl/repositories/container.rb +503 -0
  231. data/lib/pvectl/repositories/disk.rb +87 -0
  232. data/lib/pvectl/repositories/dns.rb +54 -0
  233. data/lib/pvectl/repositories/hosts.rb +63 -0
  234. data/lib/pvectl/repositories/journal.rb +23 -0
  235. data/lib/pvectl/repositories/node.rb +537 -0
  236. data/lib/pvectl/repositories/service.rb +139 -0
  237. data/lib/pvectl/repositories/snapshot.rb +133 -0
  238. data/lib/pvectl/repositories/storage.rb +302 -0
  239. data/lib/pvectl/repositories/subscription.rb +77 -0
  240. data/lib/pvectl/repositories/syslog.rb +25 -0
  241. data/lib/pvectl/repositories/task.rb +82 -0
  242. data/lib/pvectl/repositories/task_list.rb +30 -0
  243. data/lib/pvectl/repositories/task_log.rb +31 -0
  244. data/lib/pvectl/repositories/time_config.rb +53 -0
  245. data/lib/pvectl/repositories/vm.rb +616 -0
  246. data/lib/pvectl/repositories/volume.rb +306 -0
  247. data/lib/pvectl/selectors/base.rb +201 -0
  248. data/lib/pvectl/selectors/container.rb +116 -0
  249. data/lib/pvectl/selectors/disk.rb +59 -0
  250. data/lib/pvectl/selectors/vm.rb +116 -0
  251. data/lib/pvectl/selectors/volume.rb +59 -0
  252. data/lib/pvectl/services/backup.rb +209 -0
  253. data/lib/pvectl/services/clone_container.rb +260 -0
  254. data/lib/pvectl/services/clone_vm.rb +265 -0
  255. data/lib/pvectl/services/cloudinit.rb +96 -0
  256. data/lib/pvectl/services/console.rb +152 -0
  257. data/lib/pvectl/services/container_lifecycle.rb +124 -0
  258. data/lib/pvectl/services/create_container.rb +179 -0
  259. data/lib/pvectl/services/create_vm.rb +191 -0
  260. data/lib/pvectl/services/edit_container.rb +125 -0
  261. data/lib/pvectl/services/edit_dns.rb +159 -0
  262. data/lib/pvectl/services/edit_hosts.rb +78 -0
  263. data/lib/pvectl/services/edit_node.rb +147 -0
  264. data/lib/pvectl/services/edit_vm.rb +125 -0
  265. data/lib/pvectl/services/edit_volume.rb +224 -0
  266. data/lib/pvectl/services/get/resource_service.rb +98 -0
  267. data/lib/pvectl/services/move_disk.rb +132 -0
  268. data/lib/pvectl/services/pull_config.rb +94 -0
  269. data/lib/pvectl/services/push_config.rb +524 -0
  270. data/lib/pvectl/services/resize_volume.rb +253 -0
  271. data/lib/pvectl/services/resource_delete.rb +169 -0
  272. data/lib/pvectl/services/resource_migration.rb +170 -0
  273. data/lib/pvectl/services/sendkey.rb +108 -0
  274. data/lib/pvectl/services/service_lifecycle.rb +89 -0
  275. data/lib/pvectl/services/set_container.rb +128 -0
  276. data/lib/pvectl/services/set_node.rb +236 -0
  277. data/lib/pvectl/services/set_vm.rb +128 -0
  278. data/lib/pvectl/services/set_volume.rb +126 -0
  279. data/lib/pvectl/services/snapshot.rb +261 -0
  280. data/lib/pvectl/services/task_listing.rb +75 -0
  281. data/lib/pvectl/services/unlink_disk.rb +86 -0
  282. data/lib/pvectl/services/vm_lifecycle.rb +124 -0
  283. data/lib/pvectl/services/wakeonlan.rb +79 -0
  284. data/lib/pvectl/utils/resource_resolver.rb +80 -0
  285. data/lib/pvectl/version.rb +13 -0
  286. data/lib/pvectl/wizards/create_container.rb +105 -0
  287. data/lib/pvectl/wizards/create_vm.rb +98 -0
  288. data/lib/pvectl.rb +439 -0
  289. data/sig/external/gli.rbs +16 -0
  290. data/sig/external/proxmox_api.rbs +10 -0
  291. data/sig/pvectl/argv_preprocessor.rbs +53 -0
  292. data/sig/pvectl/cli.rbs +26 -0
  293. data/sig/pvectl/commands/apt.rbs +47 -0
  294. data/sig/pvectl/commands/clone_container.rbs +31 -0
  295. data/sig/pvectl/commands/clone_vm.rbs +33 -0
  296. data/sig/pvectl/commands/cloudinit/command.rbs +13 -0
  297. data/sig/pvectl/commands/cloudinit/dump.rbs +13 -0
  298. data/sig/pvectl/commands/cloudinit/pending.rbs +17 -0
  299. data/sig/pvectl/commands/cloudinit/regenerate.rbs +11 -0
  300. data/sig/pvectl/commands/config/command.rbs +9 -0
  301. data/sig/pvectl/commands/config/get_contexts.rbs +11 -0
  302. data/sig/pvectl/commands/config/set_cluster.rbs +11 -0
  303. data/sig/pvectl/commands/config/set_context.rbs +15 -0
  304. data/sig/pvectl/commands/config/set_credentials.rbs +15 -0
  305. data/sig/pvectl/commands/config/use_context.rbs +11 -0
  306. data/sig/pvectl/commands/config/view.rbs +11 -0
  307. data/sig/pvectl/commands/console.rbs +9 -0
  308. data/sig/pvectl/commands/console_ct.rbs +27 -0
  309. data/sig/pvectl/commands/console_vm.rbs +27 -0
  310. data/sig/pvectl/commands/container_lifecycle_command.rbs +25 -0
  311. data/sig/pvectl/commands/create_backup.rbs +29 -0
  312. data/sig/pvectl/commands/create_container.rbs +30 -0
  313. data/sig/pvectl/commands/create_resource_command.rbs +53 -0
  314. data/sig/pvectl/commands/create_snapshot.rbs +35 -0
  315. data/sig/pvectl/commands/create_vm.rbs +30 -0
  316. data/sig/pvectl/commands/delete_backup.rbs +25 -0
  317. data/sig/pvectl/commands/delete_command.rbs +45 -0
  318. data/sig/pvectl/commands/delete_container.rbs +11 -0
  319. data/sig/pvectl/commands/delete_snapshot.rbs +35 -0
  320. data/sig/pvectl/commands/delete_vm.rbs +13 -0
  321. data/sig/pvectl/commands/describe/command.rbs +27 -0
  322. data/sig/pvectl/commands/edit_container.rbs +17 -0
  323. data/sig/pvectl/commands/edit_dns.rbs +25 -0
  324. data/sig/pvectl/commands/edit_hosts.rbs +23 -0
  325. data/sig/pvectl/commands/edit_node.rbs +17 -0
  326. data/sig/pvectl/commands/edit_resource_command.rbs +35 -0
  327. data/sig/pvectl/commands/edit_vm.rbs +19 -0
  328. data/sig/pvectl/commands/edit_volume.rbs +24 -0
  329. data/sig/pvectl/commands/feature_command.rbs +43 -0
  330. data/sig/pvectl/commands/feature_container.rbs +10 -0
  331. data/sig/pvectl/commands/feature_vm.rbs +12 -0
  332. data/sig/pvectl/commands/get/command.rbs +42 -0
  333. data/sig/pvectl/commands/get/handlers/backups.rbs +23 -0
  334. data/sig/pvectl/commands/get/handlers/capabilities.rbs +29 -0
  335. data/sig/pvectl/commands/get/handlers/containers.rbs +35 -0
  336. data/sig/pvectl/commands/get/handlers/disks.rbs +27 -0
  337. data/sig/pvectl/commands/get/handlers/dns.rbs +25 -0
  338. data/sig/pvectl/commands/get/handlers/hosts.rbs +25 -0
  339. data/sig/pvectl/commands/get/handlers/nodes.rbs +33 -0
  340. data/sig/pvectl/commands/get/handlers/services.rbs +23 -0
  341. data/sig/pvectl/commands/get/handlers/snapshots.rbs +27 -0
  342. data/sig/pvectl/commands/get/handlers/storage.rbs +25 -0
  343. data/sig/pvectl/commands/get/handlers/subscription.rbs +25 -0
  344. data/sig/pvectl/commands/get/handlers/tasks.rbs +28 -0
  345. data/sig/pvectl/commands/get/handlers/templates.rbs +35 -0
  346. data/sig/pvectl/commands/get/handlers/time.rbs +29 -0
  347. data/sig/pvectl/commands/get/handlers/vms.rbs +35 -0
  348. data/sig/pvectl/commands/get/handlers/volume.rbs +27 -0
  349. data/sig/pvectl/commands/get/resource_handler.rbs +13 -0
  350. data/sig/pvectl/commands/get/resource_registry.rbs +8 -0
  351. data/sig/pvectl/commands/get/watch_loop.rbs +33 -0
  352. data/sig/pvectl/commands/irreversible_command.rbs +32 -0
  353. data/sig/pvectl/commands/logs/command.rbs +35 -0
  354. data/sig/pvectl/commands/logs/handlers/journal.rbs +21 -0
  355. data/sig/pvectl/commands/logs/handlers/syslog.rbs +21 -0
  356. data/sig/pvectl/commands/logs/handlers/task_detail.rbs +21 -0
  357. data/sig/pvectl/commands/logs/handlers/task_logs.rbs +35 -0
  358. data/sig/pvectl/commands/logs/resource_handler.rbs +11 -0
  359. data/sig/pvectl/commands/logs/resource_registry.rbs +8 -0
  360. data/sig/pvectl/commands/migrate_command.rbs +45 -0
  361. data/sig/pvectl/commands/migrate_container.rbs +11 -0
  362. data/sig/pvectl/commands/migrate_vm.rbs +13 -0
  363. data/sig/pvectl/commands/move_disk_command.rbs +43 -0
  364. data/sig/pvectl/commands/move_disk_container.rbs +11 -0
  365. data/sig/pvectl/commands/move_disk_vm.rbs +13 -0
  366. data/sig/pvectl/commands/ping.rbs +39 -0
  367. data/sig/pvectl/commands/pull.rbs +33 -0
  368. data/sig/pvectl/commands/push.rbs +32 -0
  369. data/sig/pvectl/commands/reset.rbs +11 -0
  370. data/sig/pvectl/commands/resource_lifecycle_command.rbs +55 -0
  371. data/sig/pvectl/commands/resource_registry.rbs +19 -0
  372. data/sig/pvectl/commands/restart.rbs +11 -0
  373. data/sig/pvectl/commands/restart_container.rbs +9 -0
  374. data/sig/pvectl/commands/restore_backup.rbs +27 -0
  375. data/sig/pvectl/commands/resume.rbs +11 -0
  376. data/sig/pvectl/commands/rollback_snapshot.rbs +31 -0
  377. data/sig/pvectl/commands/sendkey_vm.rbs +25 -0
  378. data/sig/pvectl/commands/service.rbs +38 -0
  379. data/sig/pvectl/commands/set_container.rbs +13 -0
  380. data/sig/pvectl/commands/set_node.rbs +13 -0
  381. data/sig/pvectl/commands/set_resource_command.rbs +25 -0
  382. data/sig/pvectl/commands/set_vm.rbs +15 -0
  383. data/sig/pvectl/commands/set_volume.rbs +24 -0
  384. data/sig/pvectl/commands/shared_config_parsers.rbs +19 -0
  385. data/sig/pvectl/commands/shared_flags.rbs +10 -0
  386. data/sig/pvectl/commands/shutdown.rbs +11 -0
  387. data/sig/pvectl/commands/shutdown_container.rbs +9 -0
  388. data/sig/pvectl/commands/start.rbs +11 -0
  389. data/sig/pvectl/commands/start_container.rbs +9 -0
  390. data/sig/pvectl/commands/stop.rbs +11 -0
  391. data/sig/pvectl/commands/stop_container.rbs +9 -0
  392. data/sig/pvectl/commands/suspend.rbs +11 -0
  393. data/sig/pvectl/commands/template_command.rbs +21 -0
  394. data/sig/pvectl/commands/template_container.rbs +10 -0
  395. data/sig/pvectl/commands/template_vm.rbs +12 -0
  396. data/sig/pvectl/commands/top/command.rbs +31 -0
  397. data/sig/pvectl/commands/top/handlers/containers.rbs +21 -0
  398. data/sig/pvectl/commands/top/handlers/nodes.rbs +21 -0
  399. data/sig/pvectl/commands/top/handlers/vms.rbs +21 -0
  400. data/sig/pvectl/commands/top/resource_handler.rbs +11 -0
  401. data/sig/pvectl/commands/top/resource_registry.rbs +8 -0
  402. data/sig/pvectl/commands/unlink_disk_vm.rbs +27 -0
  403. data/sig/pvectl/commands/vm_lifecycle_command.rbs +25 -0
  404. data/sig/pvectl/commands/wakeonlan_node.rbs +21 -0
  405. data/sig/pvectl/config/errors.rbs +24 -0
  406. data/sig/pvectl/config/models/cluster.rbs +39 -0
  407. data/sig/pvectl/config/models/context.rbs +23 -0
  408. data/sig/pvectl/config/models/resolved_config.rbs +51 -0
  409. data/sig/pvectl/config/models/user.rbs +31 -0
  410. data/sig/pvectl/config/provider.rbs +40 -0
  411. data/sig/pvectl/config/service.rbs +65 -0
  412. data/sig/pvectl/config/store.rbs +14 -0
  413. data/sig/pvectl/config/wizard.rbs +48 -0
  414. data/sig/pvectl/config_serializer.rbs +121 -0
  415. data/sig/pvectl/connection/retry_handler.rbs +31 -0
  416. data/sig/pvectl/connection.rbs +35 -0
  417. data/sig/pvectl/console/terminal_session.rbs +63 -0
  418. data/sig/pvectl/editor_session.rbs +33 -0
  419. data/sig/pvectl/exit_codes.rbs +19 -0
  420. data/sig/pvectl/formatters/base.rbs +13 -0
  421. data/sig/pvectl/formatters/color_support.rbs +13 -0
  422. data/sig/pvectl/formatters/json.rbs +7 -0
  423. data/sig/pvectl/formatters/output_helper.rbs +9 -0
  424. data/sig/pvectl/formatters/registry.rbs +13 -0
  425. data/sig/pvectl/formatters/table.rbs +25 -0
  426. data/sig/pvectl/formatters/wide.rbs +15 -0
  427. data/sig/pvectl/formatters/yaml.rbs +7 -0
  428. data/sig/pvectl/manifest_serializer.rbs +18 -0
  429. data/sig/pvectl/models/apt_package.rbs +26 -0
  430. data/sig/pvectl/models/backup.rbs +31 -0
  431. data/sig/pvectl/models/base.rbs +11 -0
  432. data/sig/pvectl/models/capability.rbs +16 -0
  433. data/sig/pvectl/models/container.rbs +44 -0
  434. data/sig/pvectl/models/container_operation_result.rbs +9 -0
  435. data/sig/pvectl/models/dns_config.rbs +15 -0
  436. data/sig/pvectl/models/hosts_file.rbs +13 -0
  437. data/sig/pvectl/models/journal_entry.rbs +10 -0
  438. data/sig/pvectl/models/network_interface.rbs +20 -0
  439. data/sig/pvectl/models/node.rbs +47 -0
  440. data/sig/pvectl/models/node_operation_result.rbs +12 -0
  441. data/sig/pvectl/models/operation_result.rbs +21 -0
  442. data/sig/pvectl/models/physical_disk.rbs +35 -0
  443. data/sig/pvectl/models/service.rbs +18 -0
  444. data/sig/pvectl/models/snapshot.rbs +21 -0
  445. data/sig/pvectl/models/snapshot_description.rbs +18 -0
  446. data/sig/pvectl/models/storage.rbs +39 -0
  447. data/sig/pvectl/models/subscription.rbs +24 -0
  448. data/sig/pvectl/models/syslog_entry.rbs +10 -0
  449. data/sig/pvectl/models/task.rbs +22 -0
  450. data/sig/pvectl/models/task_entry.rbs +24 -0
  451. data/sig/pvectl/models/task_log_line.rbs +10 -0
  452. data/sig/pvectl/models/time_config.rbs +12 -0
  453. data/sig/pvectl/models/vm.rbs +32 -0
  454. data/sig/pvectl/models/vm_operation_result.rbs +9 -0
  455. data/sig/pvectl/models/volume.rbs +29 -0
  456. data/sig/pvectl/models/volume_operation_result.rbs +9 -0
  457. data/sig/pvectl/parsers/cloud_init_config.rbs +15 -0
  458. data/sig/pvectl/parsers/disk_config.rbs +19 -0
  459. data/sig/pvectl/parsers/lxc_mount_config.rbs +19 -0
  460. data/sig/pvectl/parsers/lxc_net_config.rbs +19 -0
  461. data/sig/pvectl/parsers/net_config.rbs +19 -0
  462. data/sig/pvectl/parsers/smart_text.rbs +7 -0
  463. data/sig/pvectl/plugin_loader.rbs +25 -0
  464. data/sig/pvectl/presenters/apt_package.rbs +19 -0
  465. data/sig/pvectl/presenters/backup.rbs +25 -0
  466. data/sig/pvectl/presenters/base.rbs +41 -0
  467. data/sig/pvectl/presenters/capability.rbs +19 -0
  468. data/sig/pvectl/presenters/config/context.rbs +17 -0
  469. data/sig/pvectl/presenters/container.rbs +78 -0
  470. data/sig/pvectl/presenters/container_operation_result.rbs +19 -0
  471. data/sig/pvectl/presenters/disk.rbs +31 -0
  472. data/sig/pvectl/presenters/dns_config.rbs +13 -0
  473. data/sig/pvectl/presenters/hosts_file.rbs +13 -0
  474. data/sig/pvectl/presenters/journal_entry.rbs +11 -0
  475. data/sig/pvectl/presenters/node.rbs +118 -0
  476. data/sig/pvectl/presenters/node_operation_result.rbs +11 -0
  477. data/sig/pvectl/presenters/operation_result.rbs +17 -0
  478. data/sig/pvectl/presenters/service.rbs +15 -0
  479. data/sig/pvectl/presenters/snapshot.rbs +35 -0
  480. data/sig/pvectl/presenters/snapshot_operation_result.rbs +27 -0
  481. data/sig/pvectl/presenters/storage.rbs +59 -0
  482. data/sig/pvectl/presenters/subscription.rbs +36 -0
  483. data/sig/pvectl/presenters/syslog_entry.rbs +11 -0
  484. data/sig/pvectl/presenters/task_entry.rbs +21 -0
  485. data/sig/pvectl/presenters/task_log_line.rbs +11 -0
  486. data/sig/pvectl/presenters/template.rbs +15 -0
  487. data/sig/pvectl/presenters/time_config.rbs +19 -0
  488. data/sig/pvectl/presenters/top_container.rbs +17 -0
  489. data/sig/pvectl/presenters/top_node.rbs +17 -0
  490. data/sig/pvectl/presenters/top_presenter.rbs +13 -0
  491. data/sig/pvectl/presenters/top_vm.rbs +17 -0
  492. data/sig/pvectl/presenters/vm.rbs +91 -0
  493. data/sig/pvectl/presenters/vm_operation_result.rbs +19 -0
  494. data/sig/pvectl/presenters/volume.rbs +23 -0
  495. data/sig/pvectl/presenters/volume_operation_result.rbs +11 -0
  496. data/sig/pvectl/repositories/apt.rbs +17 -0
  497. data/sig/pvectl/repositories/backup.rbs +27 -0
  498. data/sig/pvectl/repositories/base.rbs +23 -0
  499. data/sig/pvectl/repositories/capabilities.rbs +20 -0
  500. data/sig/pvectl/repositories/container.rbs +63 -0
  501. data/sig/pvectl/repositories/disk.rbs +17 -0
  502. data/sig/pvectl/repositories/dns.rbs +13 -0
  503. data/sig/pvectl/repositories/hosts.rbs +13 -0
  504. data/sig/pvectl/repositories/journal.rbs +7 -0
  505. data/sig/pvectl/repositories/node.rbs +68 -0
  506. data/sig/pvectl/repositories/service.rbs +27 -0
  507. data/sig/pvectl/repositories/snapshot.rbs +19 -0
  508. data/sig/pvectl/repositories/storage.rbs +37 -0
  509. data/sig/pvectl/repositories/subscription.rbs +17 -0
  510. data/sig/pvectl/repositories/syslog.rbs +7 -0
  511. data/sig/pvectl/repositories/task.rbs +19 -0
  512. data/sig/pvectl/repositories/task_list.rbs +7 -0
  513. data/sig/pvectl/repositories/task_log.rbs +11 -0
  514. data/sig/pvectl/repositories/time_config.rbs +13 -0
  515. data/sig/pvectl/repositories/vm.rbs +85 -0
  516. data/sig/pvectl/repositories/volume.rbs +43 -0
  517. data/sig/pvectl/selectors/base.rbs +37 -0
  518. data/sig/pvectl/selectors/container.rbs +19 -0
  519. data/sig/pvectl/selectors/disk.rbs +13 -0
  520. data/sig/pvectl/selectors/vm.rbs +19 -0
  521. data/sig/pvectl/selectors/volume.rbs +13 -0
  522. data/sig/pvectl/services/backup.rbs +27 -0
  523. data/sig/pvectl/services/clone_container.rbs +35 -0
  524. data/sig/pvectl/services/clone_vm.rbs +35 -0
  525. data/sig/pvectl/services/cloudinit.rbs +19 -0
  526. data/sig/pvectl/services/console.rbs +23 -0
  527. data/sig/pvectl/services/container_lifecycle.rbs +26 -0
  528. data/sig/pvectl/services/create_container.rbs +64 -0
  529. data/sig/pvectl/services/create_vm.rbs +72 -0
  530. data/sig/pvectl/services/edit_container.rbs +17 -0
  531. data/sig/pvectl/services/edit_dns.rbs +23 -0
  532. data/sig/pvectl/services/edit_hosts.rbs +13 -0
  533. data/sig/pvectl/services/edit_node.rbs +21 -0
  534. data/sig/pvectl/services/edit_vm.rbs +17 -0
  535. data/sig/pvectl/services/edit_volume.rbs +18 -0
  536. data/sig/pvectl/services/get/resource_service.rbs +23 -0
  537. data/sig/pvectl/services/move_disk.rbs +21 -0
  538. data/sig/pvectl/services/pull_config.rbs +18 -0
  539. data/sig/pvectl/services/push_config.rbs +37 -0
  540. data/sig/pvectl/services/resize_volume.rbs +47 -0
  541. data/sig/pvectl/services/resource_delete.rbs +27 -0
  542. data/sig/pvectl/services/resource_migration.rbs +29 -0
  543. data/sig/pvectl/services/sendkey.rbs +19 -0
  544. data/sig/pvectl/services/service_lifecycle.rbs +17 -0
  545. data/sig/pvectl/services/set_container.rbs +14 -0
  546. data/sig/pvectl/services/set_node.rbs +23 -0
  547. data/sig/pvectl/services/set_vm.rbs +14 -0
  548. data/sig/pvectl/services/set_volume.rbs +12 -0
  549. data/sig/pvectl/services/snapshot.rbs +35 -0
  550. data/sig/pvectl/services/task_listing.rbs +13 -0
  551. data/sig/pvectl/services/unlink_disk.rbs +17 -0
  552. data/sig/pvectl/services/vm_lifecycle.rbs +26 -0
  553. data/sig/pvectl/services/wakeonlan.rbs +17 -0
  554. data/sig/pvectl/utils/resource_resolver.rbs +17 -0
  555. data/sig/pvectl/wizards/create_container.rbs +21 -0
  556. data/sig/pvectl/wizards/create_vm.rbs +21 -0
  557. data/sig/pvectl.rbs +9 -0
  558. metadata +675 -0
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Pvectl
6
+ # Wraps ConfigSerializer output with a kubectl-like manifest envelope
7
+ # (apiVersion, kind, metadata, spec). Handles bidirectional conversion
8
+ # between YAML manifest files and internal config representations.
9
+ module ManifestSerializer
10
+ API_VERSION = "pvectl/v1"
11
+
12
+ KINDS = {
13
+ vm: "VirtualMachine",
14
+ container: "Container"
15
+ }.freeze
16
+
17
+ KINDS_REVERSE = KINDS.invert.transform_keys(&:to_s).freeze
18
+
19
+ class << self
20
+ # Builds a YAML manifest string from nested config and metadata.
21
+ #
22
+ # @param nested_config [Hash] nested config from ConfigSerializer.to_nested
23
+ # @param type [Symbol] :vm or :container
24
+ # @param metadata [Hash] resource metadata (vmid, name, node, status, tags)
25
+ # @return [String] YAML manifest string
26
+ def to_yaml(nested_config, type:, metadata:)
27
+ manifest = {
28
+ "apiVersion" => API_VERSION,
29
+ "kind" => KINDS.fetch(type),
30
+ "metadata" => build_metadata(metadata),
31
+ "spec" => stringify_keys_deep(nested_config)
32
+ }
33
+
34
+ YAML.dump(manifest)
35
+ end
36
+
37
+ # Parses a YAML manifest string into type, metadata, and spec.
38
+ #
39
+ # @param yaml_string [String] YAML manifest
40
+ # @return [Hash] { type: Symbol, metadata: Hash, spec: Hash }
41
+ def from_yaml(yaml_string)
42
+ parsed = YAML.safe_load(yaml_string)
43
+ type = KINDS_REVERSE[parsed["kind"]]
44
+
45
+ {
46
+ type: type,
47
+ metadata: symbolize_metadata(parsed["metadata"] || {}),
48
+ spec: symbolize_keys_deep(parsed["spec"] || {})
49
+ }
50
+ end
51
+
52
+ # Validates manifest structure (envelope only, not spec content).
53
+ #
54
+ # @param yaml_string [String] YAML manifest
55
+ # @return [Array<String>] error messages (empty if valid)
56
+ def validate(yaml_string)
57
+ errors = []
58
+
59
+ begin
60
+ parsed = YAML.safe_load(yaml_string)
61
+ rescue Psych::SyntaxError => e
62
+ return ["YAML syntax error: #{e.message}"]
63
+ end
64
+
65
+ unless parsed.is_a?(Hash)
66
+ return ["Invalid manifest: expected a YAML mapping"]
67
+ end
68
+
69
+ unless parsed["apiVersion"]
70
+ errors << "Missing required field 'apiVersion'"
71
+ end
72
+
73
+ if parsed["apiVersion"] && parsed["apiVersion"] != API_VERSION
74
+ errors << "Unsupported apiVersion '#{parsed["apiVersion"]}'. Expected: #{API_VERSION}"
75
+ end
76
+
77
+ errors << "Missing required field 'kind'" unless parsed["kind"]
78
+
79
+ if parsed["kind"] && !KINDS_REVERSE.key?(parsed["kind"])
80
+ errors << "Unknown kind '#{parsed["kind"]}'. Valid: #{KINDS.values.join(', ')}"
81
+ end
82
+
83
+ metadata = parsed["metadata"]
84
+ if metadata.nil? || !metadata.is_a?(Hash)
85
+ errors << "Missing required field 'metadata'"
86
+ end
87
+
88
+ errors
89
+ end
90
+
91
+ private
92
+
93
+ # Builds string-keyed metadata hash from symbol-keyed input.
94
+ #
95
+ # @param metadata [Hash] symbol-keyed metadata
96
+ # @return [Hash] string-keyed metadata for YAML output
97
+ def build_metadata(metadata)
98
+ result = {}
99
+ result["vmid"] = metadata[:vmid] if metadata[:vmid]
100
+ result["name"] = metadata[:name] if metadata[:name]
101
+ result["node"] = metadata[:node] if metadata[:node]
102
+ result["status"] = metadata[:status] if metadata[:status]
103
+ result["tags"] = metadata[:tags] if metadata[:tags]
104
+ result
105
+ end
106
+
107
+ # Recursively converts symbol keys to string keys.
108
+ #
109
+ # @param hash [Hash] symbol-keyed hash
110
+ # @return [Hash] string-keyed hash
111
+ def stringify_keys_deep(hash)
112
+ hash.transform_keys(&:to_s).transform_values do |v|
113
+ v.is_a?(Hash) ? stringify_keys_deep(v) : v
114
+ end
115
+ end
116
+
117
+ # Converts string-keyed metadata to symbol-keyed hash.
118
+ #
119
+ # @param hash [Hash] string-keyed metadata from YAML
120
+ # @return [Hash] symbol-keyed metadata
121
+ def symbolize_metadata(hash)
122
+ result = {}
123
+ result[:vmid] = hash["vmid"] if hash["vmid"]
124
+ result[:name] = hash["name"] if hash["name"]
125
+ result[:node] = hash["node"] if hash["node"]
126
+ result[:status] = hash["status"] if hash["status"]
127
+ result[:tags] = hash["tags"] if hash["tags"]
128
+ result
129
+ end
130
+
131
+ # Recursively converts string keys to symbol keys.
132
+ #
133
+ # @param hash [Hash] string-keyed hash from YAML
134
+ # @return [Hash] symbol-keyed hash
135
+ def symbolize_keys_deep(hash)
136
+ hash.to_h do |k, v|
137
+ [k.to_sym, v.is_a?(Hash) ? symbolize_keys_deep(v) : v]
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Represents an APT package on a Proxmox node.
6
+ #
7
+ # Single model serves both pending updates (`/apt/update`) and installed
8
+ # package versions (`/apt/versions`). Some attributes only apply to one
9
+ # API: `notify_status` to pending updates, `current_state`,
10
+ # `manager_version`, `running_kernel` to versions.
11
+ #
12
+ # @example Creating a pending update instance
13
+ # pkg = AptPackage.new(
14
+ # Package: "pve-manager",
15
+ # Version: "8.2.4-1",
16
+ # OldVersion: "8.2.3-1",
17
+ # Origin: "Proxmox",
18
+ # node: "pve1"
19
+ # )
20
+ # pkg.package # => "pve-manager"
21
+ # pkg.upgrade? # => true
22
+ #
23
+ # @see Pvectl::Repositories::Apt Repository that creates these instances
24
+ #
25
+ class AptPackage < Base
26
+ # @return [String, nil] package name
27
+ attr_reader :package
28
+
29
+ # @return [String, nil] short package title
30
+ attr_reader :title
31
+
32
+ # @return [String, nil] available / target version
33
+ attr_reader :version
34
+
35
+ # @return [String, nil] currently installed version
36
+ attr_reader :old_version
37
+
38
+ # @return [String, nil] package origin (e.g., "Proxmox", "Debian")
39
+ attr_reader :origin
40
+
41
+ # @return [String, nil] package section
42
+ attr_reader :section
43
+
44
+ # @return [String, nil] package priority
45
+ attr_reader :priority
46
+
47
+ # @return [String, nil] architecture (amd64, arm64, all, ...)
48
+ attr_reader :arch
49
+
50
+ # @return [String, nil] package description
51
+ attr_reader :description
52
+
53
+ # @return [String, nil] notify status (pending updates only)
54
+ attr_reader :notify_status
55
+
56
+ # @return [String, nil] current installed state (versions only)
57
+ attr_reader :current_state
58
+
59
+ # @return [String, nil] pve-manager API server version (versions only)
60
+ attr_reader :manager_version
61
+
62
+ # @return [String, nil] running kernel (proxmox-ve package, versions only)
63
+ attr_reader :running_kernel
64
+
65
+ # @return [String, nil] node name this package belongs to
66
+ attr_reader :node
67
+
68
+ # Creates a new AptPackage instance.
69
+ #
70
+ # Accepts Proxmox API capitalized keys (`Package`, `OldVersion`, ...) as
71
+ # well as snake_case / dasherized variants. Indifferent access on keys.
72
+ #
73
+ # @param attrs [Hash] package attributes from API
74
+ def initialize(attrs = {})
75
+ super
76
+ @package = attributes[:Package] || attributes[:package]
77
+ @title = attributes[:Title] || attributes[:title]
78
+ @version = attributes[:Version] || attributes[:version]
79
+ @old_version = attributes[:OldVersion] || attributes[:old_version] || attributes[:"old-version"]
80
+ @origin = attributes[:Origin] || attributes[:origin]
81
+ @section = attributes[:Section] || attributes[:section]
82
+ @priority = attributes[:Priority] || attributes[:priority]
83
+ @arch = attributes[:Arch] || attributes[:arch]
84
+ @description = attributes[:Description] || attributes[:description]
85
+ @notify_status = attributes[:NotifyStatus] || attributes[:notify_status] || attributes[:"notify-status"]
86
+ @current_state = attributes[:CurrentState] || attributes[:current_state] || attributes[:"current-state"]
87
+ @manager_version = attributes[:ManagerVersion] || attributes[:manager_version] || attributes[:"manager-version"]
88
+ @running_kernel = attributes[:RunningKernel] || attributes[:running_kernel] || attributes[:"running-kernel"]
89
+ @node = attributes[:node]
90
+ end
91
+
92
+ # Returns true if a different version is available.
93
+ #
94
+ # @return [Boolean] true if old_version and version are both set and differ
95
+ def upgrade?
96
+ !old_version.nil? && !version.nil? && old_version != version
97
+ end
98
+
99
+ # Returns the installed package state, defaults to "Installed" when not provided.
100
+ #
101
+ # @return [String] installed state
102
+ def installed_state
103
+ current_state || "Installed"
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Represents a VM/container backup in Proxmox.
6
+ #
7
+ # A backup is a full copy of a VM or container stored on a storage backend.
8
+ # Backups can be created via vzdump and restored to create new VMs/containers.
9
+ #
10
+ # @example Creating a backup model
11
+ # backup = Backup.new(
12
+ # volid: "local:backup/vzdump-qemu-100-2024_01_15-10_30_00.vma.zst",
13
+ # vmid: 100,
14
+ # size: 1610612736,
15
+ # ctime: 1705315800,
16
+ # format: "vma"
17
+ # )
18
+ # backup.human_size # => "1.5 GiB"
19
+ # backup.vm? # => true
20
+ #
21
+ # @see Pvectl::Models::Base Base model class
22
+ #
23
+ class Backup < Base
24
+ # @return [String] full volume identifier (e.g., "local:backup/vzdump-qemu-100-xxx.vma.zst")
25
+ attr_reader :volid
26
+
27
+ # @return [Integer] VM/container ID
28
+ attr_reader :vmid
29
+
30
+ # @return [String, nil] node name where backup is stored
31
+ attr_reader :node
32
+
33
+ # @return [String, nil] storage name (extracted from volid)
34
+ attr_reader :storage
35
+
36
+ # @return [Symbol, nil] resource type (:qemu or :lxc)
37
+ attr_reader :resource_type
38
+
39
+ # @return [String, nil] backup format ("vma", "tar")
40
+ attr_reader :format
41
+
42
+ # @return [Integer, nil] backup size in bytes
43
+ attr_reader :size
44
+
45
+ # @return [Integer, nil] Unix timestamp when backup was created
46
+ attr_reader :ctime
47
+
48
+ # @return [String, nil] optional notes/description
49
+ attr_reader :notes
50
+
51
+ # @return [Boolean] whether backup is protected from deletion
52
+ attr_reader :protected
53
+
54
+ # Creates a new Backup instance.
55
+ #
56
+ # @param attrs [Hash] backup attributes
57
+ # @option attrs [String] :volid volume identifier
58
+ # @option attrs [Integer] :vmid VM/container ID
59
+ # @option attrs [String] :node node name
60
+ # @option attrs [String] :storage storage name (auto-detected from volid if not provided)
61
+ # @option attrs [Symbol] :resource_type :qemu or :lxc (auto-detected from volid if not provided)
62
+ # @option attrs [String] :format backup format
63
+ # @option attrs [Integer] :size size in bytes
64
+ # @option attrs [Integer] :ctime Unix timestamp of creation
65
+ # @option attrs [String] :notes description
66
+ # @option attrs [Boolean] :protected protection status
67
+ def initialize(attrs = {})
68
+ super
69
+ @volid = attributes[:volid]
70
+ @vmid = attributes[:vmid]
71
+ @node = attributes[:node]
72
+ @storage = attributes[:storage] || extract_storage
73
+ @resource_type = attributes[:resource_type] || detect_resource_type
74
+ @format = attributes[:format]
75
+ @size = attributes[:size]
76
+ @ctime = attributes[:ctime]
77
+ @notes = attributes[:notes]
78
+ @protected = attributes[:protected] || false
79
+ end
80
+
81
+ # Returns the backup creation time as a Time object.
82
+ #
83
+ # @return [Time, nil] creation time or nil if ctime is not set
84
+ def created_at
85
+ return nil if ctime.nil?
86
+
87
+ Time.at(ctime)
88
+ end
89
+
90
+ # Checks if the backup is for a VM (QEMU).
91
+ #
92
+ # @return [Boolean] true if resource_type is :qemu
93
+ def vm?
94
+ resource_type == :qemu
95
+ end
96
+
97
+ # Checks if the backup is for a container (LXC).
98
+ #
99
+ # @return [Boolean] true if resource_type is :lxc
100
+ def container?
101
+ resource_type == :lxc
102
+ end
103
+
104
+ # Extracts the filename from the volume identifier.
105
+ #
106
+ # @return [String, nil] filename or nil if volid is not set
107
+ def filename
108
+ return nil if volid.nil?
109
+
110
+ volid.split("/").last
111
+ end
112
+
113
+ # Returns human-readable size.
114
+ #
115
+ # @return [String, nil] formatted size (e.g., "1.5 GiB") or nil if size is not set
116
+ def human_size
117
+ return nil if size.nil?
118
+
119
+ format_bytes(size)
120
+ end
121
+
122
+ # Checks if the backup is protected from deletion.
123
+ #
124
+ # @return [Boolean] true if protected
125
+ def protected?
126
+ @protected == true
127
+ end
128
+
129
+ private
130
+
131
+ # Extracts storage name from volid.
132
+ #
133
+ # @return [String, nil] storage name
134
+ def extract_storage
135
+ return nil if volid.nil?
136
+
137
+ volid.split(":").first
138
+ end
139
+
140
+ # Detects resource type from volid pattern.
141
+ #
142
+ # @return [Symbol, nil] :qemu, :lxc, or nil
143
+ def detect_resource_type
144
+ return nil if volid.nil?
145
+ return :qemu if volid.include?("vzdump-qemu")
146
+ return :lxc if volid.include?("vzdump-lxc")
147
+
148
+ nil
149
+ end
150
+
151
+ # Formats bytes into human-readable units.
152
+ #
153
+ # @param bytes [Integer] size in bytes
154
+ # @return [String] formatted size
155
+ def format_bytes(bytes)
156
+ units = ["B", "KiB", "MiB", "GiB", "TiB"]
157
+ unit_index = 0
158
+ value = bytes.to_f
159
+
160
+ while value >= 1024 && unit_index < units.size - 1
161
+ value /= 1024
162
+ unit_index += 1
163
+ end
164
+
165
+ if unit_index == 0
166
+ "#{value.to_i} #{units[unit_index]}"
167
+ else
168
+ "#{Kernel.format('%.1f', value)} #{units[unit_index]}"
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Abstract base class for domain models.
6
+ #
7
+ # Provides common initialization from hash attributes.
8
+ # All models are immutable - only getters, no setters.
9
+ #
10
+ # Subclasses store domain data and contain domain logic,
11
+ # but do not fetch data themselves (that's the Repository's job).
12
+ #
13
+ # @abstract Subclass and add attr_readers for domain attributes.
14
+ #
15
+ # @example Implementing a model
16
+ # class Vm < Base
17
+ # attr_reader :vmid, :name, :status
18
+ #
19
+ # def initialize(attributes = {})
20
+ # super
21
+ # @vmid = attributes[:vmid]
22
+ # @name = attributes[:name]
23
+ # @status = attributes[:status]
24
+ # end
25
+ #
26
+ # def running?
27
+ # status == "running"
28
+ # end
29
+ # end
30
+ #
31
+ # @see Pvectl::Repositories::Base Repository creates model instances
32
+ #
33
+ class Base
34
+ # Creates model from attributes hash.
35
+ #
36
+ # Converts string keys to symbols for consistent access.
37
+ #
38
+ # @param attributes [Hash] attribute key-value pairs
39
+ def initialize(attributes = {})
40
+ @attributes = (attributes || {}).transform_keys(&:to_sym)
41
+ end
42
+
43
+ protected
44
+
45
+ # @return [Hash] the raw attributes hash
46
+ attr_reader :attributes
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Represents a single node capability entry — either a supported QEMU
6
+ # CPU model or a supported QEMU machine type.
7
+ #
8
+ # The two kinds share a flat structure with different optional fields
9
+ # populated. A small, kind-aware model keeps the presenter simple while
10
+ # still allowing JSON/YAML output to expose all relevant attributes.
11
+ #
12
+ # @example QEMU CPU capability
13
+ # cap = Capability.new(node_name: "pve1", kind: :cpu, name: "host", vendor: "Intel")
14
+ #
15
+ # @example QEMU machine type capability
16
+ # cap = Capability.new(node_name: "pve1", kind: :machine, name: "pc-q35-8.1", machine_type: "q35", version: "8.1")
17
+ #
18
+ # @see Pvectl::Repositories::Capabilities Repository producing instances
19
+ # @see Pvectl::Presenters::Capability Presenter for display
20
+ #
21
+ class Capability < Base
22
+ # @return [String, nil] node the capability belongs to
23
+ attr_reader :node_name
24
+
25
+ # @return [Symbol] capability kind: :cpu or :machine
26
+ attr_reader :kind
27
+
28
+ # @return [String, nil] identifying name (CPU model or machine id)
29
+ attr_reader :name
30
+
31
+ # @return [String, nil] CPU vendor (only for :cpu kind)
32
+ attr_reader :vendor
33
+
34
+ # @return [Boolean] true when this is a custom CPU model (only :cpu)
35
+ attr_reader :custom
36
+
37
+ # @return [String, nil] machine type — q35 or i440fx (only :machine)
38
+ attr_reader :machine_type
39
+
40
+ # @return [String, nil] machine version (only :machine)
41
+ attr_reader :version
42
+
43
+ # @return [String, nil] notable changes for the version (only :machine)
44
+ attr_reader :changes
45
+
46
+ # Creates a new Capability.
47
+ #
48
+ # @param attributes [Hash] attribute hash
49
+ def initialize(attributes = {})
50
+ super
51
+ @node_name = @attributes[:node_name]
52
+ @kind = @attributes[:kind]
53
+ @name = @attributes[:name]
54
+ @vendor = @attributes[:vendor]
55
+ @custom = @attributes[:custom] || false
56
+ @machine_type = @attributes[:machine_type]
57
+ @version = @attributes[:version]
58
+ @changes = @attributes[:changes]
59
+ end
60
+ end
61
+ end
62
+ end