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,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl migrate vm` command.
6
+ #
7
+ # Migrates one or more virtual machines to another cluster node.
8
+ # Always requires --target and confirmation (--yes to skip).
9
+ #
10
+ # @example Migrate a single VM
11
+ # pvectl migrate vm 100 --target pve2 --yes
12
+ #
13
+ # @example Online migration
14
+ # pvectl migrate vm 100 --target pve2 --online --yes
15
+ #
16
+ class MigrateVm
17
+ include MigrateCommand
18
+
19
+ # Registers the migrate command with the CLI.
20
+ #
21
+ # @param cli [GLI::App] the CLI application object
22
+ # @return [void]
23
+ def self.register(cli)
24
+ cli.desc "Migrate a resource to another node"
25
+ cli.long_desc <<~HELP
26
+ Migrate virtual machines or containers between cluster nodes.
27
+ Supports live migration (--online) for zero-downtime moves.
28
+
29
+ EXAMPLES
30
+ Offline migration:
31
+ $ pvectl migrate vm 100 --target pve2
32
+
33
+ Live migration (zero downtime):
34
+ $ pvectl migrate vm 100 --target pve2 --online
35
+
36
+ Migrate a container with restart:
37
+ $ pvectl migrate ct 200 --target pve2 --restart
38
+
39
+ Migrate to different storage:
40
+ $ pvectl migrate vm 100 --target pve2 --target-storage local-lvm
41
+
42
+ Batch migrate all VMs from a node:
43
+ $ pvectl migrate vm --all --node pve1 --target pve2 --yes
44
+
45
+ Migrate VMs matching a selector:
46
+ $ pvectl migrate vm --all -l tags=web --target pve2 --yes
47
+
48
+ NOTES
49
+ --online (live migration) requires shared storage or migration
50
+ network configured between nodes.
51
+
52
+ Container migration with --restart briefly stops the container,
53
+ migrates, then starts it on the target node.
54
+
55
+ --target is required for all migrations.
56
+
57
+ Default timeout is 600 seconds. Use --timeout to adjust for
58
+ large VMs with lots of memory/disk.
59
+
60
+ SEE ALSO
61
+ pvectl help clone Clone instead of move
62
+ pvectl help get nodes List available target nodes
63
+ HELP
64
+ cli.arg_name "RESOURCE_TYPE [ID...]"
65
+ cli.command :migrate do |c|
66
+ c.desc "Target node (required)"
67
+ c.flag [:target, :t], arg_name: "NODE"
68
+
69
+ c.desc "Online/live migration"
70
+ c.switch [:online], negatable: false
71
+
72
+ c.desc "Restart migration (container only)"
73
+ c.switch [:restart], negatable: false
74
+
75
+ c.desc "Target storage mapping"
76
+ c.flag [:"target-storage"], arg_name: "STORAGE"
77
+
78
+ c.desc "Select all resources of this type"
79
+ c.switch [:all, :A], negatable: false
80
+
81
+ c.desc "Filter by source node"
82
+ c.flag [:node, :n], arg_name: "NODE"
83
+
84
+ c.desc "Filter by selector (e.g., status=running,tags=prod)"
85
+ c.flag [:l, :selector], arg_name: "SELECTOR", multiple: true
86
+
87
+ c.desc "Skip confirmation prompt"
88
+ c.switch [:yes, :y], negatable: false
89
+
90
+ c.desc "Stop on first error"
91
+ c.switch [:"fail-fast"], negatable: false
92
+
93
+ c.desc "Wait for migration to complete (sync mode)"
94
+ c.switch [:wait], negatable: false
95
+
96
+ c.desc "Timeout in seconds for sync operations (default: 600)"
97
+ c.flag [:timeout], type: Integer, arg_name: "SECONDS"
98
+
99
+ c.action do |global_options, options, args|
100
+ resource_type = args.shift
101
+
102
+ exit_code = case resource_type
103
+ when "vm"
104
+ Commands::MigrateVm.execute(args, options, global_options)
105
+ when "container", "ct"
106
+ Commands::MigrateContainer.execute(args, options, global_options)
107
+ else
108
+ $stderr.puts "Error: Unknown resource type: #{resource_type}"
109
+ $stderr.puts "Valid types: vm, container, ct"
110
+ ExitCodes::USAGE_ERROR
111
+ end
112
+
113
+ exit exit_code if exit_code != 0
114
+ end
115
+ end
116
+ end
117
+
118
+ RESOURCE_TYPE = :vm
119
+ SUPPORTED_RESOURCES = %w[vm].freeze
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,239 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Shared functionality for the move disk commands (move disk vm, move disk ct).
6
+ #
7
+ # Mirrors the structure of MigrateCommand but operates on a single resource
8
+ # (VM or container) and a single disk/volume rather than a batch.
9
+ #
10
+ # @example Including in a command class
11
+ # class MoveDiskVm
12
+ # include MoveDiskCommand
13
+ # RESOURCE_TYPE = :vm
14
+ # SUPPORTED_RESOURCES = %w[vm].freeze
15
+ # end
16
+ #
17
+ module MoveDiskCommand
18
+ # Allowed target formats for VM disks (per Proxmox API).
19
+ VALID_FORMATS = %w[raw qcow2 vmdk].freeze
20
+
21
+ # Class methods added when the module is included.
22
+ module ClassMethods
23
+ # Executes the move disk command.
24
+ #
25
+ # @param args [Array<String>] command-positional args ([id, disk])
26
+ # @param options [Hash] command options
27
+ # @param global_options [Hash] global CLI options
28
+ # @return [Integer] exit code
29
+ def execute(args, options, global_options)
30
+ new(args, options, global_options).execute
31
+ end
32
+ end
33
+
34
+ # Hook called when the module is included.
35
+ #
36
+ # @param base [Class] the class including this module
37
+ def self.included(base)
38
+ base.extend(ClassMethods)
39
+ end
40
+
41
+ # Initializes a move disk command.
42
+ #
43
+ # @param args [Array<String>] command-positional args ([id, disk])
44
+ # @param options [Hash] command options
45
+ # @param global_options [Hash] global CLI options
46
+ def initialize(args, options, global_options)
47
+ @args = Array(args).compact
48
+ @options = options
49
+ @global_options = global_options
50
+ end
51
+
52
+ # Executes the move disk command.
53
+ #
54
+ # @return [Integer] exit code
55
+ def execute
56
+ target = @options[:target]
57
+ return usage_error("--target is required") if target.nil? || target.to_s.empty?
58
+
59
+ return usage_error("#{id_label} and #{disk_label} are required") if @args.size < 2
60
+
61
+ id_str, disk = @args[0], @args[1]
62
+
63
+ unless id_str.to_s.match?(/\A\d+\z/)
64
+ return usage_error("Invalid #{id_label}: #{id_str}")
65
+ end
66
+
67
+ if @options[:format]
68
+ return usage_error("--format is not supported for containers") if resource_type_symbol == :container
69
+ return usage_error("Invalid format: #{@options[:format]} (allowed: #{VALID_FORMATS.join(', ')})") unless VALID_FORMATS.include?(@options[:format])
70
+ end
71
+
72
+ perform_operation(id_str.to_i, disk, target)
73
+ end
74
+
75
+ private
76
+
77
+ # Returns the resource type symbol (:vm or :container).
78
+ #
79
+ # @return [Symbol]
80
+ def resource_type_symbol
81
+ self.class::RESOURCE_TYPE
82
+ end
83
+
84
+ # Returns the human label for the resource ID ("VMID" or "CTID").
85
+ #
86
+ # @return [String]
87
+ def id_label
88
+ resource_type_symbol == :vm ? "VMID" : "CTID"
89
+ end
90
+
91
+ # Returns the human label for the disk/volume.
92
+ #
93
+ # @return [String]
94
+ def disk_label
95
+ resource_type_symbol == :vm ? "DISK" : "VOLUME"
96
+ end
97
+
98
+ # Performs the move operation: loads config, resolves resource, prompts,
99
+ # invokes service, prints result.
100
+ #
101
+ # @param id [Integer] resource identifier
102
+ # @param disk [String] disk/volume key
103
+ # @param target [String] target storage
104
+ # @return [Integer] exit code
105
+ def perform_operation(id, disk, target)
106
+ load_config
107
+ connection = Pvectl::Connection.new(@config)
108
+
109
+ resource = resolve_resource(connection, id)
110
+ return resource_not_found(id) if resource.nil?
111
+
112
+ return ExitCodes::SUCCESS unless confirm_operation(resource, disk, target)
113
+
114
+ service = build_service(connection)
115
+ result = service.execute(resource_type_symbol, resource,
116
+ disk: disk, target_storage: target)
117
+
118
+ output_result(result)
119
+ result.failed? ? ExitCodes::GENERAL_ERROR : ExitCodes::SUCCESS
120
+ rescue Pvectl::Config::ConfigNotFoundError,
121
+ Pvectl::Config::InvalidConfigError,
122
+ Pvectl::Config::ContextNotFoundError,
123
+ Pvectl::Config::ClusterNotFoundError,
124
+ Pvectl::Config::UserNotFoundError
125
+ raise
126
+ rescue StandardError => e
127
+ $stderr.puts "Error: #{e.message}"
128
+ ExitCodes::GENERAL_ERROR
129
+ end
130
+
131
+ # Resolves the single resource by ID using the appropriate repository.
132
+ #
133
+ # @param connection [Connection] API connection
134
+ # @param id [Integer] resource ID
135
+ # @return [Models::Vm, Models::Container, nil]
136
+ def resolve_resource(connection, id)
137
+ repo = resource_type_symbol == :vm ?
138
+ Pvectl::Repositories::Vm.new(connection) :
139
+ Pvectl::Repositories::Container.new(connection)
140
+ repo.get(id)
141
+ end
142
+
143
+ # Builds the MoveDisk service with required dependencies.
144
+ #
145
+ # @param connection [Connection] API connection
146
+ # @return [Services::MoveDisk]
147
+ def build_service(connection)
148
+ Pvectl::Services::MoveDisk.new(
149
+ vm_repository: Pvectl::Repositories::Vm.new(connection),
150
+ container_repository: Pvectl::Repositories::Container.new(connection),
151
+ task_repository: Pvectl::Repositories::Task.new(connection),
152
+ options: service_options
153
+ )
154
+ end
155
+
156
+ # Builds service options from command options.
157
+ #
158
+ # @return [Hash]
159
+ def service_options
160
+ opts = {}
161
+ opts[:format] = @options[:format] if @options[:format]
162
+ opts[:delete_source] = true if @options[:"delete-source"]
163
+ opts[:bandwidth] = @options[:bandwidth].to_i if @options[:bandwidth]
164
+ opts[:wait] = true if @options[:wait]
165
+ opts[:timeout] = @options[:timeout] if @options[:timeout]
166
+ opts
167
+ end
168
+
169
+ # Confirms the move operation with the user.
170
+ #
171
+ # @param resource [Models::Vm, Models::Container]
172
+ # @param disk [String]
173
+ # @param target [String]
174
+ # @return [Boolean] true if the operation should proceed
175
+ def confirm_operation(resource, disk, target)
176
+ return true if @options[:yes]
177
+
178
+ type_name = resource_type_symbol == :vm ? "VM" : "container"
179
+ $stdout.puts "You are about to move #{disk} of #{type_name} #{resource.vmid} " \
180
+ "(#{resource.name || 'unnamed'}) on #{resource.node} to storage #{target}."
181
+ $stdout.puts ""
182
+ if @options[:"delete-source"]
183
+ $stdout.puts "Source disk WILL be deleted after a successful copy."
184
+ else
185
+ $stdout.puts "Source disk will be kept as an unused entry."
186
+ end
187
+ $stdout.print "Proceed? [y/N]: "
188
+
189
+ response = $stdin.gets&.strip&.downcase
190
+ %w[y yes].include?(response)
191
+ end
192
+
193
+ # Loads configuration from file or environment.
194
+ #
195
+ # @return [void]
196
+ def load_config
197
+ service = Pvectl::Config::Service.new
198
+ service.load(config: @global_options[:config])
199
+ @config = service.current_config
200
+ end
201
+
202
+ # Outputs the operation result using the configured formatter.
203
+ #
204
+ # @param result [Models::OperationResult]
205
+ # @return [void]
206
+ def output_result(result)
207
+ presenter = if resource_type_symbol == :vm
208
+ Pvectl::Presenters::VmOperationResult.new
209
+ else
210
+ Pvectl::Presenters::ContainerOperationResult.new
211
+ end
212
+ format = @global_options[:output] || "table"
213
+ color_flag = @global_options[:color]
214
+
215
+ formatter = Pvectl::Formatters::Registry.for(format)
216
+ output = formatter.format([result], presenter, color: color_flag)
217
+ puts output
218
+ end
219
+
220
+ # Outputs usage error and returns the usage exit code.
221
+ #
222
+ # @param message [String]
223
+ # @return [Integer]
224
+ def usage_error(message)
225
+ $stderr.puts "Error: #{message}"
226
+ ExitCodes::USAGE_ERROR
227
+ end
228
+
229
+ # Outputs "not found" error and returns the not-found exit code.
230
+ #
231
+ # @param id [Integer]
232
+ # @return [Integer]
233
+ def resource_not_found(id)
234
+ $stderr.puts "Error: No #{resource_type_symbol == :vm ? 'VM' : 'container'} found with ID #{id}"
235
+ ExitCodes::NOT_FOUND
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl move disk ct` command.
6
+ #
7
+ # Moves a container volume (rootfs / mpN) to a different storage on the
8
+ # same node. The --format flag is rejected because the LXC move_volume
9
+ # API does not accept a format.
10
+ #
11
+ # @example Move rootfs of container 200 to storage2
12
+ # pvectl move disk ct 200 rootfs --target storage2
13
+ #
14
+ class MoveDiskContainer
15
+ include MoveDiskCommand
16
+
17
+ RESOURCE_TYPE = :container
18
+ SUPPORTED_RESOURCES = %w[container ct].freeze
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl move disk vm` command.
6
+ #
7
+ # Moves a VM disk to a different storage on the same node.
8
+ # The Proxmox API call is asynchronous — the returned UPID is included
9
+ # in the OperationResult. Use --wait to block until the task completes.
10
+ #
11
+ # @example Move scsi0 of VM 100 to storage2
12
+ # pvectl move disk vm 100 scsi0 --target storage2
13
+ #
14
+ # @example Move and convert format, deleting source after copy
15
+ # pvectl move disk vm 100 scsi0 --target storage2 --format qcow2 --delete-source
16
+ #
17
+ class MoveDiskVm
18
+ include MoveDiskCommand
19
+
20
+ # Registers the move command with the CLI.
21
+ #
22
+ # @param cli [GLI::App] the CLI application object
23
+ # @return [void]
24
+ def self.register(cli)
25
+ cli.desc "Move a VM disk or container volume to another storage"
26
+ cli.long_desc <<~HELP
27
+ Move a VM disk or container volume to a different storage on the
28
+ same node. The source disk is kept as an unused entry by default;
29
+ pass --delete-source to remove it after a successful copy.
30
+
31
+ The operation is asynchronous: the returned task UPID can be
32
+ tracked with `pvectl get tasks` or `pvectl logs task <upid>`.
33
+ Pass --wait to block until the move completes (with --timeout).
34
+
35
+ EXAMPLES
36
+ Move VM disk to another storage:
37
+ $ pvectl move disk vm 100 scsi0 --target storage2
38
+
39
+ Move VM disk and convert format:
40
+ $ pvectl move disk vm 100 scsi0 --target storage2 --format qcow2
41
+
42
+ Move VM disk and delete source after copy:
43
+ $ pvectl move disk vm 100 scsi0 --target storage2 --delete-source
44
+
45
+ Move container rootfs to another storage:
46
+ $ pvectl move disk ct 200 rootfs --target storage2
47
+
48
+ Move container mount point with bandwidth cap (KiB/s):
49
+ $ pvectl move disk ct 200 mp0 --target storage2 --bandwidth 10240
50
+
51
+ Block until completion:
52
+ $ pvectl move disk vm 100 scsi0 --target storage2 --wait
53
+
54
+ NOTES
55
+ --target is required and must be a valid storage on the source node.
56
+
57
+ --format is only valid for VMs (raw, qcow2, vmdk). It is rejected
58
+ for containers because the LXC API does not accept a format.
59
+
60
+ --bandwidth is in KiB/s, matching the Proxmox API directly. The
61
+ operation defaults to the datacenter/storage move limit when omitted.
62
+
63
+ For VMs, allowed disk keys include ide0..ide3, scsi0..scsi30,
64
+ virtio0..virtio15, sata0..sata5, efidisk0, tpmstate0, unused*.
65
+ For containers, allowed volume keys include rootfs, mp0..mp255,
66
+ unused*.
67
+
68
+ SEE ALSO
69
+ pvectl help migrate Move a VM/container to another node
70
+ pvectl help clone Clone a VM or container
71
+ pvectl help get storage List storages on the cluster
72
+ HELP
73
+ cli.arg_name "SUBJECT RESOURCE_TYPE ID DISK"
74
+ cli.command :move do |c|
75
+ c.desc "Target storage (required)"
76
+ c.flag [:target, :t], arg_name: "STORAGE"
77
+
78
+ c.desc "Target disk format (VM only): raw, qcow2, or vmdk"
79
+ c.flag [:format, :f], arg_name: "FORMAT"
80
+
81
+ c.desc "Delete source disk after successful copy"
82
+ c.switch [:"delete-source"], negatable: false
83
+
84
+ c.desc "Bandwidth limit in KiB/s"
85
+ c.flag [:bandwidth, :b], type: Integer, arg_name: "KIBPS"
86
+
87
+ c.desc "Wait for the task to complete (sync mode)"
88
+ c.switch [:wait], negatable: false
89
+
90
+ c.desc "Timeout in seconds for sync operations (default: 600)"
91
+ c.flag [:timeout], type: Integer, arg_name: "SECONDS"
92
+
93
+ c.desc "Skip confirmation prompt"
94
+ c.switch [:yes, :y], negatable: false
95
+
96
+ c.action do |global_options, options, args|
97
+ subject = args.shift
98
+ resource_type = args.shift
99
+
100
+ exit_code =
101
+ if subject != "disk"
102
+ $stderr.puts "Error: Unknown subject: #{subject.inspect}"
103
+ $stderr.puts "Valid subjects: disk"
104
+ ExitCodes::USAGE_ERROR
105
+ else
106
+ case resource_type
107
+ when "vm"
108
+ Commands::MoveDiskVm.execute(args, options, global_options)
109
+ when "container", "ct"
110
+ Commands::MoveDiskContainer.execute(args, options, global_options)
111
+ else
112
+ $stderr.puts "Error: Unknown resource type: #{resource_type}"
113
+ $stderr.puts "Valid types: vm, container, ct"
114
+ ExitCodes::USAGE_ERROR
115
+ end
116
+ end
117
+
118
+ exit exit_code if exit_code != 0
119
+ end
120
+ end
121
+ end
122
+
123
+ RESOURCE_TYPE = :vm
124
+ SUPPORTED_RESOURCES = %w[vm].freeze
125
+ end
126
+ end
127
+ end