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,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Config
5
+ module Models
6
+ # Represents a Proxmox cluster server configuration.
7
+ #
8
+ # Cluster is an immutable value object containing connection settings
9
+ # for a single Proxmox server. It stores the server URL, SSL options,
10
+ # and retry/timeout configuration.
11
+ #
12
+ # @example Creating a cluster from constructor
13
+ # cluster = Cluster.new(
14
+ # name: "production",
15
+ # server: "https://pve.example.com:8006",
16
+ # verify_ssl: true,
17
+ # certificate_authority: "/path/to/ca.crt"
18
+ # )
19
+ #
20
+ # @example Creating from YAML config hash
21
+ # hash = {
22
+ # "name" => "production",
23
+ # "cluster" => {
24
+ # "server" => "https://pve.example.com:8006",
25
+ # "insecure-skip-tls-verify" => false
26
+ # }
27
+ # }
28
+ # cluster = Cluster.from_hash(hash)
29
+ #
30
+ class Cluster
31
+ # @return [String] unique name identifying this cluster
32
+ attr_reader :name
33
+
34
+ # @return [String] Proxmox server URL (e.g., "https://pve.example.com:8006")
35
+ attr_reader :server
36
+
37
+ # @return [Boolean] whether to verify SSL certificates
38
+ attr_reader :verify_ssl
39
+
40
+ # @return [String, nil] path to CA certificate file
41
+ attr_reader :certificate_authority
42
+
43
+ # @return [Integer, nil] request timeout in seconds
44
+ attr_reader :timeout
45
+
46
+ # @return [Integer, nil] maximum retry attempts
47
+ attr_reader :retry_count
48
+
49
+ # @return [Integer, nil] base delay between retries in seconds
50
+ attr_reader :retry_delay
51
+
52
+ # @return [Integer, nil] maximum delay cap for exponential backoff
53
+ attr_reader :max_retry_delay
54
+
55
+ # @return [Boolean, nil] whether to retry write operations
56
+ attr_reader :retry_writes
57
+
58
+ # Creates a new Cluster instance.
59
+ #
60
+ # @param name [String] unique name for this cluster
61
+ # @param server [String] Proxmox server URL
62
+ # @param verify_ssl [Boolean] whether to verify SSL (default: true)
63
+ # @param certificate_authority [String, nil] path to CA certificate
64
+ # @param timeout [Integer, nil] request timeout in seconds
65
+ # @param retry_count [Integer, nil] maximum retry attempts
66
+ # @param retry_delay [Integer, nil] base delay between retries
67
+ # @param max_retry_delay [Integer, nil] maximum delay cap
68
+ # @param retry_writes [Boolean, nil] whether to retry write operations
69
+ #
70
+ # @raise [InvalidConfigError] if validation fails
71
+ def initialize(name:, server:, verify_ssl: true, certificate_authority: nil,
72
+ timeout: nil, retry_count: nil, retry_delay: nil,
73
+ max_retry_delay: nil, retry_writes: nil)
74
+ @name = name
75
+ @server = server
76
+ @verify_ssl = verify_ssl
77
+ @certificate_authority = certificate_authority
78
+ @timeout = timeout
79
+ @retry_count = retry_count
80
+ @retry_delay = retry_delay
81
+ @max_retry_delay = max_retry_delay
82
+ @retry_writes = retry_writes
83
+
84
+ validate_retry_settings!
85
+ end
86
+
87
+ # Creates a Cluster from a kubeconfig-style hash structure.
88
+ #
89
+ # @param hash [Hash] hash with "name" and "cluster" keys
90
+ # @return [Cluster] new cluster instance
91
+ # @raise [InvalidConfigError] if validation fails
92
+ #
93
+ # @example Hash structure
94
+ # {
95
+ # "name" => "production",
96
+ # "cluster" => {
97
+ # "server" => "https://pve.example.com:8006",
98
+ # "insecure-skip-tls-verify" => true,
99
+ # "certificate-authority" => "/path/to/ca.crt"
100
+ # }
101
+ # }
102
+ def self.from_hash(hash)
103
+ cluster_data = hash["cluster"] || {}
104
+
105
+ new(
106
+ name: hash["name"],
107
+ server: cluster_data["server"],
108
+ verify_ssl: !cluster_data["insecure-skip-tls-verify"],
109
+ certificate_authority: cluster_data["certificate-authority"],
110
+ timeout: cluster_data["timeout"],
111
+ retry_count: cluster_data["retry-count"],
112
+ retry_delay: cluster_data["retry-delay"],
113
+ max_retry_delay: cluster_data["max-retry-delay"],
114
+ retry_writes: cluster_data["retry-writes"]
115
+ )
116
+ end
117
+
118
+ # Converts the cluster to a kubeconfig-style hash structure.
119
+ #
120
+ # @return [Hash] hash representation suitable for YAML serialization
121
+ def to_hash
122
+ cluster_data = {
123
+ "server" => server,
124
+ "insecure-skip-tls-verify" => !verify_ssl
125
+ }
126
+ cluster_data["certificate-authority"] = certificate_authority if certificate_authority
127
+ cluster_data["timeout"] = timeout if timeout
128
+ cluster_data["retry-count"] = retry_count if retry_count
129
+ cluster_data["retry-delay"] = retry_delay if retry_delay
130
+ cluster_data["max-retry-delay"] = max_retry_delay if max_retry_delay
131
+ cluster_data["retry-writes"] = retry_writes unless retry_writes.nil?
132
+
133
+ {
134
+ "name" => name,
135
+ "cluster" => cluster_data
136
+ }
137
+ end
138
+
139
+ private
140
+
141
+ # Validates retry/timeout settings.
142
+ #
143
+ # @raise [InvalidConfigError] if values are invalid
144
+ def validate_retry_settings!
145
+ validate_positive(:timeout, @timeout) if @timeout
146
+ validate_non_negative_integer(:retry_count, @retry_count) if @retry_count
147
+ validate_positive(:retry_delay, @retry_delay) if @retry_delay
148
+ validate_positive(:max_retry_delay, @max_retry_delay) if @max_retry_delay
149
+
150
+ if @retry_delay && @max_retry_delay && @max_retry_delay < @retry_delay
151
+ raise InvalidConfigError,
152
+ "max-retry-delay (#{@max_retry_delay}) must be >= retry-delay (#{@retry_delay})"
153
+ end
154
+ end
155
+
156
+ # Validates that a value is a positive number.
157
+ #
158
+ # @param name [Symbol] attribute name for error message
159
+ # @param value [Object] value to validate
160
+ # @raise [InvalidConfigError] if value is not positive
161
+ def validate_positive(name, value)
162
+ return if value.is_a?(Numeric) && value.positive?
163
+
164
+ raise InvalidConfigError, "#{name} must be a positive number, got: #{value.inspect}"
165
+ end
166
+
167
+ # Validates that a value is a non-negative integer.
168
+ #
169
+ # @param name [Symbol] attribute name for error message
170
+ # @param value [Object] value to validate
171
+ # @raise [InvalidConfigError] if value is not a non-negative integer
172
+ def validate_non_negative_integer(name, value)
173
+ return if value.is_a?(Integer) && value >= 0
174
+
175
+ raise InvalidConfigError, "#{name} must be a non-negative integer, got: #{value.inspect}"
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Config
5
+ module Models
6
+ # Represents a context linking a cluster to a user.
7
+ #
8
+ # Context is an immutable value object that binds together a cluster
9
+ # and user configuration, similar to kubectl contexts. It optionally
10
+ # includes a default node for operations.
11
+ #
12
+ # @example Creating a context
13
+ # context = Context.new(
14
+ # name: "production",
15
+ # cluster_ref: "pve-prod",
16
+ # user_ref: "admin",
17
+ # default_node: "pve1"
18
+ # )
19
+ #
20
+ # @example Creating from YAML config hash
21
+ # hash = {
22
+ # "name" => "prod",
23
+ # "context" => {
24
+ # "cluster" => "production",
25
+ # "user" => "admin-prod",
26
+ # "default-node" => "pve1"
27
+ # }
28
+ # }
29
+ # context = Context.from_hash(hash)
30
+ #
31
+ class Context
32
+ # @return [String] unique name identifying this context
33
+ attr_reader :name
34
+
35
+ # @return [String] reference to cluster name
36
+ attr_reader :cluster_ref
37
+
38
+ # @return [String] reference to user name
39
+ attr_reader :user_ref
40
+
41
+ # @return [String, nil] default node for operations
42
+ attr_reader :default_node
43
+
44
+ # Creates a new Context instance.
45
+ #
46
+ # @param name [String] unique name for this context
47
+ # @param cluster_ref [String] name of the cluster to use
48
+ # @param user_ref [String] name of the user to use
49
+ # @param default_node [String, nil] optional default node
50
+ def initialize(name:, cluster_ref:, user_ref:, default_node: nil)
51
+ @name = name
52
+ @cluster_ref = cluster_ref
53
+ @user_ref = user_ref
54
+ @default_node = default_node
55
+ end
56
+
57
+ # Creates a Context from a kubeconfig-style hash structure.
58
+ #
59
+ # @param hash [Hash] hash with "name" and "context" keys
60
+ # @return [Context] new context instance
61
+ #
62
+ # @example Hash structure
63
+ # {
64
+ # "name" => "prod",
65
+ # "context" => {
66
+ # "cluster" => "production",
67
+ # "user" => "admin-prod",
68
+ # "default-node" => "pve1"
69
+ # }
70
+ # }
71
+ def self.from_hash(hash)
72
+ context_data = hash["context"] || {}
73
+
74
+ new(
75
+ name: hash["name"],
76
+ cluster_ref: context_data["cluster"],
77
+ user_ref: context_data["user"],
78
+ default_node: context_data["default-node"]
79
+ )
80
+ end
81
+
82
+ # Converts the context to a kubeconfig-style hash structure.
83
+ #
84
+ # @return [Hash] hash representation suitable for YAML serialization
85
+ def to_hash
86
+ context_data = {
87
+ "cluster" => cluster_ref,
88
+ "user" => user_ref
89
+ }
90
+ context_data["default-node"] = default_node if default_node
91
+
92
+ {
93
+ "name" => name,
94
+ "context" => context_data
95
+ }
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Config
5
+ module Models
6
+ # Represents the final resolved configuration ready for use.
7
+ #
8
+ # ResolvedConfig is an immutable value object containing all settings
9
+ # needed to connect to a Proxmox server. It is created by merging
10
+ # configuration from file, environment variables, and CLI options.
11
+ #
12
+ # @example Creating a resolved config with token auth
13
+ # config = ResolvedConfig.new(
14
+ # context_name: "production",
15
+ # server: "https://pve.example.com:8006",
16
+ # auth_type: :token,
17
+ # token_id: "root@pam!automation",
18
+ # token_secret: "secret-uuid"
19
+ # )
20
+ #
21
+ # @example Getting connection options for proxmox-api gem
22
+ # options = config.to_connection_options
23
+ # # => { server: "https://...", token: "root@pam!automation", ... }
24
+ #
25
+ class ResolvedConfig
26
+ # Default values for retry/timeout settings
27
+ DEFAULT_TIMEOUT = 30
28
+ DEFAULT_RETRY_COUNT = 3
29
+ DEFAULT_RETRY_DELAY = 1
30
+ DEFAULT_MAX_RETRY_DELAY = 30
31
+ DEFAULT_RETRY_WRITES = false
32
+
33
+ # @return [String] name of the active context
34
+ attr_reader :context_name
35
+
36
+ # @return [String] Proxmox server URL
37
+ attr_reader :server
38
+
39
+ # @return [Boolean] whether to verify SSL certificates
40
+ attr_reader :verify_ssl
41
+
42
+ # @return [String, nil] path to CA certificate file
43
+ attr_reader :certificate_authority
44
+
45
+ # @return [Symbol] authentication type (:token or :password)
46
+ attr_reader :auth_type
47
+
48
+ # @return [String, nil] API token ID
49
+ attr_reader :token_id
50
+
51
+ # @return [String, nil] API token secret
52
+ attr_reader :token_secret
53
+
54
+ # @return [String, nil] username for password auth
55
+ attr_reader :username
56
+
57
+ # @return [String, nil] password for password auth
58
+ attr_reader :password
59
+
60
+ # @return [String, nil] default node for operations
61
+ attr_reader :default_node
62
+
63
+ # @return [Integer] request timeout in seconds
64
+ attr_reader :timeout
65
+
66
+ # @return [Integer] maximum retry attempts
67
+ attr_reader :retry_count
68
+
69
+ # @return [Integer] base delay between retries in seconds
70
+ attr_reader :retry_delay
71
+
72
+ # @return [Integer] maximum delay cap for exponential backoff
73
+ attr_reader :max_retry_delay
74
+
75
+ # @return [Boolean] whether to retry write operations
76
+ attr_reader :retry_writes
77
+
78
+ # Creates a new ResolvedConfig instance.
79
+ #
80
+ # @param context_name [String] name of the active context
81
+ # @param server [String] Proxmox server URL
82
+ # @param auth_type [Symbol] :token or :password
83
+ # @param verify_ssl [Boolean] whether to verify SSL (default: true)
84
+ # @param certificate_authority [String, nil] path to CA certificate
85
+ # @param token_id [String, nil] API token ID (required for :token auth)
86
+ # @param token_secret [String, nil] API token secret (required for :token auth)
87
+ # @param username [String, nil] username (required for :password auth)
88
+ # @param password [String, nil] password (required for :password auth)
89
+ # @param default_node [String, nil] default node for operations
90
+ # @param timeout [Integer, nil] request timeout (default: 30)
91
+ # @param retry_count [Integer, nil] max retries (default: 3)
92
+ # @param retry_delay [Integer, nil] base delay (default: 1)
93
+ # @param max_retry_delay [Integer, nil] max delay cap (default: 30)
94
+ # @param retry_writes [Boolean, nil] retry writes (default: false)
95
+ def initialize(context_name:, server:, auth_type:, verify_ssl: true,
96
+ certificate_authority: nil, token_id: nil, token_secret: nil,
97
+ username: nil, password: nil, default_node: nil,
98
+ timeout: nil, retry_count: nil, retry_delay: nil,
99
+ max_retry_delay: nil, retry_writes: nil)
100
+ @context_name = context_name
101
+ @server = server
102
+ @verify_ssl = verify_ssl
103
+ @certificate_authority = certificate_authority
104
+ @auth_type = auth_type
105
+ @token_id = token_id
106
+ @token_secret = token_secret
107
+ @username = username
108
+ @password = password
109
+ @default_node = default_node
110
+
111
+ # Apply defaults for retry/timeout settings
112
+ @timeout = timeout || DEFAULT_TIMEOUT
113
+ @retry_count = retry_count || DEFAULT_RETRY_COUNT
114
+ @retry_delay = retry_delay || DEFAULT_RETRY_DELAY
115
+ @max_retry_delay = max_retry_delay || DEFAULT_MAX_RETRY_DELAY
116
+ @retry_writes = retry_writes.nil? ? DEFAULT_RETRY_WRITES : retry_writes
117
+ end
118
+
119
+ # Checks if this config uses API token authentication.
120
+ #
121
+ # @return [Boolean] true if auth_type is :token
122
+ def token_auth?
123
+ auth_type == :token
124
+ end
125
+
126
+ # Checks if this config uses password authentication.
127
+ #
128
+ # @return [Boolean] true if auth_type is :password
129
+ def password_auth?
130
+ auth_type == :password
131
+ end
132
+
133
+ # Converts the config to options hash for proxmox-api gem.
134
+ #
135
+ # @return [Hash] options for ProxmoxAPI.new
136
+ #
137
+ # @example Token auth options
138
+ # {
139
+ # server: "https://pve.example.com:8006",
140
+ # token: "root@pam!automation",
141
+ # secret: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
142
+ # verify_ssl: false
143
+ # }
144
+ #
145
+ # @example Password auth options
146
+ # {
147
+ # server: "https://pve.example.com:8006",
148
+ # username: "root@pam",
149
+ # password: "secret",
150
+ # verify_ssl: true
151
+ # }
152
+ def to_connection_options
153
+ options = {
154
+ server: server,
155
+ verify_ssl: verify_ssl
156
+ }
157
+
158
+ if token_auth?
159
+ options[:token] = token_id
160
+ options[:secret] = token_secret
161
+ else
162
+ options[:username] = username
163
+ options[:password] = password
164
+ end
165
+
166
+ options
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Config
5
+ module Models
6
+ # Represents user credentials for Proxmox API authentication.
7
+ #
8
+ # User is an immutable value object supporting two authentication methods:
9
+ # - API Token authentication (token_id + token_secret)
10
+ # - Username/Password authentication (username + password)
11
+ #
12
+ # @example Creating a user with token authentication
13
+ # user = User.new(
14
+ # name: "admin",
15
+ # token_id: "root@pam!automation",
16
+ # token_secret: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
17
+ # )
18
+ # user.token_auth? #=> true
19
+ #
20
+ # @example Creating a user with password authentication
21
+ # user = User.new(
22
+ # name: "admin",
23
+ # username: "root@pam",
24
+ # password: "secret"
25
+ # )
26
+ # user.password_auth? #=> true
27
+ #
28
+ class User
29
+ # Mask used to hide secrets in output
30
+ SECRET_MASK = "********"
31
+
32
+ # @return [String] unique name identifying this user
33
+ attr_reader :name
34
+
35
+ # @return [String, nil] API token ID (e.g., "root@pam!tokenid")
36
+ attr_reader :token_id
37
+
38
+ # @return [String, nil] API token secret (UUID format)
39
+ attr_reader :token_secret
40
+
41
+ # @return [String, nil] username for password auth (e.g., "root@pam")
42
+ attr_reader :username
43
+
44
+ # @return [String, nil] password for password auth
45
+ attr_reader :password
46
+
47
+ # Creates a new User instance.
48
+ #
49
+ # @param name [String] unique name for this user
50
+ # @param token_id [String, nil] API token ID
51
+ # @param token_secret [String, nil] API token secret
52
+ # @param username [String, nil] username for password auth
53
+ # @param password [String, nil] password for password auth
54
+ def initialize(name:, token_id: nil, token_secret: nil, username: nil, password: nil)
55
+ @name = name
56
+ @token_id = token_id
57
+ @token_secret = token_secret
58
+ @username = username
59
+ @password = password
60
+ end
61
+
62
+ # Checks if this user is configured for API token authentication.
63
+ #
64
+ # @return [Boolean] true if both token_id and token_secret are present
65
+ def token_auth?
66
+ !token_id.nil? && !token_id.empty? && !token_secret.nil? && !token_secret.empty?
67
+ end
68
+
69
+ # Checks if this user is configured for password authentication.
70
+ #
71
+ # @return [Boolean] true if both username and password are present
72
+ def password_auth?
73
+ !username.nil? && !username.empty? && !password.nil? && !password.empty?
74
+ end
75
+
76
+ # Checks if this user has valid credentials for authentication.
77
+ #
78
+ # @return [Boolean] true if token auth or password auth is configured
79
+ def valid?
80
+ token_auth? || password_auth?
81
+ end
82
+
83
+ # Creates a User from a kubeconfig-style hash structure.
84
+ #
85
+ # @param hash [Hash] hash with "name" and "user" keys
86
+ # @return [User] new user instance
87
+ #
88
+ # @example Hash structure for token auth
89
+ # {
90
+ # "name" => "admin",
91
+ # "user" => {
92
+ # "token-id" => "root@pam!token",
93
+ # "token-secret" => "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
94
+ # }
95
+ # }
96
+ def self.from_hash(hash)
97
+ user_data = hash["user"] || {}
98
+
99
+ new(
100
+ name: hash["name"],
101
+ token_id: user_data["token-id"],
102
+ token_secret: user_data["token-secret"],
103
+ username: user_data["username"],
104
+ password: user_data["password"]
105
+ )
106
+ end
107
+
108
+ # Converts the user to a kubeconfig-style hash structure.
109
+ #
110
+ # @param mask_secrets [Boolean] whether to mask sensitive values
111
+ # @return [Hash] hash representation suitable for YAML serialization
112
+ def to_hash(mask_secrets: false)
113
+ user_data = {}
114
+
115
+ if token_auth?
116
+ user_data["token-id"] = token_id
117
+ user_data["token-secret"] = mask_secrets ? SECRET_MASK : token_secret
118
+ end
119
+
120
+ if password_auth?
121
+ user_data["username"] = username
122
+ user_data["password"] = mask_secrets ? SECRET_MASK : password
123
+ end
124
+
125
+ {
126
+ "name" => name,
127
+ "user" => user_data
128
+ }
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end