pvectl 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (558) hide show
  1. checksums.yaml +7 -0
  2. data/.claude/rules/branch-before-changes.md +52 -0
  3. data/.claude/rules/documentation-updates.md +104 -0
  4. data/.claude/rules/git-workflow.md +84 -0
  5. data/.claude/rules/proxmox-api-docs.md +58 -0
  6. data/.claude/rules/rbs-signatures.md +80 -0
  7. data/.claude/rules/refactoring-as-design-option.md +35 -0
  8. data/.claude/scheduled_tasks.lock +1 -0
  9. data/.claude/settings.json +51 -0
  10. data/.mcp.json +8 -0
  11. data/.ruby-gemset +1 -0
  12. data/.ruby-version +1 -0
  13. data/CHANGELOG.md +138 -0
  14. data/CLAUDE.md +211 -0
  15. data/CODE_OF_CONDUCT.md +132 -0
  16. data/LICENSE.txt +21 -0
  17. data/README.md +143 -0
  18. data/Rakefile +8 -0
  19. data/docs/proxmox-api-update.sh +96 -0
  20. data/exe/pvectl +5 -0
  21. data/lib/pvectl/argv_preprocessor.rb +334 -0
  22. data/lib/pvectl/cli.rb +102 -0
  23. data/lib/pvectl/commands/apt.rb +389 -0
  24. data/lib/pvectl/commands/clone_container.rb +230 -0
  25. data/lib/pvectl/commands/clone_vm.rb +331 -0
  26. data/lib/pvectl/commands/cloudinit/command.rb +122 -0
  27. data/lib/pvectl/commands/cloudinit/dump.rb +94 -0
  28. data/lib/pvectl/commands/cloudinit/pending.rb +137 -0
  29. data/lib/pvectl/commands/cloudinit/regenerate.rb +79 -0
  30. data/lib/pvectl/commands/config/command.rb +65 -0
  31. data/lib/pvectl/commands/config/get_contexts.rb +68 -0
  32. data/lib/pvectl/commands/config/set_cluster.rb +103 -0
  33. data/lib/pvectl/commands/config/set_context.rb +136 -0
  34. data/lib/pvectl/commands/config/set_credentials.rb +181 -0
  35. data/lib/pvectl/commands/config/use_context.rb +69 -0
  36. data/lib/pvectl/commands/config/view.rb +67 -0
  37. data/lib/pvectl/commands/console.rb +93 -0
  38. data/lib/pvectl/commands/console_ct.rb +187 -0
  39. data/lib/pvectl/commands/console_vm.rb +187 -0
  40. data/lib/pvectl/commands/container_lifecycle_command.rb +77 -0
  41. data/lib/pvectl/commands/create_backup.rb +173 -0
  42. data/lib/pvectl/commands/create_container.rb +141 -0
  43. data/lib/pvectl/commands/create_resource_command.rb +244 -0
  44. data/lib/pvectl/commands/create_snapshot.rb +242 -0
  45. data/lib/pvectl/commands/create_vm.rb +267 -0
  46. data/lib/pvectl/commands/delete_backup.rb +139 -0
  47. data/lib/pvectl/commands/delete_command.rb +119 -0
  48. data/lib/pvectl/commands/delete_container.rb +30 -0
  49. data/lib/pvectl/commands/delete_snapshot.rb +248 -0
  50. data/lib/pvectl/commands/delete_vm.rb +127 -0
  51. data/lib/pvectl/commands/describe/command.rb +251 -0
  52. data/lib/pvectl/commands/edit_container.rb +56 -0
  53. data/lib/pvectl/commands/edit_dns.rb +149 -0
  54. data/lib/pvectl/commands/edit_hosts.rb +135 -0
  55. data/lib/pvectl/commands/edit_node.rb +54 -0
  56. data/lib/pvectl/commands/edit_resource_command.rb +180 -0
  57. data/lib/pvectl/commands/edit_vm.rb +154 -0
  58. data/lib/pvectl/commands/edit_volume.rb +189 -0
  59. data/lib/pvectl/commands/feature_command.rb +230 -0
  60. data/lib/pvectl/commands/feature_container.rb +21 -0
  61. data/lib/pvectl/commands/feature_vm.rb +94 -0
  62. data/lib/pvectl/commands/get/command.rb +360 -0
  63. data/lib/pvectl/commands/get/handlers/backups.rb +76 -0
  64. data/lib/pvectl/commands/get/handlers/capabilities.rb +107 -0
  65. data/lib/pvectl/commands/get/handlers/containers.rb +148 -0
  66. data/lib/pvectl/commands/get/handlers/disks.rb +107 -0
  67. data/lib/pvectl/commands/get/handlers/dns.rb +94 -0
  68. data/lib/pvectl/commands/get/handlers/hosts.rb +94 -0
  69. data/lib/pvectl/commands/get/handlers/nodes.rb +162 -0
  70. data/lib/pvectl/commands/get/handlers/services.rb +81 -0
  71. data/lib/pvectl/commands/get/handlers/snapshots.rb +97 -0
  72. data/lib/pvectl/commands/get/handlers/storage.rb +118 -0
  73. data/lib/pvectl/commands/get/handlers/subscription.rb +69 -0
  74. data/lib/pvectl/commands/get/handlers/tasks.rb +89 -0
  75. data/lib/pvectl/commands/get/handlers/templates.rb +175 -0
  76. data/lib/pvectl/commands/get/handlers/time.rb +118 -0
  77. data/lib/pvectl/commands/get/handlers/vms.rb +145 -0
  78. data/lib/pvectl/commands/get/handlers/volume.rb +134 -0
  79. data/lib/pvectl/commands/get/resource_handler.rb +63 -0
  80. data/lib/pvectl/commands/get/resource_registry.rb +18 -0
  81. data/lib/pvectl/commands/get/watch_loop.rb +129 -0
  82. data/lib/pvectl/commands/irreversible_command.rb +265 -0
  83. data/lib/pvectl/commands/logs/command.rb +275 -0
  84. data/lib/pvectl/commands/logs/handlers/journal.rb +46 -0
  85. data/lib/pvectl/commands/logs/handlers/syslog.rb +53 -0
  86. data/lib/pvectl/commands/logs/handlers/task_detail.rb +52 -0
  87. data/lib/pvectl/commands/logs/handlers/task_logs.rb +115 -0
  88. data/lib/pvectl/commands/logs/resource_handler.rb +46 -0
  89. data/lib/pvectl/commands/logs/resource_registry.rb +22 -0
  90. data/lib/pvectl/commands/migrate_command.rb +282 -0
  91. data/lib/pvectl/commands/migrate_container.rb +23 -0
  92. data/lib/pvectl/commands/migrate_vm.rb +122 -0
  93. data/lib/pvectl/commands/move_disk_command.rb +239 -0
  94. data/lib/pvectl/commands/move_disk_container.rb +21 -0
  95. data/lib/pvectl/commands/move_disk_vm.rb +127 -0
  96. data/lib/pvectl/commands/ping.rb +249 -0
  97. data/lib/pvectl/commands/pull.rb +342 -0
  98. data/lib/pvectl/commands/push.rb +352 -0
  99. data/lib/pvectl/commands/reset.rb +64 -0
  100. data/lib/pvectl/commands/resource_lifecycle_command.rb +277 -0
  101. data/lib/pvectl/commands/resource_registry.rb +73 -0
  102. data/lib/pvectl/commands/restart.rb +70 -0
  103. data/lib/pvectl/commands/restart_container.rb +18 -0
  104. data/lib/pvectl/commands/restore_backup.rb +236 -0
  105. data/lib/pvectl/commands/resume.rb +57 -0
  106. data/lib/pvectl/commands/rollback_snapshot.rb +228 -0
  107. data/lib/pvectl/commands/sendkey_vm.rb +205 -0
  108. data/lib/pvectl/commands/service.rb +293 -0
  109. data/lib/pvectl/commands/set_container.rb +50 -0
  110. data/lib/pvectl/commands/set_node.rb +52 -0
  111. data/lib/pvectl/commands/set_resource_command.rb +185 -0
  112. data/lib/pvectl/commands/set_vm.rb +136 -0
  113. data/lib/pvectl/commands/set_volume.rb +212 -0
  114. data/lib/pvectl/commands/shared_config_parsers.rb +126 -0
  115. data/lib/pvectl/commands/shared_flags.rb +155 -0
  116. data/lib/pvectl/commands/shutdown.rb +73 -0
  117. data/lib/pvectl/commands/shutdown_container.rb +18 -0
  118. data/lib/pvectl/commands/start.rb +79 -0
  119. data/lib/pvectl/commands/start_container.rb +18 -0
  120. data/lib/pvectl/commands/stop.rb +75 -0
  121. data/lib/pvectl/commands/stop_container.rb +18 -0
  122. data/lib/pvectl/commands/suspend.rb +64 -0
  123. data/lib/pvectl/commands/template_command.rb +205 -0
  124. data/lib/pvectl/commands/template_container.rb +27 -0
  125. data/lib/pvectl/commands/template_vm.rb +106 -0
  126. data/lib/pvectl/commands/top/command.rb +206 -0
  127. data/lib/pvectl/commands/top/handlers/containers.rb +61 -0
  128. data/lib/pvectl/commands/top/handlers/nodes.rb +61 -0
  129. data/lib/pvectl/commands/top/handlers/vms.rb +61 -0
  130. data/lib/pvectl/commands/top/resource_handler.rb +46 -0
  131. data/lib/pvectl/commands/top/resource_registry.rb +22 -0
  132. data/lib/pvectl/commands/unlink_disk_vm.rb +232 -0
  133. data/lib/pvectl/commands/vm_lifecycle_command.rb +77 -0
  134. data/lib/pvectl/commands/wakeonlan_node.rb +153 -0
  135. data/lib/pvectl/config/errors.rb +62 -0
  136. data/lib/pvectl/config/models/cluster.rb +180 -0
  137. data/lib/pvectl/config/models/context.rb +100 -0
  138. data/lib/pvectl/config/models/resolved_config.rb +171 -0
  139. data/lib/pvectl/config/models/user.rb +133 -0
  140. data/lib/pvectl/config/provider.rb +297 -0
  141. data/lib/pvectl/config/service.rb +300 -0
  142. data/lib/pvectl/config/store.rb +161 -0
  143. data/lib/pvectl/config/wizard.rb +309 -0
  144. data/lib/pvectl/config_serializer.rb +1034 -0
  145. data/lib/pvectl/connection/retry_handler.rb +161 -0
  146. data/lib/pvectl/connection.rb +157 -0
  147. data/lib/pvectl/console/terminal_session.rb +449 -0
  148. data/lib/pvectl/editor_session.rb +157 -0
  149. data/lib/pvectl/exit_codes.rb +43 -0
  150. data/lib/pvectl/formatters/base.rb +55 -0
  151. data/lib/pvectl/formatters/color_support.rb +90 -0
  152. data/lib/pvectl/formatters/json.rb +45 -0
  153. data/lib/pvectl/formatters/output_helper.rb +77 -0
  154. data/lib/pvectl/formatters/registry.rb +72 -0
  155. data/lib/pvectl/formatters/table.rb +235 -0
  156. data/lib/pvectl/formatters/wide.rb +93 -0
  157. data/lib/pvectl/formatters/yaml.rb +49 -0
  158. data/lib/pvectl/manifest_serializer.rb +142 -0
  159. data/lib/pvectl/models/apt_package.rb +107 -0
  160. data/lib/pvectl/models/backup.rb +173 -0
  161. data/lib/pvectl/models/base.rb +49 -0
  162. data/lib/pvectl/models/capability.rb +62 -0
  163. data/lib/pvectl/models/container.rb +205 -0
  164. data/lib/pvectl/models/container_operation_result.rb +27 -0
  165. data/lib/pvectl/models/dns_config.rb +54 -0
  166. data/lib/pvectl/models/hosts_file.rb +47 -0
  167. data/lib/pvectl/models/journal_entry.rb +16 -0
  168. data/lib/pvectl/models/network_interface.rb +85 -0
  169. data/lib/pvectl/models/node.rb +195 -0
  170. data/lib/pvectl/models/node_operation_result.rb +45 -0
  171. data/lib/pvectl/models/operation_result.rb +110 -0
  172. data/lib/pvectl/models/physical_disk.rb +193 -0
  173. data/lib/pvectl/models/service.rb +80 -0
  174. data/lib/pvectl/models/snapshot.rb +101 -0
  175. data/lib/pvectl/models/snapshot_description.rb +39 -0
  176. data/lib/pvectl/models/storage.rb +180 -0
  177. data/lib/pvectl/models/subscription.rb +87 -0
  178. data/lib/pvectl/models/syslog_entry.rb +17 -0
  179. data/lib/pvectl/models/task.rb +95 -0
  180. data/lib/pvectl/models/task_entry.rb +52 -0
  181. data/lib/pvectl/models/task_log_line.rb +17 -0
  182. data/lib/pvectl/models/time_config.rb +47 -0
  183. data/lib/pvectl/models/vm.rb +137 -0
  184. data/lib/pvectl/models/vm_operation_result.rb +27 -0
  185. data/lib/pvectl/models/volume.rb +133 -0
  186. data/lib/pvectl/models/volume_operation_result.rb +26 -0
  187. data/lib/pvectl/parsers/cloud_init_config.rb +92 -0
  188. data/lib/pvectl/parsers/disk_config.rb +97 -0
  189. data/lib/pvectl/parsers/lxc_mount_config.rb +98 -0
  190. data/lib/pvectl/parsers/lxc_net_config.rb +97 -0
  191. data/lib/pvectl/parsers/net_config.rb +95 -0
  192. data/lib/pvectl/parsers/smart_text.rb +42 -0
  193. data/lib/pvectl/plugin_loader.rb +157 -0
  194. data/lib/pvectl/presenters/apt_package.rb +99 -0
  195. data/lib/pvectl/presenters/backup.rb +128 -0
  196. data/lib/pvectl/presenters/base.rb +283 -0
  197. data/lib/pvectl/presenters/capability.rb +104 -0
  198. data/lib/pvectl/presenters/config/context.rb +80 -0
  199. data/lib/pvectl/presenters/container.rb +574 -0
  200. data/lib/pvectl/presenters/container_operation_result.rb +109 -0
  201. data/lib/pvectl/presenters/disk.rb +184 -0
  202. data/lib/pvectl/presenters/dns_config.rb +68 -0
  203. data/lib/pvectl/presenters/hosts_file.rb +61 -0
  204. data/lib/pvectl/presenters/journal_entry.rb +20 -0
  205. data/lib/pvectl/presenters/node.rb +762 -0
  206. data/lib/pvectl/presenters/node_operation_result.rb +50 -0
  207. data/lib/pvectl/presenters/operation_result.rb +61 -0
  208. data/lib/pvectl/presenters/service.rb +76 -0
  209. data/lib/pvectl/presenters/snapshot.rb +239 -0
  210. data/lib/pvectl/presenters/snapshot_operation_result.rb +125 -0
  211. data/lib/pvectl/presenters/storage.rb +329 -0
  212. data/lib/pvectl/presenters/subscription.rb +189 -0
  213. data/lib/pvectl/presenters/syslog_entry.rb +20 -0
  214. data/lib/pvectl/presenters/task_entry.rb +69 -0
  215. data/lib/pvectl/presenters/task_log_line.rb +20 -0
  216. data/lib/pvectl/presenters/template.rb +76 -0
  217. data/lib/pvectl/presenters/time_config.rb +86 -0
  218. data/lib/pvectl/presenters/top_container.rb +112 -0
  219. data/lib/pvectl/presenters/top_node.rb +115 -0
  220. data/lib/pvectl/presenters/top_presenter.rb +59 -0
  221. data/lib/pvectl/presenters/top_vm.rb +105 -0
  222. data/lib/pvectl/presenters/vm.rb +853 -0
  223. data/lib/pvectl/presenters/vm_operation_result.rb +109 -0
  224. data/lib/pvectl/presenters/volume.rb +136 -0
  225. data/lib/pvectl/presenters/volume_operation_result.rb +58 -0
  226. data/lib/pvectl/repositories/apt.rb +93 -0
  227. data/lib/pvectl/repositories/backup.rb +186 -0
  228. data/lib/pvectl/repositories/base.rb +110 -0
  229. data/lib/pvectl/repositories/capabilities.rb +96 -0
  230. data/lib/pvectl/repositories/container.rb +503 -0
  231. data/lib/pvectl/repositories/disk.rb +87 -0
  232. data/lib/pvectl/repositories/dns.rb +54 -0
  233. data/lib/pvectl/repositories/hosts.rb +63 -0
  234. data/lib/pvectl/repositories/journal.rb +23 -0
  235. data/lib/pvectl/repositories/node.rb +537 -0
  236. data/lib/pvectl/repositories/service.rb +139 -0
  237. data/lib/pvectl/repositories/snapshot.rb +133 -0
  238. data/lib/pvectl/repositories/storage.rb +302 -0
  239. data/lib/pvectl/repositories/subscription.rb +77 -0
  240. data/lib/pvectl/repositories/syslog.rb +25 -0
  241. data/lib/pvectl/repositories/task.rb +82 -0
  242. data/lib/pvectl/repositories/task_list.rb +30 -0
  243. data/lib/pvectl/repositories/task_log.rb +31 -0
  244. data/lib/pvectl/repositories/time_config.rb +53 -0
  245. data/lib/pvectl/repositories/vm.rb +616 -0
  246. data/lib/pvectl/repositories/volume.rb +306 -0
  247. data/lib/pvectl/selectors/base.rb +201 -0
  248. data/lib/pvectl/selectors/container.rb +116 -0
  249. data/lib/pvectl/selectors/disk.rb +59 -0
  250. data/lib/pvectl/selectors/vm.rb +116 -0
  251. data/lib/pvectl/selectors/volume.rb +59 -0
  252. data/lib/pvectl/services/backup.rb +209 -0
  253. data/lib/pvectl/services/clone_container.rb +260 -0
  254. data/lib/pvectl/services/clone_vm.rb +265 -0
  255. data/lib/pvectl/services/cloudinit.rb +96 -0
  256. data/lib/pvectl/services/console.rb +152 -0
  257. data/lib/pvectl/services/container_lifecycle.rb +124 -0
  258. data/lib/pvectl/services/create_container.rb +179 -0
  259. data/lib/pvectl/services/create_vm.rb +191 -0
  260. data/lib/pvectl/services/edit_container.rb +125 -0
  261. data/lib/pvectl/services/edit_dns.rb +159 -0
  262. data/lib/pvectl/services/edit_hosts.rb +78 -0
  263. data/lib/pvectl/services/edit_node.rb +147 -0
  264. data/lib/pvectl/services/edit_vm.rb +125 -0
  265. data/lib/pvectl/services/edit_volume.rb +224 -0
  266. data/lib/pvectl/services/get/resource_service.rb +98 -0
  267. data/lib/pvectl/services/move_disk.rb +132 -0
  268. data/lib/pvectl/services/pull_config.rb +94 -0
  269. data/lib/pvectl/services/push_config.rb +524 -0
  270. data/lib/pvectl/services/resize_volume.rb +253 -0
  271. data/lib/pvectl/services/resource_delete.rb +169 -0
  272. data/lib/pvectl/services/resource_migration.rb +170 -0
  273. data/lib/pvectl/services/sendkey.rb +108 -0
  274. data/lib/pvectl/services/service_lifecycle.rb +89 -0
  275. data/lib/pvectl/services/set_container.rb +128 -0
  276. data/lib/pvectl/services/set_node.rb +236 -0
  277. data/lib/pvectl/services/set_vm.rb +128 -0
  278. data/lib/pvectl/services/set_volume.rb +126 -0
  279. data/lib/pvectl/services/snapshot.rb +261 -0
  280. data/lib/pvectl/services/task_listing.rb +75 -0
  281. data/lib/pvectl/services/unlink_disk.rb +86 -0
  282. data/lib/pvectl/services/vm_lifecycle.rb +124 -0
  283. data/lib/pvectl/services/wakeonlan.rb +79 -0
  284. data/lib/pvectl/utils/resource_resolver.rb +80 -0
  285. data/lib/pvectl/version.rb +13 -0
  286. data/lib/pvectl/wizards/create_container.rb +105 -0
  287. data/lib/pvectl/wizards/create_vm.rb +98 -0
  288. data/lib/pvectl.rb +439 -0
  289. data/sig/external/gli.rbs +16 -0
  290. data/sig/external/proxmox_api.rbs +10 -0
  291. data/sig/pvectl/argv_preprocessor.rbs +53 -0
  292. data/sig/pvectl/cli.rbs +26 -0
  293. data/sig/pvectl/commands/apt.rbs +47 -0
  294. data/sig/pvectl/commands/clone_container.rbs +31 -0
  295. data/sig/pvectl/commands/clone_vm.rbs +33 -0
  296. data/sig/pvectl/commands/cloudinit/command.rbs +13 -0
  297. data/sig/pvectl/commands/cloudinit/dump.rbs +13 -0
  298. data/sig/pvectl/commands/cloudinit/pending.rbs +17 -0
  299. data/sig/pvectl/commands/cloudinit/regenerate.rbs +11 -0
  300. data/sig/pvectl/commands/config/command.rbs +9 -0
  301. data/sig/pvectl/commands/config/get_contexts.rbs +11 -0
  302. data/sig/pvectl/commands/config/set_cluster.rbs +11 -0
  303. data/sig/pvectl/commands/config/set_context.rbs +15 -0
  304. data/sig/pvectl/commands/config/set_credentials.rbs +15 -0
  305. data/sig/pvectl/commands/config/use_context.rbs +11 -0
  306. data/sig/pvectl/commands/config/view.rbs +11 -0
  307. data/sig/pvectl/commands/console.rbs +9 -0
  308. data/sig/pvectl/commands/console_ct.rbs +27 -0
  309. data/sig/pvectl/commands/console_vm.rbs +27 -0
  310. data/sig/pvectl/commands/container_lifecycle_command.rbs +25 -0
  311. data/sig/pvectl/commands/create_backup.rbs +29 -0
  312. data/sig/pvectl/commands/create_container.rbs +30 -0
  313. data/sig/pvectl/commands/create_resource_command.rbs +53 -0
  314. data/sig/pvectl/commands/create_snapshot.rbs +35 -0
  315. data/sig/pvectl/commands/create_vm.rbs +30 -0
  316. data/sig/pvectl/commands/delete_backup.rbs +25 -0
  317. data/sig/pvectl/commands/delete_command.rbs +45 -0
  318. data/sig/pvectl/commands/delete_container.rbs +11 -0
  319. data/sig/pvectl/commands/delete_snapshot.rbs +35 -0
  320. data/sig/pvectl/commands/delete_vm.rbs +13 -0
  321. data/sig/pvectl/commands/describe/command.rbs +27 -0
  322. data/sig/pvectl/commands/edit_container.rbs +17 -0
  323. data/sig/pvectl/commands/edit_dns.rbs +25 -0
  324. data/sig/pvectl/commands/edit_hosts.rbs +23 -0
  325. data/sig/pvectl/commands/edit_node.rbs +17 -0
  326. data/sig/pvectl/commands/edit_resource_command.rbs +35 -0
  327. data/sig/pvectl/commands/edit_vm.rbs +19 -0
  328. data/sig/pvectl/commands/edit_volume.rbs +24 -0
  329. data/sig/pvectl/commands/feature_command.rbs +43 -0
  330. data/sig/pvectl/commands/feature_container.rbs +10 -0
  331. data/sig/pvectl/commands/feature_vm.rbs +12 -0
  332. data/sig/pvectl/commands/get/command.rbs +42 -0
  333. data/sig/pvectl/commands/get/handlers/backups.rbs +23 -0
  334. data/sig/pvectl/commands/get/handlers/capabilities.rbs +29 -0
  335. data/sig/pvectl/commands/get/handlers/containers.rbs +35 -0
  336. data/sig/pvectl/commands/get/handlers/disks.rbs +27 -0
  337. data/sig/pvectl/commands/get/handlers/dns.rbs +25 -0
  338. data/sig/pvectl/commands/get/handlers/hosts.rbs +25 -0
  339. data/sig/pvectl/commands/get/handlers/nodes.rbs +33 -0
  340. data/sig/pvectl/commands/get/handlers/services.rbs +23 -0
  341. data/sig/pvectl/commands/get/handlers/snapshots.rbs +27 -0
  342. data/sig/pvectl/commands/get/handlers/storage.rbs +25 -0
  343. data/sig/pvectl/commands/get/handlers/subscription.rbs +25 -0
  344. data/sig/pvectl/commands/get/handlers/tasks.rbs +28 -0
  345. data/sig/pvectl/commands/get/handlers/templates.rbs +35 -0
  346. data/sig/pvectl/commands/get/handlers/time.rbs +29 -0
  347. data/sig/pvectl/commands/get/handlers/vms.rbs +35 -0
  348. data/sig/pvectl/commands/get/handlers/volume.rbs +27 -0
  349. data/sig/pvectl/commands/get/resource_handler.rbs +13 -0
  350. data/sig/pvectl/commands/get/resource_registry.rbs +8 -0
  351. data/sig/pvectl/commands/get/watch_loop.rbs +33 -0
  352. data/sig/pvectl/commands/irreversible_command.rbs +32 -0
  353. data/sig/pvectl/commands/logs/command.rbs +35 -0
  354. data/sig/pvectl/commands/logs/handlers/journal.rbs +21 -0
  355. data/sig/pvectl/commands/logs/handlers/syslog.rbs +21 -0
  356. data/sig/pvectl/commands/logs/handlers/task_detail.rbs +21 -0
  357. data/sig/pvectl/commands/logs/handlers/task_logs.rbs +35 -0
  358. data/sig/pvectl/commands/logs/resource_handler.rbs +11 -0
  359. data/sig/pvectl/commands/logs/resource_registry.rbs +8 -0
  360. data/sig/pvectl/commands/migrate_command.rbs +45 -0
  361. data/sig/pvectl/commands/migrate_container.rbs +11 -0
  362. data/sig/pvectl/commands/migrate_vm.rbs +13 -0
  363. data/sig/pvectl/commands/move_disk_command.rbs +43 -0
  364. data/sig/pvectl/commands/move_disk_container.rbs +11 -0
  365. data/sig/pvectl/commands/move_disk_vm.rbs +13 -0
  366. data/sig/pvectl/commands/ping.rbs +39 -0
  367. data/sig/pvectl/commands/pull.rbs +33 -0
  368. data/sig/pvectl/commands/push.rbs +32 -0
  369. data/sig/pvectl/commands/reset.rbs +11 -0
  370. data/sig/pvectl/commands/resource_lifecycle_command.rbs +55 -0
  371. data/sig/pvectl/commands/resource_registry.rbs +19 -0
  372. data/sig/pvectl/commands/restart.rbs +11 -0
  373. data/sig/pvectl/commands/restart_container.rbs +9 -0
  374. data/sig/pvectl/commands/restore_backup.rbs +27 -0
  375. data/sig/pvectl/commands/resume.rbs +11 -0
  376. data/sig/pvectl/commands/rollback_snapshot.rbs +31 -0
  377. data/sig/pvectl/commands/sendkey_vm.rbs +25 -0
  378. data/sig/pvectl/commands/service.rbs +38 -0
  379. data/sig/pvectl/commands/set_container.rbs +13 -0
  380. data/sig/pvectl/commands/set_node.rbs +13 -0
  381. data/sig/pvectl/commands/set_resource_command.rbs +25 -0
  382. data/sig/pvectl/commands/set_vm.rbs +15 -0
  383. data/sig/pvectl/commands/set_volume.rbs +24 -0
  384. data/sig/pvectl/commands/shared_config_parsers.rbs +19 -0
  385. data/sig/pvectl/commands/shared_flags.rbs +10 -0
  386. data/sig/pvectl/commands/shutdown.rbs +11 -0
  387. data/sig/pvectl/commands/shutdown_container.rbs +9 -0
  388. data/sig/pvectl/commands/start.rbs +11 -0
  389. data/sig/pvectl/commands/start_container.rbs +9 -0
  390. data/sig/pvectl/commands/stop.rbs +11 -0
  391. data/sig/pvectl/commands/stop_container.rbs +9 -0
  392. data/sig/pvectl/commands/suspend.rbs +11 -0
  393. data/sig/pvectl/commands/template_command.rbs +21 -0
  394. data/sig/pvectl/commands/template_container.rbs +10 -0
  395. data/sig/pvectl/commands/template_vm.rbs +12 -0
  396. data/sig/pvectl/commands/top/command.rbs +31 -0
  397. data/sig/pvectl/commands/top/handlers/containers.rbs +21 -0
  398. data/sig/pvectl/commands/top/handlers/nodes.rbs +21 -0
  399. data/sig/pvectl/commands/top/handlers/vms.rbs +21 -0
  400. data/sig/pvectl/commands/top/resource_handler.rbs +11 -0
  401. data/sig/pvectl/commands/top/resource_registry.rbs +8 -0
  402. data/sig/pvectl/commands/unlink_disk_vm.rbs +27 -0
  403. data/sig/pvectl/commands/vm_lifecycle_command.rbs +25 -0
  404. data/sig/pvectl/commands/wakeonlan_node.rbs +21 -0
  405. data/sig/pvectl/config/errors.rbs +24 -0
  406. data/sig/pvectl/config/models/cluster.rbs +39 -0
  407. data/sig/pvectl/config/models/context.rbs +23 -0
  408. data/sig/pvectl/config/models/resolved_config.rbs +51 -0
  409. data/sig/pvectl/config/models/user.rbs +31 -0
  410. data/sig/pvectl/config/provider.rbs +40 -0
  411. data/sig/pvectl/config/service.rbs +65 -0
  412. data/sig/pvectl/config/store.rbs +14 -0
  413. data/sig/pvectl/config/wizard.rbs +48 -0
  414. data/sig/pvectl/config_serializer.rbs +121 -0
  415. data/sig/pvectl/connection/retry_handler.rbs +31 -0
  416. data/sig/pvectl/connection.rbs +35 -0
  417. data/sig/pvectl/console/terminal_session.rbs +63 -0
  418. data/sig/pvectl/editor_session.rbs +33 -0
  419. data/sig/pvectl/exit_codes.rbs +19 -0
  420. data/sig/pvectl/formatters/base.rbs +13 -0
  421. data/sig/pvectl/formatters/color_support.rbs +13 -0
  422. data/sig/pvectl/formatters/json.rbs +7 -0
  423. data/sig/pvectl/formatters/output_helper.rbs +9 -0
  424. data/sig/pvectl/formatters/registry.rbs +13 -0
  425. data/sig/pvectl/formatters/table.rbs +25 -0
  426. data/sig/pvectl/formatters/wide.rbs +15 -0
  427. data/sig/pvectl/formatters/yaml.rbs +7 -0
  428. data/sig/pvectl/manifest_serializer.rbs +18 -0
  429. data/sig/pvectl/models/apt_package.rbs +26 -0
  430. data/sig/pvectl/models/backup.rbs +31 -0
  431. data/sig/pvectl/models/base.rbs +11 -0
  432. data/sig/pvectl/models/capability.rbs +16 -0
  433. data/sig/pvectl/models/container.rbs +44 -0
  434. data/sig/pvectl/models/container_operation_result.rbs +9 -0
  435. data/sig/pvectl/models/dns_config.rbs +15 -0
  436. data/sig/pvectl/models/hosts_file.rbs +13 -0
  437. data/sig/pvectl/models/journal_entry.rbs +10 -0
  438. data/sig/pvectl/models/network_interface.rbs +20 -0
  439. data/sig/pvectl/models/node.rbs +47 -0
  440. data/sig/pvectl/models/node_operation_result.rbs +12 -0
  441. data/sig/pvectl/models/operation_result.rbs +21 -0
  442. data/sig/pvectl/models/physical_disk.rbs +35 -0
  443. data/sig/pvectl/models/service.rbs +18 -0
  444. data/sig/pvectl/models/snapshot.rbs +21 -0
  445. data/sig/pvectl/models/snapshot_description.rbs +18 -0
  446. data/sig/pvectl/models/storage.rbs +39 -0
  447. data/sig/pvectl/models/subscription.rbs +24 -0
  448. data/sig/pvectl/models/syslog_entry.rbs +10 -0
  449. data/sig/pvectl/models/task.rbs +22 -0
  450. data/sig/pvectl/models/task_entry.rbs +24 -0
  451. data/sig/pvectl/models/task_log_line.rbs +10 -0
  452. data/sig/pvectl/models/time_config.rbs +12 -0
  453. data/sig/pvectl/models/vm.rbs +32 -0
  454. data/sig/pvectl/models/vm_operation_result.rbs +9 -0
  455. data/sig/pvectl/models/volume.rbs +29 -0
  456. data/sig/pvectl/models/volume_operation_result.rbs +9 -0
  457. data/sig/pvectl/parsers/cloud_init_config.rbs +15 -0
  458. data/sig/pvectl/parsers/disk_config.rbs +19 -0
  459. data/sig/pvectl/parsers/lxc_mount_config.rbs +19 -0
  460. data/sig/pvectl/parsers/lxc_net_config.rbs +19 -0
  461. data/sig/pvectl/parsers/net_config.rbs +19 -0
  462. data/sig/pvectl/parsers/smart_text.rbs +7 -0
  463. data/sig/pvectl/plugin_loader.rbs +25 -0
  464. data/sig/pvectl/presenters/apt_package.rbs +19 -0
  465. data/sig/pvectl/presenters/backup.rbs +25 -0
  466. data/sig/pvectl/presenters/base.rbs +41 -0
  467. data/sig/pvectl/presenters/capability.rbs +19 -0
  468. data/sig/pvectl/presenters/config/context.rbs +17 -0
  469. data/sig/pvectl/presenters/container.rbs +78 -0
  470. data/sig/pvectl/presenters/container_operation_result.rbs +19 -0
  471. data/sig/pvectl/presenters/disk.rbs +31 -0
  472. data/sig/pvectl/presenters/dns_config.rbs +13 -0
  473. data/sig/pvectl/presenters/hosts_file.rbs +13 -0
  474. data/sig/pvectl/presenters/journal_entry.rbs +11 -0
  475. data/sig/pvectl/presenters/node.rbs +118 -0
  476. data/sig/pvectl/presenters/node_operation_result.rbs +11 -0
  477. data/sig/pvectl/presenters/operation_result.rbs +17 -0
  478. data/sig/pvectl/presenters/service.rbs +15 -0
  479. data/sig/pvectl/presenters/snapshot.rbs +35 -0
  480. data/sig/pvectl/presenters/snapshot_operation_result.rbs +27 -0
  481. data/sig/pvectl/presenters/storage.rbs +59 -0
  482. data/sig/pvectl/presenters/subscription.rbs +36 -0
  483. data/sig/pvectl/presenters/syslog_entry.rbs +11 -0
  484. data/sig/pvectl/presenters/task_entry.rbs +21 -0
  485. data/sig/pvectl/presenters/task_log_line.rbs +11 -0
  486. data/sig/pvectl/presenters/template.rbs +15 -0
  487. data/sig/pvectl/presenters/time_config.rbs +19 -0
  488. data/sig/pvectl/presenters/top_container.rbs +17 -0
  489. data/sig/pvectl/presenters/top_node.rbs +17 -0
  490. data/sig/pvectl/presenters/top_presenter.rbs +13 -0
  491. data/sig/pvectl/presenters/top_vm.rbs +17 -0
  492. data/sig/pvectl/presenters/vm.rbs +91 -0
  493. data/sig/pvectl/presenters/vm_operation_result.rbs +19 -0
  494. data/sig/pvectl/presenters/volume.rbs +23 -0
  495. data/sig/pvectl/presenters/volume_operation_result.rbs +11 -0
  496. data/sig/pvectl/repositories/apt.rbs +17 -0
  497. data/sig/pvectl/repositories/backup.rbs +27 -0
  498. data/sig/pvectl/repositories/base.rbs +23 -0
  499. data/sig/pvectl/repositories/capabilities.rbs +20 -0
  500. data/sig/pvectl/repositories/container.rbs +63 -0
  501. data/sig/pvectl/repositories/disk.rbs +17 -0
  502. data/sig/pvectl/repositories/dns.rbs +13 -0
  503. data/sig/pvectl/repositories/hosts.rbs +13 -0
  504. data/sig/pvectl/repositories/journal.rbs +7 -0
  505. data/sig/pvectl/repositories/node.rbs +68 -0
  506. data/sig/pvectl/repositories/service.rbs +27 -0
  507. data/sig/pvectl/repositories/snapshot.rbs +19 -0
  508. data/sig/pvectl/repositories/storage.rbs +37 -0
  509. data/sig/pvectl/repositories/subscription.rbs +17 -0
  510. data/sig/pvectl/repositories/syslog.rbs +7 -0
  511. data/sig/pvectl/repositories/task.rbs +19 -0
  512. data/sig/pvectl/repositories/task_list.rbs +7 -0
  513. data/sig/pvectl/repositories/task_log.rbs +11 -0
  514. data/sig/pvectl/repositories/time_config.rbs +13 -0
  515. data/sig/pvectl/repositories/vm.rbs +85 -0
  516. data/sig/pvectl/repositories/volume.rbs +43 -0
  517. data/sig/pvectl/selectors/base.rbs +37 -0
  518. data/sig/pvectl/selectors/container.rbs +19 -0
  519. data/sig/pvectl/selectors/disk.rbs +13 -0
  520. data/sig/pvectl/selectors/vm.rbs +19 -0
  521. data/sig/pvectl/selectors/volume.rbs +13 -0
  522. data/sig/pvectl/services/backup.rbs +27 -0
  523. data/sig/pvectl/services/clone_container.rbs +35 -0
  524. data/sig/pvectl/services/clone_vm.rbs +35 -0
  525. data/sig/pvectl/services/cloudinit.rbs +19 -0
  526. data/sig/pvectl/services/console.rbs +23 -0
  527. data/sig/pvectl/services/container_lifecycle.rbs +26 -0
  528. data/sig/pvectl/services/create_container.rbs +64 -0
  529. data/sig/pvectl/services/create_vm.rbs +72 -0
  530. data/sig/pvectl/services/edit_container.rbs +17 -0
  531. data/sig/pvectl/services/edit_dns.rbs +23 -0
  532. data/sig/pvectl/services/edit_hosts.rbs +13 -0
  533. data/sig/pvectl/services/edit_node.rbs +21 -0
  534. data/sig/pvectl/services/edit_vm.rbs +17 -0
  535. data/sig/pvectl/services/edit_volume.rbs +18 -0
  536. data/sig/pvectl/services/get/resource_service.rbs +23 -0
  537. data/sig/pvectl/services/move_disk.rbs +21 -0
  538. data/sig/pvectl/services/pull_config.rbs +18 -0
  539. data/sig/pvectl/services/push_config.rbs +37 -0
  540. data/sig/pvectl/services/resize_volume.rbs +47 -0
  541. data/sig/pvectl/services/resource_delete.rbs +27 -0
  542. data/sig/pvectl/services/resource_migration.rbs +29 -0
  543. data/sig/pvectl/services/sendkey.rbs +19 -0
  544. data/sig/pvectl/services/service_lifecycle.rbs +17 -0
  545. data/sig/pvectl/services/set_container.rbs +14 -0
  546. data/sig/pvectl/services/set_node.rbs +23 -0
  547. data/sig/pvectl/services/set_vm.rbs +14 -0
  548. data/sig/pvectl/services/set_volume.rbs +12 -0
  549. data/sig/pvectl/services/snapshot.rbs +35 -0
  550. data/sig/pvectl/services/task_listing.rbs +13 -0
  551. data/sig/pvectl/services/unlink_disk.rbs +17 -0
  552. data/sig/pvectl/services/vm_lifecycle.rbs +26 -0
  553. data/sig/pvectl/services/wakeonlan.rbs +17 -0
  554. data/sig/pvectl/utils/resource_resolver.rbs +17 -0
  555. data/sig/pvectl/wizards/create_container.rbs +21 -0
  556. data/sig/pvectl/wizards/create_vm.rbs +21 -0
  557. data/sig/pvectl.rbs +9 -0
  558. metadata +675 -0
@@ -0,0 +1,205 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl sendkey vm` command.
6
+ #
7
+ # Sends a single QEMU monitor key event to a running VM. The key string
8
+ # uses QEMU's qcode format (e.g., +ctrl-alt-delete+, +ret+, +f1+) and is
9
+ # forwarded verbatim to the Proxmox API.
10
+ #
11
+ # @example Send Ctrl+Alt+Delete to VM 100
12
+ # pvectl sendkey vm 100 ctrl-alt-delete
13
+ #
14
+ # @example Send Enter to VM 100
15
+ # pvectl sendkey vm 100 ret
16
+ #
17
+ class SendkeyVm
18
+ # Registers the sendkey command with the CLI.
19
+ #
20
+ # @param cli [GLI::App] the CLI application object
21
+ # @return [void]
22
+ def self.register(cli)
23
+ cli.desc "Send a QEMU monitor key event to a VM"
24
+ cli.long_desc <<~HELP
25
+ Send a single QEMU monitor key event to a running virtual machine.
26
+ The key string is forwarded verbatim to the Proxmox API and is
27
+ interpreted by QEMU using its qcode key format.
28
+
29
+ Common key codes:
30
+ - ctrl-alt-delete Reboot signal (Linux/Windows)
31
+ - ctrl-alt-f1..f6 Switch Linux virtual terminals
32
+ - ret Enter / Return
33
+ - esc Escape
34
+ - tab, spc, backspace
35
+
36
+ Single character keys (letters, digits) are also accepted as-is.
37
+
38
+ EXAMPLES
39
+ Trigger Ctrl+Alt+Del on a running VM:
40
+ $ pvectl sendkey vm 100 ctrl-alt-delete
41
+
42
+ Send Enter (e.g., dismiss a bootloader prompt):
43
+ $ pvectl sendkey vm 100 ret
44
+
45
+ Send Escape:
46
+ $ pvectl sendkey vm 100 esc
47
+
48
+ Switch to TTY 1 on a Linux guest:
49
+ $ pvectl sendkey vm 100 ctrl-alt-f1
50
+
51
+ Resolve VM on a specific node:
52
+ $ pvectl sendkey vm 100 ret --node pve1
53
+
54
+ NOTES
55
+ Only VMs are supported — LXC containers do not have a QEMU monitor.
56
+
57
+ The VM must be running. If it is not, the command exits with an
58
+ error before issuing the API call.
59
+
60
+ Composite keys are dash-separated qcodes (e.g., "ctrl-alt-f1"),
61
+ not the literal "+" notation. Refer to QEMU's qcode reference
62
+ for the full list.
63
+
64
+ SEE ALSO
65
+ pvectl help console vm Interactive console (recommended for
66
+ sustained typing)
67
+ pvectl help start Start a stopped VM
68
+ HELP
69
+ cli.arg_name "RESOURCE_TYPE ID KEY"
70
+ cli.command :sendkey do |c|
71
+ c.desc "Node hosting the VM (used to disambiguate lookup)"
72
+ c.flag [:node, :n], arg_name: "NODE"
73
+
74
+ c.action do |global_options, options, args|
75
+ resource_type = args.shift
76
+
77
+ exit_code = case resource_type
78
+ when "vm"
79
+ SendkeyVm.execute(args, options, global_options)
80
+ else
81
+ $stderr.puts "Error: Unknown resource type: #{resource_type}"
82
+ $stderr.puts "Valid types: vm"
83
+ ExitCodes::USAGE_ERROR
84
+ end
85
+
86
+ exit exit_code if exit_code != 0
87
+ end
88
+ end
89
+ end
90
+
91
+ # Executes the sendkey VM command.
92
+ #
93
+ # @param args [Array<String>] command arguments (VMID KEY)
94
+ # @param options [Hash] command options
95
+ # @param global_options [Hash] global CLI options
96
+ # @return [Integer] exit code
97
+ def self.execute(args, options, global_options)
98
+ new(args, options, global_options).execute
99
+ end
100
+
101
+ # Initializes a sendkey VM command.
102
+ #
103
+ # @param args [Array<String>] command arguments
104
+ # @param options [Hash] command options
105
+ # @param global_options [Hash] global CLI options
106
+ def initialize(args, options, global_options)
107
+ @args = Array(args)
108
+ @options = options || {}
109
+ @global_options = global_options || {}
110
+ end
111
+
112
+ # Executes the sendkey VM command.
113
+ #
114
+ # @return [Integer] exit code
115
+ def execute
116
+ vmid_arg = @args[0]
117
+ key = @args[1]
118
+
119
+ return usage_error("VMID is required") if vmid_arg.nil? || vmid_arg.to_s.strip.empty?
120
+ return usage_error("VMID must be numeric: #{vmid_arg}") unless vmid_arg.to_s.match?(/\A\d+\z/)
121
+ return usage_error("key argument is required") if key.nil? || key.to_s.strip.empty?
122
+
123
+ perform_sendkey(vmid_arg.to_i, key)
124
+ end
125
+
126
+ private
127
+
128
+ # Loads the config, builds the service, and dispatches the call.
129
+ #
130
+ # @param vmid [Integer] VM identifier
131
+ # @param key [String] key sequence
132
+ # @return [Integer] exit code
133
+ def perform_sendkey(vmid, key)
134
+ load_config
135
+ connection = Pvectl::Connection.new(@config)
136
+ vm_repo = Pvectl::Repositories::Vm.new(connection)
137
+
138
+ service = Pvectl::Services::Sendkey.new(vm_repository: vm_repo)
139
+ result = service.execute(vmid: vmid, key: key, node: @options[:node])
140
+
141
+ output_result(result)
142
+
143
+ return ExitCodes::NOT_FOUND if vm_not_found?(result)
144
+
145
+ result.failed? ? ExitCodes::GENERAL_ERROR : ExitCodes::SUCCESS
146
+ rescue Pvectl::Config::ConfigNotFoundError,
147
+ Pvectl::Config::InvalidConfigError,
148
+ Pvectl::Config::ContextNotFoundError,
149
+ Pvectl::Config::ClusterNotFoundError,
150
+ Pvectl::Config::UserNotFoundError
151
+ raise
152
+ rescue StandardError => e
153
+ $stderr.puts "Error: #{e.message}"
154
+ ExitCodes::GENERAL_ERROR
155
+ end
156
+
157
+ # Detects the "VM not found" failure case.
158
+ #
159
+ # @param result [Models::VmOperationResult]
160
+ # @return [Boolean]
161
+ def vm_not_found?(result)
162
+ result.failed? && result.vm.nil? && result.error.to_s.include?("not found")
163
+ end
164
+
165
+ # Loads configuration from file or environment.
166
+ #
167
+ # @return [void]
168
+ def load_config
169
+ service = Pvectl::Config::Service.new
170
+ service.load(config: @global_options[:config])
171
+ @config = service.current_config
172
+ end
173
+
174
+ # Outputs the operation result using the configured formatter.
175
+ #
176
+ # @param result [Models::VmOperationResult]
177
+ # @return [void]
178
+ def output_result(result)
179
+ # When the VM could not be resolved we have no VM info — write a
180
+ # plain stderr error instead of a presenter row referencing nil.
181
+ if result.failed? && result.vm.nil?
182
+ $stderr.puts "Error: #{result.error}"
183
+ return
184
+ end
185
+
186
+ presenter = Pvectl::Presenters::VmOperationResult.new
187
+ format = @global_options[:output] || "table"
188
+ color_flag = @global_options[:color]
189
+
190
+ formatter = Pvectl::Formatters::Registry.for(format)
191
+ output = formatter.format([result], presenter, color: color_flag)
192
+ puts output
193
+ end
194
+
195
+ # Writes a usage error and returns the exit code.
196
+ #
197
+ # @param message [String]
198
+ # @return [Integer]
199
+ def usage_error(message)
200
+ $stderr.puts "Error: #{message}"
201
+ ExitCodes::USAGE_ERROR
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,293 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Top-level `pvectl service` command for managing systemd services on
6
+ # Proxmox nodes.
7
+ #
8
+ # Exposes four lifecycle sub-commands:
9
+ #
10
+ # * `service start <name>` start a service
11
+ # * `service stop <name>` stop a service (irreversible — requires --yes or prompt)
12
+ # * `service restart <name>` hard restart a service (irreversible — requires --yes or prompt)
13
+ # * `service reload <name>` reload (graceful where supported)
14
+ #
15
+ # Each sub-command requires `--node NODE` (falls back to default-node from
16
+ # the active context configuration when not provided).
17
+ #
18
+ # @example Register with the CLI
19
+ # Commands::Service.register(cli)
20
+ #
21
+ class Service
22
+ # All confirmable operations (stop and restart can disrupt running workloads).
23
+ CONFIRMABLE_OPERATIONS = %i[stop restart].freeze
24
+
25
+ # All supported operations.
26
+ OPERATIONS = %i[start stop restart reload].freeze
27
+
28
+ # Registers the service command and all sub-commands with the CLI.
29
+ #
30
+ # @param cli [GLI::App] the CLI application object
31
+ # @return [void]
32
+ def self.register(cli)
33
+ cli.desc "Manage systemd services on Proxmox nodes"
34
+ cli.long_desc <<~HELP
35
+ Manage systemd services running on Proxmox VE nodes. Wraps the Proxmox
36
+ /nodes/{node}/services API to start, stop, restart, or reload daemons
37
+ such as pveproxy, pvedaemon, corosync, and others.
38
+
39
+ SUB-COMMANDS
40
+ service start NAME Start a stopped service
41
+ service stop NAME Stop a running service (irreversible)
42
+ service restart NAME Hard restart a service (irreversible)
43
+ service reload NAME Reload a service (graceful where supported)
44
+
45
+ EXAMPLES
46
+ Restart the API proxy on a single node (with confirmation skipped):
47
+ $ pvectl service restart pveproxy --node pve1 --yes
48
+
49
+ Start a stopped service on the default node:
50
+ $ pvectl service start cron
51
+
52
+ Stop a service after interactive confirmation:
53
+ $ pvectl service stop pve-firewall --node pve1
54
+
55
+ Reload the syslog daemon (no interruption to running workloads):
56
+ $ pvectl service reload syslog --node pve1
57
+
58
+ NOTES
59
+ --node defaults to the context's default-node if configured.
60
+
61
+ stop and restart are irreversible and require either an interactive
62
+ "yes" confirmation or the --yes flag to skip the prompt.
63
+
64
+ Restarting pveproxy or corosync can momentarily disconnect the
65
+ current API session and break cluster membership respectively. Use
66
+ --yes only when you understand the impact.
67
+
68
+ Operations are asynchronous — the result includes the Proxmox task
69
+ UPID which can be inspected with `pvectl get tasks` and
70
+ `pvectl logs task UPID`.
71
+
72
+ SEE ALSO
73
+ pvectl help get List resources (try `get services`)
74
+ pvectl help logs Inspect task output
75
+ HELP
76
+ cli.command :service do |c|
77
+ # Shared flags declared on the parent so all subcommands inherit them.
78
+ # Avoids GLI flag-redefinition errors when the same flag is needed by
79
+ # multiple sibling subcommands (e.g. start/stop/restart/reload all
80
+ # need --node and --yes).
81
+ c.desc "Node name (defaults to context default-node)"
82
+ c.flag [:node], arg_name: "NODE"
83
+
84
+ c.desc "Skip interactive confirmation prompt"
85
+ c.switch [:yes, :y], negatable: false
86
+
87
+ OPERATIONS.each do |op|
88
+ register_subcommand(c, op)
89
+ end
90
+ end
91
+ end
92
+
93
+ # Registers a single lifecycle sub-command.
94
+ #
95
+ # @param parent [GLI::Command] parent service command
96
+ # @param operation [Symbol] one of :start, :stop, :restart, :reload
97
+ # @return [void]
98
+ def self.register_subcommand(parent, operation)
99
+ parent.desc "#{operation.capitalize} a systemd service on a Proxmox node"
100
+ parent.long_desc subcommand_long_desc(operation)
101
+ parent.arg_name "SERVICE_NAME"
102
+ parent.command operation do |sub|
103
+ sub.action do |global_options, options, args|
104
+ exit_code = execute(operation, args, options, global_options)
105
+ exit exit_code if exit_code != 0
106
+ end
107
+ end
108
+ end
109
+
110
+ # Builds the man-page-style long_desc for a sub-command.
111
+ #
112
+ # @param operation [Symbol] operation
113
+ # @return [String] long help text
114
+ def self.subcommand_long_desc(operation)
115
+ action = operation.to_s
116
+ confirm_note =
117
+ if CONFIRMABLE_OPERATIONS.include?(operation)
118
+ "This operation is irreversible. Without --yes, pvectl will\n prompt for interactive confirmation before contacting the API."
119
+ else
120
+ "No confirmation is required for this operation."
121
+ end
122
+
123
+ <<~HELP
124
+ #{action.capitalize} a systemd service on a Proxmox node.
125
+
126
+ EXAMPLES
127
+ $ pvectl service #{action} pveproxy --node pve1
128
+ $ pvectl service #{action} pveproxy --node pve1 --yes
129
+
130
+ NOTES
131
+ #{confirm_note}
132
+
133
+ Restarting pveproxy or corosync can momentarily disconnect the
134
+ current API session and break cluster membership respectively.
135
+
136
+ --node defaults to the context's default-node.
137
+
138
+ SEE ALSO
139
+ pvectl help service Parent command
140
+ pvectl help get List resources (try `get services`)
141
+ HELP
142
+ end
143
+
144
+ # Executes the command.
145
+ #
146
+ # @param operation [Symbol] operation (:start, :stop, :restart, :reload)
147
+ # @param args [Array<String>] positional CLI arguments
148
+ # @param options [Hash] command options
149
+ # @param global_options [Hash] global CLI options
150
+ # @return [Integer] exit code
151
+ def self.execute(operation, args, options, global_options)
152
+ new(operation, args, options, global_options).execute
153
+ end
154
+
155
+ # Initializes a service lifecycle command.
156
+ #
157
+ # @param operation [Symbol] operation
158
+ # @param args [Array<String>] positional CLI arguments
159
+ # @param options [Hash] command options
160
+ # @param global_options [Hash] global CLI options
161
+ # @param prompt [IO] IO for confirmation prompts (default: $stdin)
162
+ # @param output [IO] IO for output (default: $stdout)
163
+ def initialize(operation, args, options, global_options, prompt: $stdin, output: $stdout)
164
+ @operation = operation
165
+ @args = Array(args).compact
166
+ @options = options
167
+ @global_options = global_options
168
+ @prompt = prompt
169
+ @output = output
170
+ end
171
+
172
+ # Executes the command.
173
+ #
174
+ # @return [Integer] exit code
175
+ def execute
176
+ return usage_error("service name is required") if @args.empty?
177
+
178
+ service_name = @args.first
179
+ load_config
180
+ node = resolve_node
181
+ return config_error("node is required (provide --node or configure default-node)") unless node
182
+
183
+ return ExitCodes::SUCCESS unless confirm!(service_name, node)
184
+
185
+ result = perform(service_name, node)
186
+ output_result(result)
187
+ result.failed? ? ExitCodes::GENERAL_ERROR : ExitCodes::SUCCESS
188
+ rescue Pvectl::Config::ConfigNotFoundError,
189
+ Pvectl::Config::InvalidConfigError,
190
+ Pvectl::Config::ContextNotFoundError,
191
+ Pvectl::Config::ClusterNotFoundError,
192
+ Pvectl::Config::UserNotFoundError => e
193
+ $stderr.puts "Error: #{e.message}"
194
+ ExitCodes::CONFIG_ERROR
195
+ rescue StandardError => e
196
+ $stderr.puts "Error: #{e.message}"
197
+ ExitCodes::GENERAL_ERROR
198
+ end
199
+
200
+ private
201
+
202
+ # Loads configuration.
203
+ #
204
+ # @return [void]
205
+ def load_config
206
+ service = Pvectl::Config::Service.new
207
+ service.load(config: @global_options[:config])
208
+ @config = service.current_config
209
+ end
210
+
211
+ # Resolves the node from --node option or default-node config.
212
+ #
213
+ # @return [String, nil] node name or nil if unresolvable
214
+ def resolve_node
215
+ @options[:node] || @config&.default_node
216
+ end
217
+
218
+ # Confirms the operation when required.
219
+ #
220
+ # @param service_name [String] service identifier
221
+ # @param node [String] node name
222
+ # @return [Boolean] true if operation should proceed
223
+ def confirm!(service_name, node)
224
+ return true unless CONFIRMABLE_OPERATIONS.include?(@operation)
225
+ return true if @options[:yes]
226
+
227
+ warning = service_warning(service_name)
228
+ @output.puts "About to #{@operation} service '#{service_name}' on node '#{node}'."
229
+ @output.puts warning if warning
230
+ @output.print "Continue? [y/N] "
231
+ answer = @prompt.gets&.strip&.downcase
232
+ confirmed = %w[y yes].include?(answer)
233
+ @output.puts "Aborted." unless confirmed
234
+ confirmed
235
+ end
236
+
237
+ # Returns a warning string for sensitive services, or nil.
238
+ #
239
+ # @param service_name [String] service identifier
240
+ # @return [String, nil] warning
241
+ def service_warning(service_name)
242
+ case service_name
243
+ when "pveproxy", "pvedaemon"
244
+ "Warning: this may disconnect the current API session."
245
+ when "corosync", "pve-cluster"
246
+ "Warning: this can disrupt cluster membership and quorum."
247
+ end
248
+ end
249
+
250
+ # Performs the API call via ServiceLifecycle.
251
+ #
252
+ # @param service_name [String] service identifier
253
+ # @param node [String] node name
254
+ # @return [Models::NodeOperationResult]
255
+ def perform(service_name, node)
256
+ connection = Pvectl::Connection.new(@config)
257
+ repository = Pvectl::Repositories::Service.new(connection)
258
+ lifecycle = Pvectl::Services::ServiceLifecycle.new(service_repository: repository)
259
+ lifecycle.execute(operation: @operation, node: node, service: service_name)
260
+ end
261
+
262
+ # Outputs the operation result using the configured formatter.
263
+ #
264
+ # @param result [Models::NodeOperationResult]
265
+ # @return [void]
266
+ def output_result(result)
267
+ format = @global_options[:output] || "table"
268
+ color = @global_options[:color]
269
+ formatter = Pvectl::Formatters::Registry.for(format)
270
+ presenter = Pvectl::Presenters::NodeOperationResult.new
271
+ @output.puts formatter.format([result], presenter, color: color)
272
+ end
273
+
274
+ # Outputs a usage error.
275
+ #
276
+ # @param message [String] error message
277
+ # @return [Integer] USAGE_ERROR exit code
278
+ def usage_error(message)
279
+ $stderr.puts "Error: #{message}"
280
+ ExitCodes::USAGE_ERROR
281
+ end
282
+
283
+ # Outputs a config error.
284
+ #
285
+ # @param message [String] error message
286
+ # @return [Integer] CONFIG_ERROR exit code
287
+ def config_error(message)
288
+ $stderr.puts "Error: #{message}"
289
+ ExitCodes::CONFIG_ERROR
290
+ end
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl set container` command.
6
+ #
7
+ # Includes SetResourceCommand for shared workflow and overrides
8
+ # template methods with container-specific behavior.
9
+ #
10
+ # @example Basic usage
11
+ # pvectl set container 200 memory=2048 hostname=web01
12
+ #
13
+ class SetContainer
14
+ include SetResourceCommand
15
+
16
+ private
17
+
18
+ # @return [String] human label for container resources
19
+ def resource_label
20
+ "container"
21
+ end
22
+
23
+ # @return [String] human label for container IDs
24
+ def resource_id_label
25
+ "CTID"
26
+ end
27
+
28
+ # Builds execution parameters from a container ID.
29
+ #
30
+ # @param resource_id [String] CTID
31
+ # @param key_values [Hash] parsed key-value pairs
32
+ # @return [Hash] parameters for the set service
33
+ def execute_params(resource_id, key_values)
34
+ { ctid: resource_id.to_i, params: key_values }
35
+ end
36
+
37
+ # Builds the container set service.
38
+ #
39
+ # @param connection [Connection] API connection
40
+ # @return [Services::SetContainer] container set service
41
+ def build_set_service(connection)
42
+ ct_repo = Pvectl::Repositories::Container.new(connection)
43
+ Pvectl::Services::SetContainer.new(
44
+ container_repository: ct_repo,
45
+ options: service_options
46
+ )
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ # Handler for the `pvectl set node` command.
6
+ #
7
+ # Includes SetResourceCommand for shared workflow and overrides
8
+ # template methods with node-specific behavior.
9
+ #
10
+ # @example Basic usage
11
+ # pvectl set node pve1 description="Production node"
12
+ #
13
+ class SetNode
14
+ include SetResourceCommand
15
+
16
+ private
17
+
18
+ # @return [String] human label for node resources
19
+ def resource_label
20
+ "node"
21
+ end
22
+
23
+ # @return [String] human label for node IDs
24
+ def resource_id_label
25
+ "NODE"
26
+ end
27
+
28
+ # Builds execution parameters from a node name.
29
+ #
30
+ # @param resource_id [String] node name
31
+ # @param key_values [Hash] parsed key-value pairs
32
+ # @return [Hash] parameters for the set service
33
+ def execute_params(resource_id, key_values)
34
+ { node_name: resource_id, params: key_values }
35
+ end
36
+
37
+ # Builds the node set service.
38
+ #
39
+ # @param connection [Connection] API connection
40
+ # @return [Services::SetNode] node set service
41
+ def build_set_service(connection)
42
+ node_repo = Pvectl::Repositories::Node.new(connection)
43
+ time_repo = Pvectl::Repositories::TimeConfig.new(connection)
44
+ Pvectl::Services::SetNode.new(
45
+ node_repository: node_repo,
46
+ time_repository: time_repo,
47
+ options: service_options
48
+ )
49
+ end
50
+ end
51
+ end
52
+ end