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,205 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Template-specific functionality built on IrreversibleCommand.
6
+ #
7
+ # Converts VMs/containers to Proxmox templates (irreversible operation).
8
+ # Filters out resources that are already templates with a warning.
9
+ # Calls the repository's convert_to_template method for each resource.
10
+ #
11
+ # @example Including in a command class
12
+ # class TemplateVm
13
+ # include TemplateCommand
14
+ # RESOURCE_TYPE = :vm
15
+ # SUPPORTED_RESOURCES = %w[vm].freeze
16
+ # end
17
+ #
18
+ module TemplateCommand
19
+ include IrreversibleCommand
20
+
21
+ # Hook called when module is included.
22
+ #
23
+ # @param base [Class] the class including this module
24
+ def self.included(base)
25
+ base.extend(IrreversibleCommand::ClassMethods)
26
+ end
27
+
28
+ private
29
+
30
+ # Overrides perform_operation to filter already-template resources.
31
+ #
32
+ # @return [Integer] exit code
33
+ def perform_operation
34
+ load_config
35
+ connection = Pvectl::Connection.new(@config)
36
+
37
+ resources = resolve_resources(connection)
38
+ return no_resources_found if resources.empty?
39
+
40
+ # Filter out already-template resources with warning
41
+ convertible, already_templates = resources.partition { |r| !r.template? }
42
+
43
+ already_templates.each do |r|
44
+ type_name = resource_type_symbol == :vm ? "VM" : "Container"
45
+ $stderr.puts "Warning: #{type_name} #{r.vmid} is already a template, skipping"
46
+ end
47
+
48
+ return ExitCodes::SUCCESS if convertible.empty?
49
+ return ExitCodes::SUCCESS unless confirm_operation(convertible)
50
+
51
+ results = perform_service_call(convertible, connection)
52
+ output_results(results)
53
+ determine_exit_code(results)
54
+ rescue Pvectl::Config::ConfigNotFoundError,
55
+ Pvectl::Config::InvalidConfigError,
56
+ Pvectl::Config::ContextNotFoundError,
57
+ Pvectl::Config::ClusterNotFoundError,
58
+ Pvectl::Config::UserNotFoundError
59
+ raise
60
+ rescue StandardError => e
61
+ $stderr.puts "Error: #{e.message}"
62
+ ExitCodes::GENERAL_ERROR
63
+ end
64
+
65
+ # Confirms template operation — uses --yes flag.
66
+ #
67
+ # @param resources [Array] Resources to convert
68
+ # @return [Boolean] true if operation should proceed
69
+ def confirm_operation(resources)
70
+ return true if @options[:yes]
71
+
72
+ $stdout.puts confirm_message(resources)
73
+ $stdout.puts ""
74
+ $stdout.puts irreversibility_warning
75
+ $stdout.print "Proceed? [y/N]: "
76
+
77
+ response = $stdin.gets&.strip&.downcase
78
+ %w[y yes].include?(response)
79
+ end
80
+
81
+ # Returns confirmation message for template conversion.
82
+ #
83
+ # @param resources [Array] resources to convert
84
+ # @return [String] confirmation message
85
+ def confirm_message(resources)
86
+ type_name = resource_type_symbol == :vm ? "VM" : "container"
87
+ type_plural = resource_type_symbol == :vm ? "VMs" : "containers"
88
+
89
+ if resources.size == 1
90
+ r = resources.first
91
+ "You are about to convert #{type_name} #{r.vmid} (#{r.name || 'unnamed'}) on #{r.node} to a template."
92
+ else
93
+ lines = ["You are about to convert #{resources.size} #{type_plural} to templates:"]
94
+ resources.each { |r| lines << " - #{r.vmid} (#{r.name || 'unnamed'}) on #{r.node}" }
95
+ lines.join("\n")
96
+ end
97
+ end
98
+
99
+ # Returns irreversibility warning for template conversion.
100
+ #
101
+ # @return [String] warning text
102
+ def irreversibility_warning
103
+ "This action is IRREVERSIBLE. Templates cannot be converted back and cannot be started."
104
+ end
105
+
106
+ # Performs template conversion for each resource.
107
+ #
108
+ # @param resources [Array] resources to convert
109
+ # @param connection [Connection] API connection
110
+ # @return [Array<Models::OperationResult>] results
111
+ def perform_service_call(resources, connection)
112
+ repo = build_repository(connection)
113
+ @task_repository = Pvectl::Repositories::Task.new(connection) if @options[:force]
114
+ resources.map do |resource|
115
+ convert_single(repo, resource)
116
+ end
117
+ end
118
+
119
+ # Converts a single resource to template.
120
+ # Handles running resources: errors without --force, stops with --force.
121
+ #
122
+ # @param repo [Repositories::Base] repository
123
+ # @param resource [Models::Vm, Models::Container] resource to convert
124
+ # @return [Models::OperationResult] result
125
+ def convert_single(repo, resource)
126
+ if resource.status == "running"
127
+ return running_error(resource) unless @options[:force]
128
+
129
+ stop_result = stop_resource(repo, resource)
130
+ return stop_result if stop_result.failed?
131
+ end
132
+
133
+ if resource_type_symbol == :vm
134
+ repo.convert_to_template(resource.vmid, resource.node, disk: @options[:disk])
135
+ else
136
+ repo.convert_to_template(resource.vmid, resource.node)
137
+ end
138
+
139
+ build_success_result(resource)
140
+ rescue StandardError => e
141
+ build_error_result(resource, e.message)
142
+ end
143
+
144
+ # Returns error result for a running resource without --force.
145
+ #
146
+ # @param resource [Models::Vm, Models::Container] resource
147
+ # @return [Models::OperationResult] failed result
148
+ def running_error(resource)
149
+ type_name = resource_type_symbol == :vm ? "VM" : "Container"
150
+ build_error_result(resource, "#{type_name} #{resource.vmid} is running. Stop it first or use --force")
151
+ end
152
+
153
+ # Stops a running resource before template conversion.
154
+ #
155
+ # @param repo [Repositories::Base] repository
156
+ # @param resource [Models::Vm, Models::Container] resource
157
+ # @return [Models::OperationResult] result
158
+ def stop_resource(repo, resource)
159
+ upid = repo.stop(resource.vmid, resource.node)
160
+ timeout = @options[:timeout] || 60
161
+ task = @task_repository.wait(upid, timeout: timeout)
162
+
163
+ if task.successful?
164
+ build_success_result(resource)
165
+ else
166
+ build_error_result(resource, "Failed to stop: #{task.exitstatus}")
167
+ end
168
+ end
169
+
170
+ # Builds a successful operation result.
171
+ #
172
+ # @param resource [Models::Vm, Models::Container] resource
173
+ # @return [Models::OperationResult] success result
174
+ def build_success_result(resource)
175
+ result_class = resource_type_symbol == :vm ? Models::VmOperationResult : Models::ContainerOperationResult
176
+ attrs = { operation: :template, success: true }
177
+ attrs[resource_type_symbol == :vm ? :vm : :container] = resource
178
+ result_class.new(attrs)
179
+ end
180
+
181
+ # Builds an error operation result.
182
+ #
183
+ # @param resource [Models::Vm, Models::Container] resource
184
+ # @param error_message [String] error message
185
+ # @return [Models::OperationResult] error result
186
+ def build_error_result(resource, error_message)
187
+ result_class = resource_type_symbol == :vm ? Models::VmOperationResult : Models::ContainerOperationResult
188
+ attrs = { operation: :template, success: false, error: error_message }
189
+ attrs[resource_type_symbol == :vm ? :vm : :container] = resource
190
+ result_class.new(attrs)
191
+ end
192
+
193
+ # Builds presenter for template results.
194
+ #
195
+ # @return [Presenters::Base] presenter
196
+ def build_presenter
197
+ if resource_type_symbol == :vm
198
+ Pvectl::Presenters::VmOperationResult.new
199
+ else
200
+ Pvectl::Presenters::ContainerOperationResult.new
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl template container` command.
6
+ #
7
+ # Converts one or more containers to templates (irreversible).
8
+ # Always requires confirmation (--yes to skip).
9
+ # Running containers must be stopped first or use --force.
10
+ #
11
+ # @example Convert a single container
12
+ # pvectl template container 200 --yes
13
+ #
14
+ # @example Convert using ct alias
15
+ # pvectl template ct 200 --yes
16
+ #
17
+ # @example Force convert running container
18
+ # pvectl template container 200 --force --yes
19
+ #
20
+ class TemplateContainer
21
+ include TemplateCommand
22
+
23
+ RESOURCE_TYPE = :container
24
+ SUPPORTED_RESOURCES = %w[container ct].freeze
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl template vm` command.
6
+ #
7
+ # Converts one or more VMs to templates (irreversible).
8
+ # Always requires confirmation (--yes to skip).
9
+ # Running VMs must be stopped first or use --force.
10
+ #
11
+ # @example Convert a single VM
12
+ # pvectl template vm 100 --yes
13
+ #
14
+ # @example Convert multiple VMs
15
+ # pvectl template vm 100 101 102 --yes
16
+ #
17
+ # @example Force convert running VM (stops it first)
18
+ # pvectl template vm 100 --force --yes
19
+ #
20
+ # @example Convert specific disk only
21
+ # pvectl template vm 100 --disk scsi0 --yes
22
+ #
23
+ class TemplateVm
24
+ include TemplateCommand
25
+
26
+ # Registers the template command with the CLI.
27
+ #
28
+ # @param cli [GLI::App] the CLI application object
29
+ # @return [void]
30
+ def self.register(cli)
31
+ cli.desc "Convert a resource to a template (irreversible)"
32
+ cli.long_desc <<~HELP
33
+ Convert a virtual machine or container into a Proxmox template.
34
+ Templates are read-only base images used for linked cloning.
35
+
36
+ WARNING: This operation is irreversible. Once converted, the resource
37
+ cannot be converted back to a regular VM/container.
38
+
39
+ EXAMPLES
40
+ Convert a stopped VM to template:
41
+ $ pvectl template vm 100 --yes
42
+
43
+ Convert a running VM (stops it first):
44
+ $ pvectl template vm 100 --force --yes
45
+
46
+ Convert multiple VMs:
47
+ $ pvectl template vm 100 101 102 --yes
48
+
49
+ Convert a container:
50
+ $ pvectl template ct 200 --yes
51
+
52
+ NOTES
53
+ The resource must be stopped before conversion. Use --force to
54
+ automatically stop a running resource before converting.
55
+
56
+ --yes skips the confirmation prompt. Without it, you will be
57
+ asked to confirm the irreversible operation.
58
+
59
+ SEE ALSO
60
+ pvectl help clone Create linked clones from templates
61
+ pvectl help get templates List existing templates
62
+ HELP
63
+ cli.arg_name "RESOURCE_TYPE [ID...]"
64
+ cli.command :template do |c|
65
+ c.desc "Skip confirmation prompt"
66
+ c.switch [:yes, :y], negatable: false
67
+
68
+ c.desc "Force stop running VM/container before conversion"
69
+ c.switch [:force, :f], negatable: false
70
+
71
+ c.desc "Filter by node name"
72
+ c.flag [:node, :n], arg_name: "NODE"
73
+
74
+ c.desc "Filter by selector (e.g., status=stopped,tags=base)"
75
+ c.flag [:l, :selector], arg_name: "SELECTOR", multiple: true
76
+
77
+ c.desc "Select all resources of this type"
78
+ c.switch [:all, :A], negatable: false
79
+
80
+ c.desc "Specific disk to convert (VM only, e.g., scsi0)"
81
+ c.flag [:disk], arg_name: "DISK"
82
+
83
+ c.action do |global_options, options, args|
84
+ resource_type = args.shift
85
+
86
+ exit_code = case resource_type
87
+ when "vm"
88
+ Commands::TemplateVm.execute(resource_type, args, options, global_options)
89
+ when "container", "ct"
90
+ Commands::TemplateContainer.execute(resource_type, args, options, global_options)
91
+ else
92
+ $stderr.puts "Error: Unknown resource type: #{resource_type}"
93
+ $stderr.puts "Valid types: vm, container, ct"
94
+ ExitCodes::USAGE_ERROR
95
+ end
96
+
97
+ exit exit_code if exit_code != 0
98
+ end
99
+ end
100
+ end
101
+
102
+ RESOURCE_TYPE = :vm
103
+ SUPPORTED_RESOURCES = %w[vm].freeze
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Top
6
+ # Dispatcher for the `pvectl top <resource_type>` command.
7
+ #
8
+ # Displays resource usage metrics (CPU, memory, disk, swap) for
9
+ # cluster resources. Supports nodes, VMs, and containers.
10
+ #
11
+ # Uses Top::ResourceRegistry for handler lookup and Top-specific
12
+ # presenters for metrics-focused display. VMs and containers are
13
+ # filtered to running-only by default (use --all to show all).
14
+ #
15
+ # @example Basic usage
16
+ # Commands::Top::Command.execute("nodes", options, global_options)
17
+ #
18
+ class Command
19
+ # Resource types where running-only filtering does NOT apply.
20
+ SHOW_ALL_RESOURCE_TYPES = %w[nodes node].freeze
21
+
22
+ # Registers the top command with the CLI.
23
+ #
24
+ # @param cli [GLI::App] the CLI application object
25
+ # @return [void]
26
+ def self.register(cli)
27
+ cli.desc "Display resource usage metrics (CPU, memory, disk)"
28
+ cli.long_desc <<~HELP
29
+ Display real-time resource usage metrics for cluster resources.
30
+ Shows CPU, memory, disk, and network utilization in a table format.
31
+
32
+ By default, only running VMs and containers are shown. Use --all to
33
+ include stopped resources. Nodes always show all (including offline).
34
+
35
+ RESOURCE TYPES
36
+ nodes Cluster node metrics
37
+ vms Virtual machine metrics (running only by default)
38
+ containers Container metrics (running only by default)
39
+
40
+ EXAMPLES
41
+ Cluster node resource usage:
42
+ $ pvectl top nodes
43
+
44
+ VMs sorted by CPU usage:
45
+ $ pvectl top vms --sort-by cpu
46
+
47
+ All containers including stopped:
48
+ $ pvectl top containers --all
49
+
50
+ Memory usage in JSON format:
51
+ $ pvectl top vms --sort-by memory -o json
52
+
53
+ NOTES
54
+ Sort fields: cpu, memory, disk, netin, netout, name, node.
55
+
56
+ Stopped VMs/containers show 0% for all metrics. Use --all
57
+ if you need to see them alongside running resources.
58
+
59
+ SEE ALSO
60
+ pvectl help get List resources with status info
61
+ pvectl help describe Detailed resource information
62
+ HELP
63
+ cli.arg_name "RESOURCE_TYPE"
64
+ cli.command :top do |c|
65
+ c.desc "Sort by field (cpu, memory, disk, netin, netout, name, node)"
66
+ c.flag [:"sort-by"], arg_name: "FIELD"
67
+
68
+ c.desc "Show all (including stopped)"
69
+ c.switch [:all], default_value: false
70
+
71
+ c.action do |global_options, options, args|
72
+ resource_type = args[0]
73
+ exit_code = execute(resource_type, options, global_options)
74
+ exit exit_code if exit_code != 0
75
+ end
76
+ end
77
+ end
78
+
79
+ # Executes the top command.
80
+ #
81
+ # @param resource_type [String, nil] type of resource (e.g., "nodes")
82
+ # @param options [Hash] command-specific options
83
+ # - :"sort-by" [String] sort field (cpu, memory, disk)
84
+ # @param global_options [Hash] global CLI options
85
+ # - :output [String] output format (table, json, yaml, wide)
86
+ # - :color [Boolean, nil] explicit color setting
87
+ # @return [Integer] exit code
88
+ def self.execute(resource_type, options, global_options)
89
+ new(resource_type, options, global_options).execute
90
+ end
91
+
92
+ # Creates a new Top command instance.
93
+ #
94
+ # @param resource_type [String, nil] type of resource
95
+ # @param options [Hash] command options
96
+ # @param global_options [Hash] global CLI options
97
+ # @param handler [Object, nil] override handler for testing
98
+ # @param registry [Class] resource registry (default: Top::ResourceRegistry)
99
+ def initialize(resource_type, options, global_options,
100
+ handler: nil, registry: Top::ResourceRegistry)
101
+ @resource_type = resource_type
102
+ @options = options
103
+ @global_options = global_options
104
+ @handler = handler
105
+ @registry = registry
106
+ end
107
+
108
+ # Executes the top operation.
109
+ #
110
+ # @return [Integer] exit code
111
+ def execute
112
+ return missing_resource_type_error if @resource_type.nil?
113
+
114
+ handler = @handler || @registry.for(@resource_type)
115
+ return unknown_resource_error unless handler
116
+
117
+ models = handler.list(sort: @options[:"sort-by"])
118
+ models = filter_running(models) unless @options[:all]
119
+ output = format_output(models, handler.presenter)
120
+ puts output
121
+
122
+ ExitCodes::SUCCESS
123
+ rescue Pvectl::Config::ConfigNotFoundError,
124
+ Pvectl::Config::InvalidConfigError,
125
+ Pvectl::Config::ContextNotFoundError,
126
+ Pvectl::Config::ClusterNotFoundError,
127
+ Pvectl::Config::UserNotFoundError => e
128
+ $stderr.puts "Error: #{e.message}"
129
+ ExitCodes::CONFIG_ERROR
130
+ rescue Timeout::Error => e
131
+ output_connection_error(e.message)
132
+ ExitCodes::CONNECTION_ERROR
133
+ rescue Errno::ECONNREFUSED => e
134
+ output_connection_error(e.message)
135
+ ExitCodes::CONNECTION_ERROR
136
+ rescue SocketError => e
137
+ output_connection_error(e.message)
138
+ ExitCodes::CONNECTION_ERROR
139
+ end
140
+
141
+ private
142
+
143
+ # Outputs error for missing resource type argument.
144
+ #
145
+ # @return [Integer] USAGE_ERROR exit code
146
+ def missing_resource_type_error
147
+ $stderr.puts "Error: resource type is required"
148
+ $stderr.puts "Usage: pvectl top RESOURCE_TYPE [options]"
149
+ $stderr.puts "Available resources: nodes, vms, containers"
150
+ ExitCodes::USAGE_ERROR
151
+ end
152
+
153
+ # Outputs error for unknown resource type.
154
+ #
155
+ # @return [Integer] USAGE_ERROR exit code
156
+ def unknown_resource_error
157
+ $stderr.puts "Unknown resource type: #{@resource_type}"
158
+ $stderr.puts "Available resources: nodes, vms, containers"
159
+ ExitCodes::USAGE_ERROR
160
+ end
161
+
162
+ # Filters models to running-only for VM/CT resource types.
163
+ # Nodes always show all (offline nodes are important info).
164
+ #
165
+ # @param models [Array<Object>] models to filter
166
+ # @return [Array<Object>] filtered models
167
+ def filter_running(models)
168
+ return models if SHOW_ALL_RESOURCE_TYPES.include?(@resource_type)
169
+ return models unless models.first.respond_to?(:running?)
170
+
171
+ models.select(&:running?)
172
+ end
173
+
174
+ # Outputs connection error message.
175
+ #
176
+ # @param message [String] the error message
177
+ # @return [void]
178
+ def output_connection_error(message)
179
+ $stderr.puts "Error: #{message}"
180
+ end
181
+
182
+ # Formats models for output using the appropriate formatter.
183
+ #
184
+ # @param models [Array<Object>] collection of models
185
+ # @param presenter [Presenters::Base] presenter for the resource type
186
+ # @return [String] formatted output
187
+ def format_output(models, presenter)
188
+ format = @global_options[:output] || "table"
189
+ color_enabled = determine_color_enabled
190
+ formatter = Formatters::Registry.for(format)
191
+ formatter.format(models, presenter, color_enabled: color_enabled)
192
+ end
193
+
194
+ # Determines if color output should be enabled.
195
+ #
196
+ # @return [Boolean] true if color should be enabled
197
+ def determine_color_enabled
198
+ explicit = @global_options[:color]
199
+ return explicit unless explicit.nil?
200
+
201
+ $stdout.tty?
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Top
6
+ module Handlers
7
+ # Handler for Top command container metrics display.
8
+ #
9
+ # Wraps Get::Handlers::Containers to fetch container data and pairs it
10
+ # with TopContainer presenter for metrics-focused output.
11
+ #
12
+ # @example Using via ResourceRegistry
13
+ # handler = Top::ResourceRegistry.for("containers")
14
+ # containers = handler.list(sort: "cpu")
15
+ # presenter = handler.presenter
16
+ #
17
+ # @see Pvectl::Commands::Get::Handlers::Containers Get handler
18
+ # @see Pvectl::Presenters::TopContainer Top presenter
19
+ #
20
+ class Containers
21
+ include Top::ResourceHandler
22
+
23
+ # Creates handler with optional Get handler for dependency injection.
24
+ #
25
+ # @param get_handler [Get::Handlers::Containers, nil] handler (default: create new)
26
+ def initialize(get_handler: nil)
27
+ @get_handler = get_handler
28
+ end
29
+
30
+ # Lists containers with optional sorting.
31
+ #
32
+ # @param sort [String, nil] sort field (cpu, memory, disk)
33
+ # @return [Array<Models::Container>] collection of Container models
34
+ def list(sort: nil, **_)
35
+ get_handler.list(sort: sort)
36
+ end
37
+
38
+ # Returns Top-specific presenter for containers.
39
+ #
40
+ # @return [Presenters::TopContainer] TopContainer presenter instance
41
+ def presenter
42
+ Presenters::TopContainer.new
43
+ end
44
+
45
+ private
46
+
47
+ # Returns Get handler, creating it if necessary.
48
+ #
49
+ # @return [Get::Handlers::Containers] Containers get handler
50
+ def get_handler
51
+ @get_handler ||= Get::Handlers::Containers.new
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ Pvectl::Commands::Top::ResourceRegistry.register(
60
+ "containers", Pvectl::Commands::Top::Handlers::Containers, aliases: ["container", "cts", "ct"]
61
+ )
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Top
6
+ module Handlers
7
+ # Handler for Top command node metrics display.
8
+ #
9
+ # Wraps Get::Handlers::Nodes to fetch node data and pairs it
10
+ # with TopNode presenter for metrics-focused output.
11
+ #
12
+ # @example Using via ResourceRegistry
13
+ # handler = Top::ResourceRegistry.for("nodes")
14
+ # nodes = handler.list(sort: "cpu")
15
+ # presenter = handler.presenter
16
+ #
17
+ # @see Pvectl::Commands::Get::Handlers::Nodes Get handler
18
+ # @see Pvectl::Presenters::TopNode Top presenter
19
+ #
20
+ class Nodes
21
+ include Top::ResourceHandler
22
+
23
+ # Creates handler with optional Get handler for dependency injection.
24
+ #
25
+ # @param get_handler [Get::Handlers::Nodes, nil] handler (default: create new)
26
+ def initialize(get_handler: nil)
27
+ @get_handler = get_handler
28
+ end
29
+
30
+ # Lists nodes with optional sorting.
31
+ #
32
+ # @param sort [String, nil] sort field (cpu, memory, disk)
33
+ # @return [Array<Models::Node>] collection of Node models
34
+ def list(sort: nil, **_)
35
+ get_handler.list(sort: sort)
36
+ end
37
+
38
+ # Returns Top-specific presenter for nodes.
39
+ #
40
+ # @return [Presenters::TopNode] TopNode presenter instance
41
+ def presenter
42
+ Presenters::TopNode.new
43
+ end
44
+
45
+ private
46
+
47
+ # Returns Get handler, creating it if necessary.
48
+ #
49
+ # @return [Get::Handlers::Nodes] Nodes get handler
50
+ def get_handler
51
+ @get_handler ||= Get::Handlers::Nodes.new
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ Pvectl::Commands::Top::ResourceRegistry.register(
60
+ "nodes", Pvectl::Commands::Top::Handlers::Nodes, aliases: ["node"]
61
+ )