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,242 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl create snapshot` sub-command.
6
+ #
7
+ # Creates snapshots for VMs/containers. Snapshot name is the first
8
+ # positional argument, VMIDs are specified via --vmid flag.
9
+ # Without --vmid, operates on ALL VMs/CTs in the cluster.
10
+ #
11
+ # @example Create single snapshot
12
+ # pvectl create snapshot before-upgrade --vmid 100
13
+ #
14
+ # @example Create for multiple VMs
15
+ # pvectl create snapshot before-upgrade --vmid 100 --vmid 101
16
+ #
17
+ # @example Create cluster-wide
18
+ # pvectl create snapshot before-upgrade --yes
19
+ #
20
+ class CreateSnapshot
21
+ VMID_PATTERN = /\A[1-9]\d{0,8}\z/
22
+
23
+ # Registers as a sub-command under the parent create command.
24
+ #
25
+ # @param parent [GLI::Command] the parent create command
26
+ # @return [void]
27
+ def self.register_subcommand(parent)
28
+ parent.desc "Create a snapshot of VMs or containers"
29
+ parent.long_desc <<~HELP
30
+ Create a snapshot of one or more VMs or containers. Snapshots capture
31
+ the current state of disks (and optionally RAM) for later rollback.
32
+
33
+ EXAMPLES
34
+ Snapshot a single VM:
35
+ $ pvectl create snapshot before-upgrade --vmid 100
36
+
37
+ Snapshot multiple VMs:
38
+ $ pvectl create snapshot before-upgrade --vmid 100 --vmid 101
39
+
40
+ Snapshot with description and VM memory state:
41
+ $ pvectl create snapshot before-upgrade --vmid 100 --description "Pre-upgrade" --vmstate
42
+
43
+ Snapshot all VMs/containers cluster-wide:
44
+ $ pvectl create snapshot before-upgrade --yes
45
+
46
+ NOTES
47
+ --vmstate saves the VM's RAM state (QEMU only, not for containers).
48
+ This increases snapshot size but allows resuming from exact state.
49
+
50
+ Without --vmid, operates cluster-wide (requires --yes confirmation).
51
+
52
+ SEE ALSO
53
+ pvectl help rollback Rollback to a snapshot
54
+ pvectl help delete snapshot Delete snapshots
55
+ pvectl help get snapshots List existing snapshots
56
+ HELP
57
+ parent.command :snapshot do |s|
58
+ s.desc "VM/CT ID (repeatable)"
59
+ s.flag [:vmid], arg_name: "VMID", multiple: true
60
+
61
+ s.desc "Save VM memory state (QEMU only)"
62
+ s.switch [:vmstate], negatable: false
63
+
64
+ s.action do |global_options, options, args|
65
+ exit_code = execute(args, options, global_options)
66
+ exit exit_code if exit_code != 0
67
+ end
68
+ end
69
+ end
70
+
71
+ # Executes the create snapshot command.
72
+ #
73
+ # @param args [Array<String>] positional args (snapshot name)
74
+ # @param options [Hash] command options
75
+ # @param global_options [Hash] global CLI options
76
+ # @return [Integer] exit code
77
+ def self.execute(args, options, global_options)
78
+ new(args, options, global_options).execute
79
+ end
80
+
81
+ # Initializes a create snapshot command.
82
+ #
83
+ # @param args [Array<String>] positional args (snapshot name)
84
+ # @param options [Hash] command options
85
+ # @param global_options [Hash] global CLI options
86
+ def initialize(args, options, global_options)
87
+ @args = Array(args)
88
+ @options = options
89
+ @global_options = global_options
90
+ @snapshot_name = @args.first
91
+ @vmids = parse_vmids(options[:vmid])
92
+ @node = options[:node]
93
+ end
94
+
95
+ # Executes the create snapshot command.
96
+ #
97
+ # @return [Integer] exit code
98
+ def execute
99
+ return usage_error("Snapshot name required") unless @snapshot_name
100
+ return usage_error("Invalid VMID: #{invalid_vmid}") if invalid_vmid
101
+
102
+ perform_operation
103
+ end
104
+
105
+ private
106
+
107
+ # Parses --vmid flag values to integer array.
108
+ #
109
+ # @param vmid_values [Array<String>, nil] raw vmid values
110
+ # @return [Array<Integer>] parsed VMIDs
111
+ def parse_vmids(vmid_values)
112
+ return [] if vmid_values.nil? || vmid_values.empty?
113
+
114
+ Array(vmid_values).map(&:to_i)
115
+ end
116
+
117
+ # Finds first invalid VMID in options.
118
+ #
119
+ # @return [String, nil] invalid VMID value or nil
120
+ def invalid_vmid
121
+ return nil if @options[:vmid].nil? || @options[:vmid].empty?
122
+
123
+ Array(@options[:vmid]).find { |v| !VMID_PATTERN.match?(v.to_s) }
124
+ end
125
+
126
+ # Performs the snapshot creation operation.
127
+ #
128
+ # @return [Integer] exit code
129
+ def perform_operation
130
+ load_config
131
+ connection = Pvectl::Connection.new(@config)
132
+
133
+ snapshot_repo = Pvectl::Repositories::Snapshot.new(connection)
134
+ resolver = Pvectl::Utils::ResourceResolver.new(connection)
135
+ task_repo = Pvectl::Repositories::Task.new(connection)
136
+
137
+ service = Pvectl::Services::Snapshot.new(
138
+ snapshot_repo: snapshot_repo,
139
+ resource_resolver: resolver,
140
+ task_repo: task_repo,
141
+ options: service_options
142
+ )
143
+
144
+ return ExitCodes::SUCCESS unless confirm_operation
145
+
146
+ results = service.create(
147
+ @vmids,
148
+ name: @snapshot_name,
149
+ description: @options[:description],
150
+ vmstate: @options[:vmstate] || false,
151
+ node: @node
152
+ )
153
+
154
+ output_results(results)
155
+ determine_exit_code(results)
156
+ rescue Pvectl::Config::ConfigNotFoundError,
157
+ Pvectl::Config::InvalidConfigError,
158
+ Pvectl::Config::ContextNotFoundError,
159
+ Pvectl::Config::ClusterNotFoundError,
160
+ Pvectl::Config::UserNotFoundError
161
+ raise
162
+ rescue StandardError => e
163
+ $stderr.puts "Error: #{e.message}"
164
+ ExitCodes::GENERAL_ERROR
165
+ end
166
+
167
+ # Confirms operation with user prompt.
168
+ #
169
+ # @return [Boolean] true if operation should proceed
170
+ def confirm_operation
171
+ return true if @vmids.size == 1
172
+ return true if @options[:yes]
173
+
174
+ if @vmids.empty?
175
+ $stdout.puts "You are about to create snapshot '#{@snapshot_name}' for ALL VMs/CTs in the cluster."
176
+ else
177
+ $stdout.puts "You are about to create snapshot '#{@snapshot_name}' for #{@vmids.size} VMs:"
178
+ @vmids.each { |vmid| $stdout.puts " - #{vmid}" }
179
+ end
180
+ $stdout.puts ""
181
+ $stdout.print "Proceed? [y/N]: "
182
+
183
+ response = $stdin.gets&.strip&.downcase
184
+ %w[y yes].include?(response)
185
+ end
186
+
187
+ # Loads configuration.
188
+ #
189
+ # @return [void]
190
+ def load_config
191
+ service = Pvectl::Config::Service.new
192
+ service.load(config: @global_options[:config])
193
+ @config = service.current_config
194
+ end
195
+
196
+ # Builds service options.
197
+ #
198
+ # @return [Hash] service options
199
+ def service_options
200
+ opts = {}
201
+ opts[:timeout] = @options[:timeout] if @options[:timeout]
202
+ opts[:async] = true if @options[:async]
203
+ opts[:fail_fast] = true if @options[:"fail-fast"]
204
+ opts
205
+ end
206
+
207
+ # Outputs operation results.
208
+ #
209
+ # @param results [Array<Models::OperationResult>] results
210
+ # @return [void]
211
+ def output_results(results)
212
+ presenter = Pvectl::Presenters::SnapshotOperationResult.new
213
+ format = @global_options[:output] || "table"
214
+ color_flag = @global_options[:color]
215
+
216
+ formatter = Pvectl::Formatters::Registry.for(format)
217
+ output = formatter.format(results, presenter, color: color_flag)
218
+ puts output
219
+ end
220
+
221
+ # Determines exit code.
222
+ #
223
+ # @param results [Array<Models::OperationResult>] results
224
+ # @return [Integer] exit code
225
+ def determine_exit_code(results)
226
+ return ExitCodes::SUCCESS if results.all?(&:successful?)
227
+ return ExitCodes::SUCCESS if results.all?(&:pending?)
228
+
229
+ ExitCodes::GENERAL_ERROR
230
+ end
231
+
232
+ # Outputs usage error.
233
+ #
234
+ # @param message [String] error message
235
+ # @return [Integer] exit code
236
+ def usage_error(message)
237
+ $stderr.puts "Error: #{message}"
238
+ ExitCodes::USAGE_ERROR
239
+ end
240
+ end
241
+ end
242
+ end
@@ -0,0 +1,267 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl create vm` command.
6
+ #
7
+ # Includes CreateResourceCommand for shared workflow and overrides
8
+ # template methods with VM-specific behavior.
9
+ #
10
+ # @example Flag-based creation
11
+ # pvectl create vm --name web --node pve1 --cores 4 --memory 4096
12
+ #
13
+ # @example With disk and network
14
+ # pvectl create vm 100 --name web --node pve1 \
15
+ # --disk storage=local-lvm,size=32G --net bridge=vmbr0
16
+ #
17
+ # @example Dry-run mode
18
+ # pvectl create vm --name web --node pve1 --dry-run
19
+ #
20
+ class CreateVm
21
+ include CreateResourceCommand
22
+ include SharedConfigParsers
23
+
24
+ # Registers the create command with the CLI.
25
+ #
26
+ # @param cli [GLI::App] the CLI application object
27
+ # @return [void]
28
+ def self.register(cli)
29
+ cli.desc "Create a resource"
30
+ cli.long_desc <<~HELP
31
+ Create a new virtual machine, container, snapshot, or backup.
32
+
33
+ For VMs and containers, you can either specify configuration via flags
34
+ or use --interactive for a guided wizard. Use --dry-run to preview
35
+ the configuration without actually creating the resource.
36
+
37
+ SUBCOMMANDS
38
+ create vm [ID] Create a virtual machine
39
+ create container [ID] Create an LXC container
40
+ create snapshot NAME Create a snapshot (see: pvectl help create snapshot)
41
+ create backup ID... Create a backup (vzdump)
42
+
43
+ EXAMPLES
44
+ Create a VM with specific config:
45
+ $ pvectl create vm 100 --cores 4 --memory 8192 --disk storage=local-lvm,size=50G
46
+
47
+ Create a VM using interactive wizard:
48
+ $ pvectl create vm --interactive
49
+
50
+ Preview VM creation without executing:
51
+ $ pvectl create vm 100 --cores 2 --memory 4096 --dry-run
52
+
53
+ Create a container:
54
+ $ pvectl create container 200 --hostname nginx --ostemplate local:vztmpl/debian-12.tar.zst
55
+
56
+ Create a backup:
57
+ $ pvectl create backup 100 --storage nfs-backup --mode snapshot
58
+
59
+ NOTES
60
+ If no ID is specified for VM/container, Proxmox auto-assigns the
61
+ next available ID.
62
+
63
+ VM creation supports cloud-init configuration via --cloud-init flag.
64
+
65
+ Backup modes: snapshot (default, no downtime), suspend (brief pause),
66
+ stop (full stop during backup).
67
+
68
+ SEE ALSO
69
+ pvectl help clone Clone an existing VM or container
70
+ pvectl help delete Delete resources
71
+ pvectl help get templates List available templates
72
+ HELP
73
+ cli.arg_name "RESOURCE_TYPE [ID...]"
74
+ cli.command :create do |c|
75
+ c.desc "Resource name"
76
+ c.flag [:name], arg_name: "NAME"
77
+
78
+ c.desc "Description/notes"
79
+ c.flag [:description, :notes], arg_name: "TEXT"
80
+
81
+ # Backup-specific flags
82
+ c.desc "Target storage for backup"
83
+ c.flag [:storage], arg_name: "STORAGE"
84
+
85
+ c.desc "Backup mode (snapshot, suspend, stop)"
86
+ c.default_value "snapshot"
87
+ c.flag [:mode], arg_name: "MODE", must_match: %w[snapshot suspend stop]
88
+
89
+ c.desc "Compression (zstd, gzip, lzo, 0 for none)"
90
+ c.default_value "zstd"
91
+ c.flag [:compress], arg_name: "TYPE"
92
+
93
+ c.desc "Protect backup from deletion"
94
+ c.switch [:protected], negatable: false
95
+
96
+ # Common flags
97
+ c.desc "Skip confirmation prompt"
98
+ c.switch [:yes, :y], negatable: false
99
+
100
+ c.desc "Timeout in seconds for sync operations"
101
+ c.flag [:timeout], type: Integer, arg_name: "SECONDS"
102
+
103
+ c.desc "Force async mode (return task ID immediately)"
104
+ c.switch [:async], negatable: false
105
+
106
+ c.desc "Stop on first error (default: continue and report all)"
107
+ c.switch [:"fail-fast"], negatable: false
108
+
109
+ # Shared config flags (VM + container)
110
+ SharedFlags.common_config(c)
111
+ SharedFlags.vm_config(c)
112
+ SharedFlags.container_config(c)
113
+
114
+ c.desc "Resource pool"
115
+ c.flag [:pool], arg_name: "POOL"
116
+
117
+ c.desc "Force interactive wizard mode"
118
+ c.switch [:interactive], negatable: true
119
+
120
+ c.desc "Show what would happen without creating"
121
+ c.switch [:"dry-run"], negatable: false
122
+
123
+ # Container-specific create flags
124
+ c.desc "Container hostname (container)"
125
+ c.flag [:hostname], arg_name: "NAME"
126
+
127
+ c.desc "OS template path (container): storage:vztmpl/name.tar.zst"
128
+ c.flag [:ostemplate], arg_name: "TEMPLATE"
129
+
130
+ # Sub-commands
131
+ CreateSnapshot.register_subcommand(c)
132
+
133
+ c.action do |global_options, options, args|
134
+ resource_type = args.shift
135
+ resource_ids = args
136
+
137
+ exit_code = case resource_type
138
+ when "vm"
139
+ Commands::CreateVm.execute(resource_ids, options, global_options)
140
+ when "container", "ct"
141
+ Commands::CreateContainer.execute(resource_ids, options, global_options)
142
+ when "backup"
143
+ # Map :description to :notes for backup if notes not set
144
+ options[:notes] ||= options[:description]
145
+ Commands::CreateBackup.execute(resource_type, resource_ids, options, global_options)
146
+ else
147
+ $stderr.puts "Error: Unknown resource type: #{resource_type}"
148
+ $stderr.puts "Valid types: vm, container, backup (or use: create snapshot)"
149
+ ExitCodes::USAGE_ERROR
150
+ end
151
+
152
+ exit exit_code if exit_code != 0
153
+ end
154
+ end
155
+ end
156
+
157
+ private
158
+
159
+ # @return [String] human label for VM resources
160
+ def resource_label
161
+ "VM"
162
+ end
163
+
164
+ # @return [String] human label for VM IDs
165
+ def resource_id_label
166
+ "VMID"
167
+ end
168
+
169
+ # @return [Boolean] true if --name is missing
170
+ def required_params_missing?
171
+ !@options[:name]
172
+ end
173
+
174
+ # @return [Object] VM creation wizard
175
+ def build_wizard
176
+ Pvectl::Wizards::CreateVm.new(@options, @global_options)
177
+ end
178
+
179
+ # @param connection [Connection] API connection
180
+ # @param task_repo [Repositories::Task] task repository
181
+ # @return [Services::CreateVm] VM creation service
182
+ def build_create_service(connection, task_repo)
183
+ vm_repo = Pvectl::Repositories::Vm.new(connection)
184
+ Pvectl::Services::CreateVm.new(
185
+ vm_repository: vm_repo,
186
+ task_repository: task_repo,
187
+ options: service_options
188
+ )
189
+ end
190
+
191
+ # @param result [Models::VmOperationResult] operation result
192
+ # @return [void]
193
+ def output_result(result)
194
+ presenter = Pvectl::Presenters::VmOperationResult.new
195
+ format = @global_options[:output] || "table"
196
+ color_flag = @global_options[:color]
197
+
198
+ formatter = Pvectl::Formatters::Registry.for(format)
199
+ output = formatter.format([result], presenter, color: color_flag)
200
+ puts output
201
+ end
202
+
203
+ # Validates flags and performs flag-based creation.
204
+ #
205
+ # Overrides shared #perform_create to add VM-specific validation.
206
+ #
207
+ # @return [Integer] exit code
208
+ def perform_create
209
+ return usage_error("--name is required") unless @options[:name]
210
+
211
+ super
212
+ end
213
+
214
+ # Extracts CLI options into a service params hash.
215
+ #
216
+ # Delegates VM config parsing to SharedConfigParsers#build_vm_config_params,
217
+ # then adds create-specific parameters.
218
+ #
219
+ # @return [Hash] service-compatible parameters
220
+ # @raise [ArgumentError] if parser validation fails
221
+ def build_params_from_flags
222
+ params = build_vm_config_params
223
+ params[:name] = @options[:name]
224
+ params[:node] = @options[:node] || resolve_default_node
225
+ params[:description] = @options[:description]
226
+ params[:pool] = @options[:pool]
227
+
228
+ vmid = @args.first
229
+ params[:vmid] = vmid.to_i if vmid
230
+
231
+ params.compact
232
+ end
233
+
234
+ # @param params [Hash] VM creation parameters
235
+ # @return [void]
236
+ def display_resource_summary(params)
237
+ $stdout.puts " Name: #{params[:name]}"
238
+ $stdout.puts " Node: #{params[:node] || '(from context)'}"
239
+
240
+ if params[:cores] || params[:sockets]
241
+ $stdout.puts " CPU: #{params[:cores] || 1} cores, #{params[:sockets] || 1} socket(s)"
242
+ end
243
+
244
+ $stdout.puts " Memory: #{params[:memory] || 2048} MB"
245
+
246
+ if params[:disks]
247
+ params[:disks].each_with_index do |disk, i|
248
+ $stdout.puts " Disk#{i}: #{disk[:storage]}, #{disk[:size]}"
249
+ end
250
+ end
251
+
252
+ if params[:nets]
253
+ params[:nets].each_with_index do |net, i|
254
+ $stdout.puts " Net#{i}: #{net[:bridge]}, #{net[:model] || 'virtio'}"
255
+ end
256
+ end
257
+
258
+ $stdout.puts " OS Type: #{params[:ostype]}" if params[:ostype]
259
+ $stdout.puts " BIOS: #{params[:bios]}" if params[:bios]
260
+ $stdout.puts " CD-ROM: #{params[:cdrom]}" if params[:cdrom]
261
+ $stdout.puts " Agent: enabled" if params[:agent]
262
+ $stdout.puts " Tags: #{params[:tags]}" if params[:tags]
263
+ $stdout.puts " Pool: #{params[:pool]}" if params[:pool]
264
+ end
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl delete backup` command.
6
+ #
7
+ # Deletes a backup identified by its full volume ID (volid).
8
+ # Requires --yes flag for confirmation.
9
+ #
10
+ # @example Delete a backup
11
+ # pvectl delete backup local:backup/vzdump-qemu-100-2024_01_15.vma.zst --yes
12
+ #
13
+ class DeleteBackup
14
+ # Executes the delete backup command.
15
+ #
16
+ # @param resource_type [String, nil] resource type (backup)
17
+ # @param args [Array<String>, String, nil] backup volid
18
+ # @param options [Hash] command options
19
+ # @param global_options [Hash] global CLI options
20
+ # @return [Integer] exit code
21
+ def self.execute(resource_type, args, options, global_options)
22
+ new(resource_type, args, options, global_options).execute
23
+ end
24
+
25
+ # Initializes a delete backup command.
26
+ #
27
+ # @param resource_type [String, nil] resource type (backup)
28
+ # @param args [Array<String>, String, nil] backup volid
29
+ # @param options [Hash] command options
30
+ # @param global_options [Hash] global CLI options
31
+ def initialize(resource_type, args, options, global_options)
32
+ @resource_type = resource_type
33
+ @args = Array(args).compact
34
+ @options = options
35
+ @global_options = global_options
36
+ @volid = @args.first
37
+ end
38
+
39
+ # Executes the delete backup command.
40
+ #
41
+ # @return [Integer] exit code
42
+ def execute
43
+ return usage_error("Resource type required (backup)") unless @resource_type == "backup"
44
+ return usage_error("Backup volid is required") if @volid.nil? || @volid.empty?
45
+ return usage_error("Confirmation required: use --yes to confirm deletion") unless @options[:yes]
46
+
47
+ perform_operation
48
+ end
49
+
50
+ private
51
+
52
+ # Performs the backup deletion operation.
53
+ #
54
+ # @return [Integer] exit code
55
+ def perform_operation
56
+ load_config
57
+ connection = Pvectl::Connection.new(@config)
58
+
59
+ backup_repo = Pvectl::Repositories::Backup.new(connection)
60
+ resolver = Pvectl::Utils::ResourceResolver.new(connection)
61
+ task_repo = Pvectl::Repositories::Task.new(connection)
62
+
63
+ service = Pvectl::Services::Backup.new(
64
+ backup_repo: backup_repo,
65
+ resource_resolver: resolver,
66
+ task_repo: task_repo,
67
+ options: service_options
68
+ )
69
+
70
+ result = service.delete(@volid)
71
+
72
+ output_results([result])
73
+ determine_exit_code([result])
74
+ rescue Pvectl::Config::ConfigNotFoundError,
75
+ Pvectl::Config::InvalidConfigError,
76
+ Pvectl::Config::ContextNotFoundError,
77
+ Pvectl::Config::ClusterNotFoundError,
78
+ Pvectl::Config::UserNotFoundError
79
+ raise
80
+ rescue StandardError => e
81
+ $stderr.puts "Error: #{e.message}"
82
+ ExitCodes::GENERAL_ERROR
83
+ end
84
+
85
+ # Loads configuration from file or environment.
86
+ #
87
+ # @return [void]
88
+ def load_config
89
+ service = Pvectl::Config::Service.new
90
+ service.load(config: @global_options[:config])
91
+ @config = service.current_config
92
+ end
93
+
94
+ # Builds service options from command options.
95
+ #
96
+ # @return [Hash] service options
97
+ def service_options
98
+ opts = {}
99
+ opts[:timeout] = @options[:timeout] if @options[:timeout]
100
+ opts[:async] = true if @options[:async]
101
+ opts
102
+ end
103
+
104
+ # Outputs operation results using the configured formatter.
105
+ #
106
+ # @param results [Array<Models::OperationResult>] operation results
107
+ # @return [void]
108
+ def output_results(results)
109
+ presenter = Pvectl::Presenters::SnapshotOperationResult.new
110
+ format = @global_options[:output] || "table"
111
+ color_flag = @global_options[:color]
112
+
113
+ formatter = Pvectl::Formatters::Registry.for(format)
114
+ output = formatter.format(results, presenter, color: color_flag)
115
+ puts output
116
+ end
117
+
118
+ # Determines exit code based on results.
119
+ #
120
+ # @param results [Array<Models::OperationResult>] operation results
121
+ # @return [Integer] exit code
122
+ def determine_exit_code(results)
123
+ return ExitCodes::SUCCESS if results.all?(&:successful?)
124
+ return ExitCodes::SUCCESS if results.all?(&:pending?)
125
+
126
+ ExitCodes::GENERAL_ERROR
127
+ end
128
+
129
+ # Outputs usage error and returns exit code.
130
+ #
131
+ # @param message [String] error message
132
+ # @return [Integer] exit code
133
+ def usage_error(message)
134
+ $stderr.puts "Error: #{message}"
135
+ ExitCodes::USAGE_ERROR
136
+ end
137
+ end
138
+ end
139
+ end