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,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl create backup` command.
6
+ #
7
+ # Creates backups for one or more VMs/containers.
8
+ # Supports multiple VMIDs with optional confirmation prompt.
9
+ #
10
+ # @example Create single backup
11
+ # pvectl create backup 100 --storage local
12
+ #
13
+ # @example Create backup for multiple VMs
14
+ # pvectl create backup 100 101 102 --storage nfs --mode snapshot
15
+ #
16
+ # @example Create backup with options
17
+ # pvectl create backup 100 --storage local --compress zstd --notes "Pre-upgrade" --protected
18
+ #
19
+ class CreateBackup
20
+ SUPPORTED_RESOURCES = %w[backup].freeze
21
+
22
+ # Executes the create backup command.
23
+ #
24
+ # @param resource_type [String, nil] resource type (backup)
25
+ # @param resource_ids [Array<String>, String, nil] VM identifiers
26
+ # @param options [Hash] command options
27
+ # @param global_options [Hash] global CLI options
28
+ # @return [Integer] exit code
29
+ def self.execute(resource_type, resource_ids, options, global_options)
30
+ new(resource_type, resource_ids, options, global_options).execute
31
+ end
32
+
33
+ # Initializes a create backup command.
34
+ #
35
+ # @param resource_type [String, nil] resource type (backup)
36
+ # @param resource_ids [Array<String>, String, nil] VM identifiers
37
+ # @param options [Hash] command options
38
+ # @param global_options [Hash] global CLI options
39
+ def initialize(resource_type, resource_ids, options, global_options)
40
+ @resource_type = resource_type
41
+ @resource_ids = Array(resource_ids).compact.map(&:to_i)
42
+ @options = options
43
+ @global_options = global_options
44
+ end
45
+
46
+ # Executes the create backup command.
47
+ #
48
+ # @return [Integer] exit code
49
+ def execute
50
+ return usage_error("Resource type required (backup)") unless @resource_type
51
+ return usage_error("Unsupported resource: #{@resource_type}") unless SUPPORTED_RESOURCES.include?(@resource_type)
52
+ return usage_error("At least one VMID is required") if @resource_ids.empty?
53
+ return usage_error("--storage is required") unless @options[:storage]
54
+
55
+ perform_operation
56
+ end
57
+
58
+ private
59
+
60
+ # Performs the backup creation operation.
61
+ #
62
+ # @return [Integer] exit code
63
+ def perform_operation
64
+ load_config
65
+ connection = Pvectl::Connection.new(@config)
66
+
67
+ backup_repo = Pvectl::Repositories::Backup.new(connection)
68
+ resolver = Pvectl::Utils::ResourceResolver.new(connection)
69
+ task_repo = Pvectl::Repositories::Task.new(connection)
70
+
71
+ service = Pvectl::Services::Backup.new(
72
+ backup_repo: backup_repo,
73
+ resource_resolver: resolver,
74
+ task_repo: task_repo,
75
+ options: service_options
76
+ )
77
+
78
+ return ExitCodes::SUCCESS unless confirm_operation
79
+
80
+ results = service.create(
81
+ @resource_ids,
82
+ storage: @options[:storage],
83
+ mode: @options[:mode] || "snapshot",
84
+ compress: @options[:compress] || "zstd",
85
+ notes: @options[:notes],
86
+ protected: @options[:protected] || false
87
+ )
88
+
89
+ output_results(results)
90
+ determine_exit_code(results)
91
+ rescue Pvectl::Config::ConfigNotFoundError,
92
+ Pvectl::Config::InvalidConfigError,
93
+ Pvectl::Config::ContextNotFoundError,
94
+ Pvectl::Config::ClusterNotFoundError,
95
+ Pvectl::Config::UserNotFoundError
96
+ raise
97
+ rescue StandardError => e
98
+ $stderr.puts "Error: #{e.message}"
99
+ ExitCodes::GENERAL_ERROR
100
+ end
101
+
102
+ # Confirms multi-VMID operation with user.
103
+ #
104
+ # @return [Boolean] true if operation should proceed
105
+ def confirm_operation
106
+ return true if @resource_ids.size == 1
107
+ return true if @options[:yes]
108
+
109
+ $stdout.puts "You are about to create backups for #{@resource_ids.size} VMs:"
110
+ @resource_ids.each { |vmid| $stdout.puts " - #{vmid}" }
111
+ $stdout.puts ""
112
+ $stdout.print "Proceed? [y/N]: "
113
+
114
+ response = $stdin.gets&.strip&.downcase
115
+ %w[y yes].include?(response)
116
+ end
117
+
118
+ # Loads configuration from file or environment.
119
+ #
120
+ # @return [void]
121
+ def load_config
122
+ service = Pvectl::Config::Service.new
123
+ service.load(config: @global_options[:config])
124
+ @config = service.current_config
125
+ end
126
+
127
+ # Builds service options from command options.
128
+ #
129
+ # @return [Hash] service options
130
+ def service_options
131
+ opts = {}
132
+ opts[:timeout] = @options[:timeout] if @options[:timeout]
133
+ opts[:async] = true if @options[:async]
134
+ opts[:fail_fast] = true if @options[:"fail-fast"]
135
+ opts
136
+ end
137
+
138
+ # Outputs operation results using the configured formatter.
139
+ #
140
+ # @param results [Array<Models::OperationResult>] operation results
141
+ # @return [void]
142
+ def output_results(results)
143
+ presenter = Pvectl::Presenters::SnapshotOperationResult.new
144
+ format = @global_options[:output] || "table"
145
+ color_flag = @global_options[:color]
146
+
147
+ formatter = Pvectl::Formatters::Registry.for(format)
148
+ output = formatter.format(results, presenter, color: color_flag)
149
+ puts output
150
+ end
151
+
152
+ # Determines exit code based on results.
153
+ #
154
+ # @param results [Array<Models::OperationResult>] operation results
155
+ # @return [Integer] exit code
156
+ def determine_exit_code(results)
157
+ return ExitCodes::SUCCESS if results.all?(&:successful?)
158
+ return ExitCodes::SUCCESS if results.all?(&:pending?)
159
+
160
+ ExitCodes::GENERAL_ERROR
161
+ end
162
+
163
+ # Outputs usage error and returns exit code.
164
+ #
165
+ # @param message [String] error message
166
+ # @return [Integer] exit code
167
+ def usage_error(message)
168
+ $stderr.puts "Error: #{message}"
169
+ ExitCodes::USAGE_ERROR
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl create container` command.
6
+ #
7
+ # Includes CreateResourceCommand for shared workflow and overrides
8
+ # template methods with container-specific behavior.
9
+ #
10
+ # @example Flag-based creation
11
+ # pvectl create container --hostname web-ct --ostemplate local:vztmpl/debian-12.tar.zst \
12
+ # --rootfs storage=local-lvm,size=8G --cores 2 --memory 2048
13
+ #
14
+ class CreateContainer
15
+ include CreateResourceCommand
16
+ include SharedConfigParsers
17
+
18
+ private
19
+
20
+ # @return [String] human label for container resources
21
+ def resource_label
22
+ "container"
23
+ end
24
+
25
+ # @return [String] human label for container IDs
26
+ def resource_id_label
27
+ "CTID"
28
+ end
29
+
30
+ # @return [Boolean] true if --hostname is missing
31
+ def required_params_missing?
32
+ !@options[:hostname]
33
+ end
34
+
35
+ # @return [Object] container creation wizard
36
+ def build_wizard
37
+ Pvectl::Wizards::CreateContainer.new(@options, @global_options)
38
+ end
39
+
40
+ # @param connection [Connection] API connection
41
+ # @param task_repo [Repositories::Task] task repository
42
+ # @return [Services::CreateContainer] container creation service
43
+ def build_create_service(connection, task_repo)
44
+ ct_repo = Pvectl::Repositories::Container.new(connection)
45
+ Pvectl::Services::CreateContainer.new(
46
+ container_repository: ct_repo,
47
+ task_repository: task_repo,
48
+ options: service_options
49
+ )
50
+ end
51
+
52
+ # @param result [Models::ContainerOperationResult] operation result
53
+ # @return [void]
54
+ def output_result(result)
55
+ presenter = Pvectl::Presenters::ContainerOperationResult.new
56
+ format = @global_options[:output] || "table"
57
+ color_flag = @global_options[:color]
58
+
59
+ formatter = Pvectl::Formatters::Registry.for(format)
60
+ output = formatter.format([result], presenter, color: color_flag)
61
+ puts output
62
+ end
63
+
64
+ # Validates flags and performs flag-based creation.
65
+ #
66
+ # @return [Integer] exit code
67
+ def perform_create
68
+ return usage_error("--hostname is required") unless @options[:hostname]
69
+ return usage_error("--ostemplate is required") unless @options[:ostemplate]
70
+ return usage_error("--rootfs is required") unless @options[:rootfs]
71
+
72
+ super
73
+ end
74
+
75
+ # Extracts CLI options into a service params hash.
76
+ #
77
+ # Delegates container config parsing to SharedConfigParsers#build_ct_config_params,
78
+ # then adds create-specific parameters.
79
+ #
80
+ # @return [Hash] service-compatible parameters
81
+ # @raise [ArgumentError] if parser validation fails
82
+ def build_params_from_flags
83
+ params = build_ct_config_params
84
+ params[:hostname] = @options[:hostname]
85
+ params[:node] = @options[:node] || resolve_default_node
86
+ params[:ostemplate] = @options[:ostemplate]
87
+ params[:description] = @options[:description]
88
+ params[:pool] = @options[:pool]
89
+
90
+ ctid = @args.first
91
+ params[:ctid] = ctid.to_i if ctid
92
+
93
+ params.compact
94
+ end
95
+
96
+ # @param params [Hash] container creation parameters
97
+ # @return [void]
98
+ def display_resource_summary(params)
99
+ $stdout.puts " Hostname: #{params[:hostname]}"
100
+ $stdout.puts " Node: #{params[:node] || '(from context)'}"
101
+ $stdout.puts " Template: #{truncate_template(params[:ostemplate])}"
102
+ $stdout.puts " CPU: #{params[:cores] || 1} cores" if params[:cores]
103
+ $stdout.puts " Memory: #{params[:memory] || 512} MB"
104
+ $stdout.puts " Swap: #{params[:swap] || 512} MB"
105
+
106
+ if params[:rootfs]
107
+ $stdout.puts " Root FS: #{params[:rootfs][:storage]}, #{params[:rootfs][:size]}"
108
+ end
109
+
110
+ if params[:mountpoints]
111
+ params[:mountpoints].each_with_index do |mp, i|
112
+ $stdout.puts " Mount#{i}: #{mp[:storage]}, #{mp[:size]} -> #{mp[:mp]}"
113
+ end
114
+ end
115
+
116
+ if params[:nets]
117
+ params[:nets].each_with_index do |net, i|
118
+ ip_info = net[:ip] ? ", #{net[:ip]}" : ""
119
+ $stdout.puts " Net#{i}: #{net[:bridge]}, #{net[:name] || 'eth0'}#{ip_info}"
120
+ end
121
+ end
122
+
123
+ $stdout.puts " Unpriv: #{params[:privileged] ? 'No' : 'Yes'}"
124
+ $stdout.puts " Features: #{params[:features]}" if params[:features]
125
+ $stdout.puts " Tags: #{params[:tags]}" if params[:tags]
126
+ $stdout.puts " Pool: #{params[:pool]}" if params[:pool]
127
+ end
128
+
129
+ # Truncates long template paths for display.
130
+ #
131
+ # @param template [String] full template path
132
+ # @return [String] truncated template name
133
+ def truncate_template(template)
134
+ return template unless template
135
+
136
+ parts = template.split("/")
137
+ parts.last || template
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,244 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Shared functionality for resource creation commands.
6
+ #
7
+ # Template method pattern: provides common create workflow
8
+ # (interactive detection, confirmation, dry-run, config loading)
9
+ # while specialization classes define resource-specific hooks.
10
+ #
11
+ # @abstract Include this module and implement template methods.
12
+ #
13
+ # @example Specialization
14
+ # class CreateVm
15
+ # include CreateResourceCommand
16
+ # private
17
+ # def resource_label = "VM"
18
+ # def resource_id_label = "VMID"
19
+ # # ...
20
+ # end
21
+ #
22
+ module CreateResourceCommand
23
+ # Class methods added when the module is included.
24
+ module ClassMethods
25
+ # Executes the create command.
26
+ #
27
+ # @param args [Array<String>] command arguments
28
+ # @param options [Hash] command options
29
+ # @param global_options [Hash] global CLI options
30
+ # @return [Integer] exit code
31
+ def execute(args, options, global_options)
32
+ new(args, options, global_options).execute
33
+ end
34
+ end
35
+
36
+ # Hook called when module is included.
37
+ #
38
+ # @param base [Class] the class including this module
39
+ def self.included(base)
40
+ base.extend(ClassMethods)
41
+ end
42
+
43
+ # Initializes a create command.
44
+ #
45
+ # @param args [Array<String>] command arguments
46
+ # @param options [Hash] command options
47
+ # @param global_options [Hash] global CLI options
48
+ def initialize(args, options, global_options)
49
+ @args = args
50
+ @options = options
51
+ @global_options = global_options
52
+ end
53
+
54
+ # Executes the create command.
55
+ #
56
+ # @return [Integer] exit code
57
+ def execute
58
+ if interactive_mode?
59
+ perform_interactive
60
+ else
61
+ perform_create
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ # --- Template methods (override in specialization) ---
68
+
69
+ # @return [String] human label for resource ("VM" or "container")
70
+ def resource_label
71
+ raise NotImplementedError, "#{self.class} must implement #resource_label"
72
+ end
73
+
74
+ # @return [String] human label for resource ID ("VMID" or "CTID")
75
+ def resource_id_label
76
+ raise NotImplementedError, "#{self.class} must implement #resource_id_label"
77
+ end
78
+
79
+ # @return [Boolean] true if required params for non-interactive mode are missing
80
+ def required_params_missing?
81
+ raise NotImplementedError, "#{self.class} must implement #required_params_missing?"
82
+ end
83
+
84
+ # @return [Hash] parameters built from CLI flags
85
+ def build_params_from_flags
86
+ raise NotImplementedError, "#{self.class} must implement #build_params_from_flags"
87
+ end
88
+
89
+ # @return [Object] wizard instance for interactive mode
90
+ def build_wizard
91
+ raise NotImplementedError, "#{self.class} must implement #build_wizard"
92
+ end
93
+
94
+ # @param connection [Connection] API connection
95
+ # @param task_repo [Repositories::Task] task repository
96
+ # @return [Object] create service instance
97
+ def build_create_service(connection, task_repo)
98
+ raise NotImplementedError, "#{self.class} must implement #build_create_service"
99
+ end
100
+
101
+ # @param result [Models::OperationResult] operation result
102
+ # @return [void]
103
+ def output_result(result)
104
+ raise NotImplementedError, "#{self.class} must implement #output_result"
105
+ end
106
+
107
+ # @param params [Hash] creation parameters
108
+ # @return [void]
109
+ def display_resource_summary(params)
110
+ raise NotImplementedError, "#{self.class} must implement #display_resource_summary"
111
+ end
112
+
113
+ # --- Shared implementation ---
114
+
115
+ # Determines whether to use interactive mode.
116
+ #
117
+ # @return [Boolean] true if interactive mode should be used
118
+ def interactive_mode?
119
+ return true if @options[:interactive]
120
+ return false if @options[:"no-interactive"]
121
+
122
+ $stdin.tty? && required_params_missing?
123
+ end
124
+
125
+ # Runs the interactive wizard flow.
126
+ #
127
+ # @return [Integer] exit code
128
+ def perform_interactive
129
+ wizard = build_wizard
130
+ wizard_params = wizard.run
131
+ return ExitCodes::SUCCESS unless wizard_params
132
+
133
+ @options[:start] = wizard_params.delete(:start) if wizard_params.key?(:start)
134
+ perform_create_with_params(wizard_params)
135
+ end
136
+
137
+ # Validates flags and performs flag-based creation.
138
+ #
139
+ # @return [Integer] exit code
140
+ def perform_create
141
+ params = build_params_from_flags
142
+ perform_create_with_params(params)
143
+ rescue ArgumentError => e
144
+ usage_error(e.message)
145
+ end
146
+
147
+ # Creates a resource with the given parameters.
148
+ #
149
+ # @param params [Hash] creation parameters
150
+ # @return [Integer] exit code
151
+ def perform_create_with_params(params)
152
+ return ExitCodes::SUCCESS if display_summary_and_confirm(params) == :cancelled
153
+ return ExitCodes::SUCCESS if @options[:"dry-run"]
154
+
155
+ load_config
156
+ connection = Pvectl::Connection.new(@config)
157
+ task_repo = Pvectl::Repositories::Task.new(connection)
158
+
159
+ service = build_create_service(connection, task_repo)
160
+ result = service.execute(**params)
161
+ output_result(result)
162
+ result.failed? ? ExitCodes::GENERAL_ERROR : ExitCodes::SUCCESS
163
+ rescue Pvectl::Config::ConfigNotFoundError,
164
+ Pvectl::Config::InvalidConfigError,
165
+ Pvectl::Config::ContextNotFoundError,
166
+ Pvectl::Config::ClusterNotFoundError,
167
+ Pvectl::Config::UserNotFoundError
168
+ raise
169
+ rescue StandardError => e
170
+ $stderr.puts "Error: #{e.message}"
171
+ ExitCodes::GENERAL_ERROR
172
+ end
173
+
174
+ # Displays a creation summary and prompts for confirmation.
175
+ #
176
+ # @param params [Hash] creation parameters
177
+ # @return [Symbol, nil] +:cancelled+ if user declines, +nil+ otherwise
178
+ def display_summary_and_confirm(params)
179
+ display_summary(params)
180
+
181
+ return nil if @options[:yes]
182
+
183
+ $stdout.print "Create this #{resource_label}? [y/N] "
184
+ $stdout.flush
185
+ answer = $stdin.gets&.strip&.downcase
186
+ answer == "y" ? nil : :cancelled
187
+ end
188
+
189
+ # Displays the creation summary.
190
+ #
191
+ # @param params [Hash] creation parameters
192
+ # @return [void]
193
+ def display_summary(params)
194
+ $stdout.puts ""
195
+ $stdout.puts " Create #{resource_label} - Summary"
196
+ $stdout.puts " #{'─' * 40}"
197
+ $stdout.puts " #{resource_id_label}:#{' ' * (10 - resource_id_label.length)}#{params[:vmid] || params[:ctid] || '(auto)'}"
198
+ display_resource_summary(params)
199
+ $stdout.puts " #{'─' * 40}"
200
+ $stdout.puts " (dry-run mode -- no #{resource_label} will be created)" if @options[:"dry-run"]
201
+ $stdout.puts ""
202
+ end
203
+
204
+ # Resolves the default node from configuration.
205
+ #
206
+ # @return [String, nil] default node name or nil
207
+ def resolve_default_node
208
+ load_config unless @config
209
+ @config&.default_node
210
+ rescue StandardError
211
+ nil
212
+ end
213
+
214
+ # Loads configuration from file or environment.
215
+ #
216
+ # @return [void]
217
+ def load_config
218
+ service = Pvectl::Config::Service.new
219
+ service.load(config: @global_options[:config])
220
+ @config = service.current_config
221
+ end
222
+
223
+ # Builds service options from command options.
224
+ #
225
+ # @return [Hash] service options
226
+ def service_options
227
+ opts = {}
228
+ opts[:timeout] = @options[:timeout] if @options[:timeout]
229
+ opts[:async] = true if @options[:async]
230
+ opts[:start] = true if @options[:start]
231
+ opts
232
+ end
233
+
234
+ # Outputs usage error and returns exit code.
235
+ #
236
+ # @param message [String] error message
237
+ # @return [Integer] exit code
238
+ def usage_error(message)
239
+ $stderr.puts "Error: #{message}"
240
+ ExitCodes::USAGE_ERROR
241
+ end
242
+ end
243
+ end
244
+ end