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,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Logs
6
+ module Handlers
7
+ # Handler for node systemd journal output.
8
+ #
9
+ # Fetches journal entries from a node via Repositories::Journal.
10
+ # Not registered in ResourceRegistry — created by Command
11
+ # when --journal flag is set.
12
+ #
13
+ # @see Pvectl::Repositories::Journal Journal repository
14
+ # @see Pvectl::Presenters::JournalEntry Journal presenter
15
+ #
16
+ class Journal
17
+ include Logs::ResourceHandler
18
+
19
+ def initialize(repository: nil)
20
+ @repository = repository
21
+ end
22
+
23
+ def list(node:, limit: 50, since: nil, until_time: nil, **_)
24
+ repository.list(node: node, last_entries: limit, since: since,
25
+ until_time: until_time)
26
+ end
27
+
28
+ def presenter
29
+ Presenters::JournalEntry.new
30
+ end
31
+
32
+ private
33
+
34
+ def repository
35
+ @repository ||= begin
36
+ config_service = Pvectl::Config::Service.new
37
+ config_service.load
38
+ connection = Pvectl::Connection.new(config_service.current_config)
39
+ Repositories::Journal.new(connection)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Logs
6
+ module Handlers
7
+ # Handler for node syslog output.
8
+ #
9
+ # Fetches syslog entries from a node via Repositories::Syslog.
10
+ # Supports filtering by service name and time range.
11
+ #
12
+ # @example Using via registry
13
+ # handler = Logs::ResourceRegistry.for("node")
14
+ # entries = handler.list(node: "pve1", service: "pvedaemon")
15
+ #
16
+ # @see Pvectl::Repositories::Syslog Syslog repository
17
+ # @see Pvectl::Presenters::SyslogEntry Syslog presenter
18
+ #
19
+ class Syslog
20
+ include Logs::ResourceHandler
21
+
22
+ def initialize(repository: nil)
23
+ @repository = repository
24
+ end
25
+
26
+ def list(node:, limit: 50, since: nil, until_time: nil, service: nil, **_)
27
+ repository.list(node: node, limit: limit, since: since,
28
+ until_time: until_time, service: service)
29
+ end
30
+
31
+ def presenter
32
+ Presenters::SyslogEntry.new
33
+ end
34
+
35
+ private
36
+
37
+ def repository
38
+ @repository ||= begin
39
+ config_service = Pvectl::Config::Service.new
40
+ config_service.load
41
+ connection = Pvectl::Connection.new(config_service.current_config)
42
+ Repositories::Syslog.new(connection)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ Pvectl::Commands::Logs::ResourceRegistry.register(
52
+ "node", Pvectl::Commands::Logs::Handlers::Syslog, aliases: ["nodes"]
53
+ )
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Logs
6
+ module Handlers
7
+ # Handler for task log drill-down by UPID.
8
+ #
9
+ # Fetches individual task log lines from the Proxmox API.
10
+ # Extracts the node name from the UPID for API routing.
11
+ #
12
+ # @example Using via registry
13
+ # handler = Logs::ResourceRegistry.for("task")
14
+ # lines = handler.list(upid: "UPID:pve1:000ABC:...")
15
+ #
16
+ # @see Pvectl::Repositories::TaskLog Task log repository
17
+ # @see Pvectl::Presenters::TaskLogLine Task log line presenter
18
+ #
19
+ class TaskDetail
20
+ include Logs::ResourceHandler
21
+
22
+ def initialize(repository: nil)
23
+ @repository = repository
24
+ end
25
+
26
+ def list(upid:, start: 0, limit: 512, **_)
27
+ repository.list(upid: upid, start: start, limit: limit)
28
+ end
29
+
30
+ def presenter
31
+ Presenters::TaskLogLine.new
32
+ end
33
+
34
+ private
35
+
36
+ def repository
37
+ @repository ||= begin
38
+ config_service = Pvectl::Config::Service.new
39
+ config_service.load
40
+ connection = Pvectl::Connection.new(config_service.current_config)
41
+ Repositories::TaskLog.new(connection)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Pvectl::Commands::Logs::ResourceRegistry.register(
51
+ "task", Pvectl::Commands::Logs::Handlers::TaskDetail
52
+ )
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Logs
6
+ module Handlers
7
+ # Handler for VM/CT task history logs.
8
+ #
9
+ # Resolves VM/CT node via repository, then delegates task listing
10
+ # to Services::TaskListing. With --all-nodes, passes node: nil
11
+ # to the service for cluster-wide iteration.
12
+ #
13
+ # @example Using via registry
14
+ # handler = Logs::ResourceRegistry.for("vm")
15
+ # entries = handler.list(vmid: 100, resource_type: "vm")
16
+ #
17
+ # @see Pvectl::Services::TaskListing Shared task listing service
18
+ # @see Pvectl::Presenters::TaskEntry Task entry presenter
19
+ #
20
+ class TaskLogs
21
+ include Logs::ResourceHandler
22
+
23
+ # Maps resource type aliases to repository classes.
24
+ RESOURCE_REPOS = {
25
+ "vm" => -> { Pvectl::Repositories::Vm },
26
+ "vms" => -> { Pvectl::Repositories::Vm },
27
+ "ct" => -> { Pvectl::Repositories::Container },
28
+ "container" => -> { Pvectl::Repositories::Container },
29
+ "containers" => -> { Pvectl::Repositories::Container },
30
+ "cts" => -> { Pvectl::Repositories::Container }
31
+ }.freeze
32
+
33
+ def initialize(task_list_repository: nil, vm_repository: nil, node_repository: nil)
34
+ @task_list_repository = task_list_repository
35
+ @vm_repository = vm_repository
36
+ @node_repository = node_repository
37
+ end
38
+
39
+ def list(vmid:, resource_type: "vm", all_nodes: false, limit: 50,
40
+ since: nil, until_time: nil, type_filter: nil, status_filter: nil, **_)
41
+ if all_nodes
42
+ service.list(
43
+ vmid: vmid, limit: limit, since: since,
44
+ until_time: until_time, type_filter: type_filter,
45
+ status_filter: status_filter
46
+ )
47
+ else
48
+ node = resolve_node(vmid, resource_type)
49
+ service.list(
50
+ node: node, vmid: vmid, limit: limit, since: since,
51
+ until_time: until_time, type_filter: type_filter,
52
+ status_filter: status_filter
53
+ )
54
+ end
55
+ end
56
+
57
+ def presenter
58
+ Presenters::TaskEntry.new
59
+ end
60
+
61
+ private
62
+
63
+ def resolve_node(vmid, resource_type)
64
+ resource = resource_repository(resource_type).get(vmid)
65
+ raise ResourceNotFoundError, "Resource not found: #{vmid}" unless resource
66
+
67
+ resource.node
68
+ end
69
+
70
+ def resource_repository(resource_type)
71
+ @vm_repository || build_resource_repository(resource_type)
72
+ end
73
+
74
+ def build_resource_repository(resource_type)
75
+ repo_class = RESOURCE_REPOS.fetch(resource_type, -> { Pvectl::Repositories::Vm }).call
76
+ connection = build_connection
77
+ repo_class.new(connection)
78
+ end
79
+
80
+ def service
81
+ @service ||= Pvectl::Services::TaskListing.new(
82
+ task_list_repository: task_list_repository,
83
+ node_repository: node_repository
84
+ )
85
+ end
86
+
87
+ def task_list_repository
88
+ @task_list_repository ||= begin
89
+ connection = build_connection
90
+ Repositories::TaskList.new(connection)
91
+ end
92
+ end
93
+
94
+ def node_repository
95
+ @node_repository ||= begin
96
+ connection = build_connection
97
+ Repositories::Node.new(connection)
98
+ end
99
+ end
100
+
101
+ def build_connection
102
+ config_service = Pvectl::Config::Service.new
103
+ config_service.load
104
+ Pvectl::Connection.new(config_service.current_config)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ Pvectl::Commands::Logs::ResourceRegistry.register(
113
+ "vm", Pvectl::Commands::Logs::Handlers::TaskLogs,
114
+ aliases: ["vms", "ct", "container", "containers", "cts"]
115
+ )
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Logs
6
+ # Interface module for Logs command handlers.
7
+ #
8
+ # Each handler fetches log data from a specific source (task list,
9
+ # syslog, journal, or task detail) and returns an appropriate presenter.
10
+ #
11
+ # @abstract Include in handler class and implement required methods.
12
+ #
13
+ # @example Implementing a handler
14
+ # class SyslogHandler
15
+ # include Logs::ResourceHandler
16
+ #
17
+ # def list(node:, limit: 50, **_)
18
+ # repository.list(node: node, limit: limit)
19
+ # end
20
+ #
21
+ # def presenter
22
+ # Presenters::SyslogEntry.new
23
+ # end
24
+ # end
25
+ #
26
+ module ResourceHandler
27
+ # Lists log entries with filtering options.
28
+ #
29
+ # @param options [Hash] keyword arguments specific to each handler
30
+ # @return [Array<Object>] collection of model objects
31
+ # @raise [NotImplementedError] if not implemented by including class
32
+ def list(**options)
33
+ raise NotImplementedError, "#{self.class}#list must be implemented"
34
+ end
35
+
36
+ # Returns the presenter for this log type.
37
+ #
38
+ # @return [Presenters::Base] presenter instance
39
+ # @raise [NotImplementedError] if not implemented by including class
40
+ def presenter
41
+ raise NotImplementedError, "#{self.class}#presenter must be implemented"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Logs
6
+ # Registry for Logs command resource handlers.
7
+ #
8
+ # Inherits registration and lookup from Commands::ResourceRegistry,
9
+ # maintaining its own isolated set of handlers for log operations.
10
+ #
11
+ # @example Registering a handler
12
+ # Logs::ResourceRegistry.register("vm", Handlers::TaskLogs, aliases: ["vms"])
13
+ #
14
+ # @example Looking up a handler
15
+ # handler = Logs::ResourceRegistry.for("vm")
16
+ #
17
+ # @see Pvectl::Commands::ResourceRegistry Base registry
18
+ #
19
+ class ResourceRegistry < Commands::ResourceRegistry; end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,282 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Shared functionality for migrate commands (migrate vm, migrate container).
6
+ #
7
+ # This module extracts common code used by MigrateVm and MigrateContainer.
8
+ # Pattern: identical to DeleteCommand module but with migrate-specific behavior:
9
+ # - Requires --target flag (no default)
10
+ # - Validates --restart only for containers
11
+ # - Async is default (no --async flag), --wait for sync
12
+ # - partition_by_target logic is in Service layer
13
+ #
14
+ # @example Including in a command class
15
+ # class MigrateVm
16
+ # include MigrateCommand
17
+ # RESOURCE_TYPE = :vm
18
+ # SUPPORTED_RESOURCES = %w[vm].freeze
19
+ # end
20
+ #
21
+ module MigrateCommand
22
+ # Valid Proxmox node name format: lowercase alphanumeric, starting with letter, hyphens allowed.
23
+ NODE_NAME_FORMAT = /\A[a-z][a-z0-9-]*\z/
24
+
25
+ # Class methods added when the module is included.
26
+ module ClassMethods
27
+ # Executes the migrate command.
28
+ #
29
+ # @param args [Array<String>] resource identifiers
30
+ # @param options [Hash] command options
31
+ # @param global_options [Hash] global CLI options
32
+ # @return [Integer] exit code
33
+ def execute(args, options, global_options)
34
+ new(args, options, global_options).execute
35
+ end
36
+ end
37
+
38
+ # Hook called when module is included.
39
+ #
40
+ # @param base [Class] the class including this module
41
+ def self.included(base)
42
+ base.extend(ClassMethods)
43
+ end
44
+
45
+ # Initializes a migrate command.
46
+ #
47
+ # @param args [Array<String>] resource identifiers
48
+ # @param options [Hash] command options
49
+ # @param global_options [Hash] global CLI options
50
+ def initialize(args, options, global_options)
51
+ @resource_ids = Array(args).compact
52
+ @options = options
53
+ @global_options = global_options
54
+ end
55
+
56
+ # Executes the migrate command.
57
+ #
58
+ # @return [Integer] exit code
59
+ def execute
60
+ target = @options[:target]
61
+ return usage_error("--target is required") if target.nil? || target.empty?
62
+
63
+ unless target.match?(NODE_NAME_FORMAT)
64
+ return usage_error("Invalid target node name: #{target}")
65
+ end
66
+
67
+ return usage_error("--restart is only supported for containers") if restart_not_allowed?
68
+
69
+ if @resource_ids.empty? && !@options[:all] && selector_strings.empty?
70
+ return usage_error("VMID, --all, or -l selector required")
71
+ end
72
+
73
+ perform_operation
74
+ end
75
+
76
+ private
77
+
78
+ # Returns the resource type symbol (:vm or :container).
79
+ #
80
+ # @return [Symbol] resource type
81
+ def resource_type_symbol
82
+ self.class::RESOURCE_TYPE
83
+ end
84
+
85
+ # Checks if --restart is used for a non-container resource.
86
+ #
87
+ # @return [Boolean] true if restart flag is invalid
88
+ def restart_not_allowed?
89
+ @options[:restart] && resource_type_symbol == :vm
90
+ end
91
+
92
+ # Performs the migrate operation.
93
+ #
94
+ # @return [Integer] exit code
95
+ def perform_operation
96
+ load_config
97
+ connection = Pvectl::Connection.new(@config)
98
+
99
+ resources = resolve_resources(connection)
100
+ return no_resources_found if resources.empty?
101
+
102
+ target = @options[:target]
103
+ return ExitCodes::SUCCESS unless confirm_operation(resources, target)
104
+
105
+ vm_repo = Pvectl::Repositories::Vm.new(connection)
106
+ container_repo = Pvectl::Repositories::Container.new(connection)
107
+ task_repo = Pvectl::Repositories::Task.new(connection)
108
+
109
+ service = Pvectl::Services::ResourceMigration.new(
110
+ vm_repository: vm_repo,
111
+ container_repository: container_repo,
112
+ task_repository: task_repo,
113
+ options: service_options
114
+ )
115
+
116
+ results = service.execute(resource_type_symbol, resources, target: target)
117
+ return ExitCodes::SUCCESS if results.empty?
118
+
119
+ output_results(results)
120
+ determine_exit_code(results)
121
+ rescue Pvectl::Config::ConfigNotFoundError,
122
+ Pvectl::Config::InvalidConfigError,
123
+ Pvectl::Config::ContextNotFoundError,
124
+ Pvectl::Config::ClusterNotFoundError,
125
+ Pvectl::Config::UserNotFoundError
126
+ raise
127
+ rescue StandardError => e
128
+ $stderr.puts "Error: #{e.message}"
129
+ ExitCodes::GENERAL_ERROR
130
+ end
131
+
132
+ # Resolves resources based on IDs, --all flag, or selectors.
133
+ #
134
+ # @param connection [Connection] API connection
135
+ # @return [Array<Models::Vm, Models::Container>] resolved resources
136
+ def resolve_resources(connection)
137
+ repo = resource_type_symbol == :vm ?
138
+ Pvectl::Repositories::Vm.new(connection) :
139
+ Pvectl::Repositories::Container.new(connection)
140
+
141
+ resources = if @options[:all]
142
+ repo.list(node: @options[:node])
143
+ elsif @resource_ids.any?
144
+ @resource_ids.each do |id|
145
+ unless id.match?(/\A\d+\z/)
146
+ raise ArgumentError, "Invalid VMID/CTID: #{id}"
147
+ end
148
+ end
149
+ resolved = @resource_ids.map { |id| repo.get(id.to_i) }.compact
150
+ resolved = resolved.select { |r| r.node == @options[:node] } if @options[:node]
151
+ resolved
152
+ else
153
+ return [] if selector_strings.empty?
154
+ repo.list(node: @options[:node])
155
+ end
156
+
157
+ apply_selectors(resources)
158
+ end
159
+
160
+ # Returns selector strings from options.
161
+ #
162
+ # @return [Array<String>] selector strings
163
+ def selector_strings
164
+ Array(@options[:selector] || @options[:l])
165
+ end
166
+
167
+ # Applies selectors to resource collection.
168
+ #
169
+ # @param resources [Array] Resources to filter
170
+ # @return [Array] Filtered resources
171
+ def apply_selectors(resources)
172
+ return resources if selector_strings.empty?
173
+
174
+ selector_class = resource_type_symbol == :vm ? Selectors::Vm : Selectors::Container
175
+ selector = selector_class.parse_all(selector_strings)
176
+ selector.apply(resources)
177
+ end
178
+
179
+ # Confirms migrate operation with user.
180
+ #
181
+ # @param resources [Array] Resources to migrate
182
+ # @param target [String] Target node name
183
+ # @return [Boolean] true if operation should proceed
184
+ def confirm_operation(resources, target)
185
+ return true if @options[:yes]
186
+
187
+ type_name = resource_type_symbol == :vm ? "VM" : "container"
188
+ type_plural = resource_type_symbol == :vm ? "VMs" : "containers"
189
+
190
+ if resources.size == 1
191
+ r = resources.first
192
+ $stdout.puts "You are about to migrate #{type_name} #{r.vmid} (#{r.name || 'unnamed'}) from #{r.node} to #{target}."
193
+ else
194
+ $stdout.puts "You are about to migrate #{resources.size} #{type_plural} to #{target}:"
195
+ resources.each { |r| $stdout.puts " - #{r.vmid} (#{r.name || 'unnamed'}) on #{r.node}" }
196
+ end
197
+
198
+ $stdout.puts ""
199
+ $stdout.puts "This will migrate the #{type_plural} to node #{target}."
200
+ $stdout.print "Proceed? [y/N]: "
201
+
202
+ response = $stdin.gets&.strip&.downcase
203
+ %w[y yes].include?(response)
204
+ end
205
+
206
+ # Loads configuration from file or environment.
207
+ #
208
+ # @return [void]
209
+ def load_config
210
+ service = Pvectl::Config::Service.new
211
+ service.load(config: @global_options[:config])
212
+ @config = service.current_config
213
+ end
214
+
215
+ # Builds service options from command options.
216
+ #
217
+ # @return [Hash] service options
218
+ def service_options
219
+ opts = {}
220
+ opts[:timeout] = @options[:timeout] if @options[:timeout]
221
+ opts[:wait] = true if @options[:wait]
222
+ opts[:online] = true if @options[:online]
223
+ opts[:restart] = true if @options[:restart]
224
+ opts[:target_storage] = @options[:"target-storage"] if @options[:"target-storage"]
225
+ opts[:fail_fast] = true if @options[:"fail-fast"]
226
+ opts
227
+ end
228
+
229
+ # Outputs operation results using the configured formatter.
230
+ #
231
+ # @param results [Array<Models::OperationResult>] operation results
232
+ # @return [void]
233
+ def output_results(results)
234
+ presenter = if resource_type_symbol == :vm
235
+ Pvectl::Presenters::VmOperationResult.new
236
+ else
237
+ Pvectl::Presenters::ContainerOperationResult.new
238
+ end
239
+ format = @global_options[:output] || "table"
240
+ color_flag = @global_options[:color]
241
+
242
+ formatter = Pvectl::Formatters::Registry.for(format)
243
+ output = formatter.format(results, presenter, color: color_flag)
244
+ puts output
245
+ end
246
+
247
+ # Determines exit code based on results.
248
+ #
249
+ # @param results [Array<Models::OperationResult>] operation results
250
+ # @return [Integer] exit code
251
+ def determine_exit_code(results)
252
+ return ExitCodes::SUCCESS if results.all?(&:successful?)
253
+ return ExitCodes::SUCCESS if results.all?(&:pending?)
254
+
255
+ ExitCodes::GENERAL_ERROR
256
+ end
257
+
258
+ # Outputs usage error and returns exit code.
259
+ #
260
+ # @param message [String] error message
261
+ # @return [Integer] exit code
262
+ def usage_error(message)
263
+ $stderr.puts "Error: #{message}"
264
+ ExitCodes::USAGE_ERROR
265
+ end
266
+
267
+ # Outputs no resources found error and returns exit code.
268
+ #
269
+ # @return [Integer] exit code
270
+ def no_resources_found
271
+ type_plural = resource_type_symbol == :vm ? "VMs" : "containers"
272
+ msg = if @options[:all] || selector_strings.any?
273
+ @options[:node] ? "No #{type_plural} found on node #{@options[:node]}" : "No #{type_plural} found matching criteria"
274
+ else
275
+ "No #{type_plural} found for given IDs"
276
+ end
277
+ $stderr.puts "Error: #{msg}"
278
+ ExitCodes::NOT_FOUND
279
+ end
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl migrate container` command.
6
+ #
7
+ # Migrates one or more LXC containers to another cluster node.
8
+ # Always requires --target and confirmation (--yes to skip).
9
+ #
10
+ # @example Migrate a single container
11
+ # pvectl migrate container 200 --target pve2 --yes
12
+ #
13
+ # @example Restart migration
14
+ # pvectl migrate container 200 --target pve2 --restart --yes
15
+ #
16
+ class MigrateContainer
17
+ include MigrateCommand
18
+
19
+ RESOURCE_TYPE = :container
20
+ SUPPORTED_RESOURCES = %w[container ct].freeze
21
+ end
22
+ end
23
+ end