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,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Represents the result of a lifecycle operation on a VM.
6
+ #
7
+ # Combines VM, task status, and error information into a single object
8
+ # for consistent presentation of operation results.
9
+ #
10
+ # @example Successful sync operation
11
+ # result = OperationResult.new(vm: vm, task: task, success: task.successful?)
12
+ # result.successful? #=> true
13
+ # result.message #=> "OK"
14
+ #
15
+ # @example Async operation (pending)
16
+ # result = OperationResult.new(vm: vm, task_upid: upid, success: :pending)
17
+ # result.pending? #=> true
18
+ # result.message #=> "Task: UPID:pve1:..."
19
+ #
20
+ # @example Failed operation
21
+ # result = OperationResult.new(vm: vm, success: false, error: "Permission denied")
22
+ # result.failed? #=> true
23
+ # result.message #=> "Permission denied"
24
+ #
25
+ class OperationResult < Base
26
+ # @return [Hash, nil] Generic resource info (for snapshot/backup operations)
27
+ attr_reader :resource
28
+
29
+ # @return [Symbol] The operation performed (:start, :stop, etc.)
30
+ attr_reader :operation
31
+
32
+ # @return [Models::Task, nil] The task (for completed sync operations)
33
+ attr_reader :task
34
+
35
+ # @return [String, nil] The task UPID (for async operations)
36
+ attr_reader :task_upid
37
+
38
+ # @return [Boolean, Symbol] true, false, or :pending
39
+ attr_reader :success
40
+
41
+ # @return [String, nil] Error message if operation failed
42
+ attr_reader :error
43
+
44
+ # Creates a new OperationResult.
45
+ #
46
+ # @param attrs [Hash] Result attributes
47
+ def initialize(attrs = {})
48
+ super(attrs)
49
+ @resource = @attributes[:resource]
50
+ @operation = @attributes[:operation]
51
+ @task = @attributes[:task]
52
+ @task_upid = @attributes[:task_upid]
53
+ @success = @attributes[:success]
54
+ @error = @attributes[:error]
55
+ end
56
+
57
+ # Checks if the operation was successful.
58
+ #
59
+ # @return [Boolean] true if success is true or task succeeded
60
+ def successful?
61
+ success == true || task&.successful?
62
+ end
63
+
64
+ # Checks if the operation failed.
65
+ #
66
+ # @return [Boolean] true if success is false, :partial, or task failed
67
+ def failed?
68
+ success == false || success == :partial || task&.failed?
69
+ end
70
+
71
+ # Checks if the operation is still pending (async).
72
+ #
73
+ # @return [Boolean] true if success is :pending or task is pending
74
+ def pending?
75
+ success == :pending || task&.pending?
76
+ end
77
+
78
+ # Checks if the operation partially succeeded (e.g. clone OK, config update failed).
79
+ #
80
+ # @return [Boolean] true if success is :partial
81
+ def partial?
82
+ success == :partial
83
+ end
84
+
85
+ # Returns human-readable status.
86
+ #
87
+ # @return [String] "Pending", "Success", or "Failed"
88
+ def status_text
89
+ return "Pending" if pending?
90
+ return "Partial" if partial?
91
+ return "Success" if successful?
92
+
93
+ "Failed"
94
+ end
95
+
96
+ # Returns the result message for display.
97
+ #
98
+ # Priority: error > task.exitstatus > task_upid > status_text
99
+ #
100
+ # @return [String] Result message
101
+ def message
102
+ return error if error
103
+ return task.exitstatus if task
104
+ return "Task: #{task_upid}" if task_upid
105
+
106
+ status_text
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Represents a physical disk (block device) on a Proxmox node.
6
+ #
7
+ # PhysicalDisk instances are created from the Proxmox API responses
8
+ # and provide domain methods for disk analysis.
9
+ #
10
+ # @example Creating a disk from API data
11
+ # disk = PhysicalDisk.new(
12
+ # devpath: "/dev/sda",
13
+ # model: "Samsung SSD 970",
14
+ # size: 500_000_000_000,
15
+ # type: "ssd",
16
+ # health: "PASSED",
17
+ # node: "pve1",
18
+ # gpt: 1,
19
+ # mounted: 1,
20
+ # used: "LVM"
21
+ # )
22
+ # disk.ssd? # => true
23
+ # disk.healthy? # => true
24
+ # disk.size_gb # => 465.7
25
+ # disk.gpt? # => true
26
+ # disk.mounted? # => true
27
+ # disk.osd? # => false
28
+ #
29
+ # @see Pvectl::Models::Base Base class for all models
30
+ #
31
+ class PhysicalDisk < Base
32
+ # @return [String, nil] device path (e.g., "/dev/sda")
33
+ attr_reader :devpath
34
+
35
+ # @return [String, nil] disk model name
36
+ attr_reader :model
37
+
38
+ # @return [Integer, nil] disk size in bytes
39
+ attr_reader :size
40
+
41
+ # @return [String, nil] disk type ("ssd", "hdd", etc.)
42
+ attr_reader :type
43
+
44
+ # @return [String, nil] SMART health status (e.g., "PASSED", "FAILED")
45
+ attr_reader :health
46
+
47
+ # @return [String, nil] disk serial number
48
+ attr_reader :serial
49
+
50
+ # @return [String, nil] disk vendor
51
+ attr_reader :vendor
52
+
53
+ # @return [String, nil] Proxmox node name this disk belongs to
54
+ attr_reader :node
55
+
56
+ # @return [Integer, nil] whether disk has a GPT partition table (1 = yes, 0 = no)
57
+ attr_reader :gpt
58
+
59
+ # @return [Integer, nil] whether disk is mounted (1 = yes, 0 = no)
60
+ attr_reader :mounted
61
+
62
+ # @return [String, nil] how the disk is used (e.g., "LVM", "ZFS", "ext4")
63
+ attr_reader :used
64
+
65
+ # @return [String, nil] World Wide Name identifier
66
+ attr_reader :wwn
67
+
68
+ # @return [Integer, nil] Ceph OSD ID (-1 if not an OSD)
69
+ attr_reader :osdid
70
+
71
+ # @return [String, nil] parent device path (e.g., "/dev/sda" for partition "/dev/sda1")
72
+ attr_reader :parent
73
+
74
+ # @return [String, nil] SMART type ("ata" or "text")
75
+ attr_reader :smart_type
76
+
77
+ # @return [Array<Hash>, nil] ATA SMART attributes array
78
+ attr_reader :smart_attributes
79
+
80
+ # @return [String, nil] raw SMART text (NVMe/SAS)
81
+ attr_reader :smart_text
82
+
83
+ # @return [Integer, nil] disk wearout percentage
84
+ attr_reader :wearout
85
+
86
+ # Creates a new PhysicalDisk instance.
87
+ #
88
+ # @param attrs [Hash] disk attributes from API
89
+ # @option attrs [String] :devpath device path
90
+ # @option attrs [String] :model disk model name
91
+ # @option attrs [Integer] :size disk size in bytes
92
+ # @option attrs [String] :type disk type
93
+ # @option attrs [String] :health SMART health status
94
+ # @option attrs [String] :serial serial number
95
+ # @option attrs [String] :vendor vendor name
96
+ # @option attrs [String] :node Proxmox node name
97
+ # @option attrs [Integer] :gpt GPT partition table flag (1/0)
98
+ # @option attrs [Integer] :mounted mounted flag (1/0)
99
+ # @option attrs [String] :used usage type
100
+ # @option attrs [String] :wwn World Wide Name
101
+ # @option attrs [Integer] :osdid Ceph OSD ID
102
+ # @option attrs [String] :parent parent device path
103
+ # @option attrs [String] :smart_type SMART data type ("ata" or "text")
104
+ # @option attrs [Array<Hash>] :smart_attributes ATA SMART attributes
105
+ # @option attrs [String] :smart_text raw SMART text (NVMe/SAS)
106
+ # @option attrs [Integer] :wearout wearout percentage
107
+ def initialize(attrs = {})
108
+ super
109
+ @devpath = attributes[:devpath]
110
+ @model = attributes[:model]
111
+ @size = attributes[:size]
112
+ @type = attributes[:type]
113
+ @health = attributes[:health]
114
+ @serial = attributes[:serial]
115
+ @vendor = attributes[:vendor]
116
+ @node = attributes[:node]
117
+ @gpt = attributes[:gpt]
118
+ @mounted = attributes[:mounted]
119
+ @used = attributes[:used]
120
+ @wwn = attributes[:wwn]
121
+ @osdid = attributes[:osdid]
122
+ @parent = attributes[:parent]
123
+ @smart_type = attributes[:smart_type]
124
+ @smart_attributes = attributes[:smart_attributes]
125
+ @smart_text = attributes[:smart_text]
126
+ @wearout = attributes[:wearout]
127
+ end
128
+
129
+ # Returns disk size in gigabytes.
130
+ #
131
+ # @return [Float, nil] size in GB (binary, 1024-based), or nil if size unknown
132
+ #
133
+ # @example
134
+ # disk = PhysicalDisk.new(size: 500_000_000_000)
135
+ # disk.size_gb # => 465.7
136
+ def size_gb
137
+ return nil if size.nil?
138
+
139
+ (size.to_f / 1024 / 1024 / 1024).round(1)
140
+ end
141
+
142
+ # Checks if disk SMART health status is PASSED.
143
+ #
144
+ # @return [Boolean] true if health is "PASSED"
145
+ def healthy?
146
+ health == "PASSED"
147
+ end
148
+
149
+ # Checks if disk is an SSD.
150
+ #
151
+ # @return [Boolean] true if type is "ssd"
152
+ def ssd?
153
+ type == "ssd"
154
+ end
155
+
156
+ # Checks if disk has a GPT partition table.
157
+ #
158
+ # @return [Boolean] true if gpt is 1
159
+ def gpt?
160
+ gpt == 1
161
+ end
162
+
163
+ # Checks if disk is currently mounted.
164
+ #
165
+ # @return [Boolean] true if mounted is 1
166
+ def mounted?
167
+ mounted == 1
168
+ end
169
+
170
+ # Checks if disk is a Ceph OSD.
171
+ #
172
+ # @return [Boolean] true if osdid is non-nil and >= 0
173
+ def osd?
174
+ !osdid.nil? && osdid >= 0
175
+ end
176
+
177
+ # Merges SMART data into the model.
178
+ #
179
+ # Called after initial construction when SMART data is fetched separately
180
+ # from the disk list endpoint.
181
+ #
182
+ # @param smart_data [Hash{Symbol => untyped}] SMART response data
183
+ # @return [void]
184
+ def merge_smart(smart_data)
185
+ @smart_type = smart_data[:type]
186
+ @smart_attributes = smart_data[:attributes]
187
+ @smart_text = smart_data[:text]
188
+ @wearout = smart_data[:wearout]
189
+ @health = smart_data[:health] if smart_data[:health]
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Represents a Proxmox service running on a node.
6
+ #
7
+ # Services are system daemons that make up the Proxmox VE platform,
8
+ # such as pveproxy, pvedaemon, pve-cluster, etc.
9
+ #
10
+ # @example Creating a service instance
11
+ # service = Service.new(
12
+ # service: "pveproxy",
13
+ # name: "pveproxy",
14
+ # state: "running",
15
+ # desc: "PVE API Proxy Server"
16
+ # )
17
+ # service.running? # => true
18
+ #
19
+ # @see Pvectl::Repositories::Service Repository that creates these instances
20
+ #
21
+ class Service < Base
22
+ # @return [String] the service identifier
23
+ attr_reader :service
24
+
25
+ # @return [String, nil] the display name of the service
26
+ attr_reader :name
27
+
28
+ # @return [String] the current state (running, stopped, etc.)
29
+ attr_reader :state
30
+
31
+ # @return [String, nil] the service description
32
+ attr_reader :desc
33
+
34
+ # @return [String, nil] systemd ActiveState (active, inactive, failed, ...)
35
+ attr_reader :active_state
36
+
37
+ # @return [String, nil] systemd UnitFileState (enabled, disabled, masked, ...)
38
+ attr_reader :unit_state
39
+
40
+ # @return [String, nil] node name this service belongs to
41
+ attr_reader :node
42
+
43
+ # Creates a new Service instance.
44
+ #
45
+ # @param attrs [Hash] service attributes
46
+ # @option attrs [String] :service the service identifier
47
+ # @option attrs [String] :name the display name
48
+ # @option attrs [String] :state the current state
49
+ # @option attrs [String] :desc the description
50
+ # @option attrs [String] :active_state systemd ActiveState
51
+ # @option attrs [String] :unit_state systemd UnitFileState
52
+ # @option attrs [String] :node the node this service runs on
53
+ def initialize(attrs = {})
54
+ super
55
+ @service = attributes[:service]
56
+ @name = attributes[:name]
57
+ @state = attributes[:state]
58
+ @desc = attributes[:desc]
59
+ # Accept both symbol keys (:active_state) and dasherized keys (:"active-state")
60
+ @active_state = attributes[:active_state] || attributes[:"active-state"]
61
+ @unit_state = attributes[:unit_state] || attributes[:"unit-state"]
62
+ @node = attributes[:node]
63
+ end
64
+
65
+ # Checks if the service is currently running.
66
+ #
67
+ # @return [Boolean] true if state is "running"
68
+ def running?
69
+ state == "running"
70
+ end
71
+
72
+ # Returns the display name, falling back to service identifier.
73
+ #
74
+ # @return [String] the name to display
75
+ def display_name
76
+ name || service
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Represents a VM/container snapshot in Proxmox.
6
+ #
7
+ # A snapshot captures the state of a VM or container at a specific point in time,
8
+ # including optionally the VM memory state (vmstate).
9
+ #
10
+ # @example Creating a snapshot model
11
+ # snapshot = Snapshot.new(
12
+ # name: "before-upgrade",
13
+ # snaptime: 1706800000,
14
+ # description: "Snapshot before upgrade",
15
+ # vmstate: 1
16
+ # )
17
+ # snapshot.has_vmstate? # => true
18
+ # snapshot.created_at # => 2024-02-01 12:26:40 +0000
19
+ #
20
+ # @see Pvectl::Models::Base Base model class
21
+ #
22
+ class Snapshot < Base
23
+ # @return [String] snapshot name/identifier
24
+ attr_reader :name
25
+
26
+ # @return [Integer, nil] Unix timestamp when snapshot was created
27
+ attr_reader :snaptime
28
+
29
+ # @return [String, nil] optional description of the snapshot
30
+ attr_reader :description
31
+
32
+ # @return [Integer, nil] 1 if VM memory state was saved, 0 or nil otherwise
33
+ attr_reader :vmstate
34
+
35
+ # @return [String, nil] parent snapshot name for snapshot trees
36
+ attr_reader :parent
37
+
38
+ # @return [Integer, nil] VM/container ID this snapshot belongs to
39
+ attr_reader :vmid
40
+
41
+ # @return [String, nil] node name where the VM/container resides
42
+ attr_reader :node
43
+
44
+ # @return [Symbol, nil] resource type (:qemu for VM, :lxc for container)
45
+ attr_reader :resource_type
46
+
47
+ # Creates a new Snapshot instance.
48
+ #
49
+ # @param attrs [Hash] snapshot attributes
50
+ # @option attrs [String] :name snapshot name
51
+ # @option attrs [Integer] :snaptime Unix timestamp of creation
52
+ # @option attrs [String] :description snapshot description
53
+ # @option attrs [Integer] :vmstate 1 if VM state saved, 0 otherwise
54
+ # @option attrs [String] :parent parent snapshot name
55
+ # @option attrs [Integer] :vmid VM/container ID
56
+ # @option attrs [String] :node node name
57
+ # @option attrs [Symbol] :resource_type :qemu or :lxc
58
+ def initialize(attrs = {})
59
+ super
60
+ @name = attributes[:name]
61
+ @snaptime = attributes[:snaptime]
62
+ @description = attributes[:description]
63
+ @vmstate = attributes[:vmstate]
64
+ @parent = attributes[:parent]
65
+ @vmid = attributes[:vmid]
66
+ @node = attributes[:node]
67
+ @resource_type = attributes[:resource_type]
68
+ end
69
+
70
+ # Checks if the snapshot includes VM memory state.
71
+ #
72
+ # @return [Boolean] true if vmstate equals 1
73
+ def has_vmstate?
74
+ vmstate == 1
75
+ end
76
+
77
+ # Returns the snapshot creation time as a Time object.
78
+ #
79
+ # @return [Time, nil] creation time or nil if snaptime is not set
80
+ def created_at
81
+ return nil if snaptime.nil?
82
+
83
+ Time.at(snaptime)
84
+ end
85
+
86
+ # Checks if the snapshot belongs to a VM (QEMU).
87
+ #
88
+ # @return [Boolean] true if resource_type is :qemu
89
+ def vm?
90
+ resource_type == :qemu
91
+ end
92
+
93
+ # Checks if the snapshot belongs to a container (LXC).
94
+ #
95
+ # @return [Boolean] true if resource_type is :lxc
96
+ def container?
97
+ resource_type == :lxc
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Wraps snapshot describe data: target snapshot + siblings for tree building.
6
+ #
7
+ # Used by the describe command to return rich snapshot data without
8
+ # changing the existing single-model return convention in ResourceService.
9
+ #
10
+ # @example Single VM
11
+ # desc = SnapshotDescription.new(entries: [
12
+ # SnapshotDescription::Entry.new(snapshot: snap, siblings: all_snaps)
13
+ # ])
14
+ #
15
+ # @example Multiple VMs
16
+ # desc = SnapshotDescription.new(entries: [entry1, entry2])
17
+ # desc.single? # => false
18
+ #
19
+ class SnapshotDescription
20
+ # Holds a single snapshot + its siblings for one VM/container.
21
+ Entry = Struct.new(:snapshot, :siblings, keyword_init: true)
22
+
23
+ # @return [Array<Entry>] entries per VM/container
24
+ attr_reader :entries
25
+
26
+ # @param entries [Array<Entry>] snapshot entries
27
+ def initialize(entries:)
28
+ @entries = entries
29
+ end
30
+
31
+ # Returns true when describing a snapshot from a single VM.
32
+ #
33
+ # @return [Boolean]
34
+ def single?
35
+ entries.length == 1
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Models
5
+ # Represents a storage pool in the Proxmox cluster.
6
+ #
7
+ # Immutable domain model containing storage attributes and predicate methods.
8
+ # Created by Repositories::Storage from API data.
9
+ # Display formatting is handled by Presenters::Storage.
10
+ #
11
+ # @example Creating a Storage model
12
+ # storage = Storage.new(name: "local", plugintype: "dir", status: "available")
13
+ # storage.active? #=> true
14
+ # storage.shared? #=> false
15
+ #
16
+ # @example From API response
17
+ # data = { "storage" => "local", "plugintype" => "dir", "status" => "available" }
18
+ # storage = Storage.new(data)
19
+ #
20
+ # @see Pvectl::Repositories::Storage Repository that creates Storage instances
21
+ # @see Pvectl::Presenters::Storage Presenter for formatting Storage data
22
+ #
23
+ class Storage < Base
24
+ # @return [String] storage pool name
25
+ attr_reader :name
26
+
27
+ # @return [String] storage plugin type (dir, lvmthin, rbd, nfs, zfspool, etc.)
28
+ attr_reader :plugintype
29
+
30
+ # @return [String] storage status (available, unavailable)
31
+ attr_reader :status
32
+
33
+ # @return [String, nil] node name (nil for shared storage)
34
+ attr_reader :node
35
+
36
+ # @return [Integer, nil] disk used in bytes
37
+ attr_reader :disk
38
+
39
+ # @return [Integer, nil] total disk in bytes
40
+ attr_reader :maxdisk
41
+
42
+ # @return [String, nil] comma-separated content types (images, iso, vztmpl, backup, rootdir)
43
+ attr_reader :content
44
+
45
+ # @return [Integer] shared flag (1 = shared, 0 = local)
46
+ attr_reader :shared
47
+
48
+ # @return [Integer, nil] available bytes (from /nodes/{node}/storage)
49
+ attr_reader :avail
50
+
51
+ # @return [Integer, nil] enabled flag (0/1) (from /nodes/{node}/storage)
52
+ attr_reader :enabled
53
+
54
+ # @return [Integer, nil] active flag (0/1) (from /nodes/{node}/storage)
55
+ attr_reader :active_flag
56
+
57
+ # Configuration fields (from /storage/{storage} API endpoint)
58
+ # @return [String, nil] path for dir, nfs storage types
59
+ attr_reader :path
60
+
61
+ # @return [String, nil] server for nfs, iscsi, ceph
62
+ attr_reader :server
63
+
64
+ # @return [String, nil] export path (nfs)
65
+ attr_reader :export
66
+
67
+ # @return [String, nil] pool name (zfs, ceph)
68
+ attr_reader :pool
69
+
70
+ # @return [String, nil] volume group (lvm)
71
+ attr_reader :vgname
72
+
73
+ # @return [String, nil] thin pool name (lvmthin)
74
+ attr_reader :thinpool
75
+
76
+ # @return [String, nil] allowed nodes (nil = all)
77
+ attr_reader :nodes_allowed
78
+
79
+ # @return [Hash, nil] retention policy hash
80
+ attr_reader :prune_backups
81
+
82
+ # @return [Integer, nil] max backups (deprecated)
83
+ attr_reader :max_files
84
+
85
+ # Content summary
86
+ # @return [Array<Hash>] volumes from /content endpoint
87
+ attr_reader :volumes
88
+
89
+ # Creates a new Storage model from attributes.
90
+ #
91
+ # Handles field aliasing between different API endpoints:
92
+ # - /cluster/resources uses: disk, maxdisk
93
+ # - /nodes/{node}/storage uses: used, total, avail
94
+ #
95
+ # @param attrs [Hash] Storage attributes from API (string or symbol keys)
96
+ def initialize(attrs = {})
97
+ super(attrs)
98
+ @name = @attributes[:name] || @attributes[:storage]
99
+ @plugintype = @attributes[:plugintype] || @attributes[:type]
100
+ @node = @attributes[:node]
101
+ @content = @attributes[:content]
102
+ @shared = @attributes[:shared] || 0
103
+
104
+ # Handle field aliasing between endpoints
105
+ # /cluster/resources uses: disk, maxdisk
106
+ # /nodes/{node}/storage uses: used, total, avail
107
+ @disk = @attributes[:disk] || @attributes[:used]
108
+ @maxdisk = @attributes[:maxdisk] || @attributes[:total]
109
+ @avail = @attributes[:avail]
110
+ @enabled = @attributes[:enabled]
111
+ @active_flag = @attributes[:active]
112
+
113
+ # Status normalization: /nodes/{node}/storage has no status field
114
+ # Derive from active flag if status not present
115
+ @status = @attributes[:status] || derive_status_from_active
116
+
117
+ # Configuration fields from /storage/{storage} API endpoint
118
+ @path = @attributes[:path]
119
+ @server = @attributes[:server]
120
+ @export = @attributes[:export]
121
+ @pool = @attributes[:pool]
122
+ @vgname = @attributes[:vgname]
123
+ @thinpool = @attributes[:thinpool]
124
+ @nodes_allowed = @attributes[:nodes] # API returns "nodes" not "nodes_allowed"
125
+ @prune_backups = @attributes[:"prune-backups"] # API uses hyphen
126
+ @max_files = @attributes[:maxfiles]
127
+ @volumes = @attributes[:volumes] || []
128
+ end
129
+
130
+ # Checks if the storage is active/available.
131
+ #
132
+ # @return [Boolean] true if status is "available" or "active"
133
+ def active?
134
+ status == "available" || status == "active"
135
+ end
136
+
137
+ # Returns used bytes (alias for disk).
138
+ # Provides semantic clarity when working with /nodes/{node}/storage API.
139
+ #
140
+ # @return [Integer, nil] bytes used
141
+ def used
142
+ disk
143
+ end
144
+
145
+ # Returns total bytes (alias for maxdisk).
146
+ # Provides semantic clarity when working with /nodes/{node}/storage API.
147
+ #
148
+ # @return [Integer, nil] total bytes
149
+ def total
150
+ maxdisk
151
+ end
152
+
153
+ # Checks if the storage is enabled.
154
+ #
155
+ # @return [Boolean] true if enabled flag is 1
156
+ def enabled?
157
+ enabled == 1
158
+ end
159
+
160
+ # Checks if the storage is shared across nodes.
161
+ #
162
+ # @return [Boolean] true if shared flag is 1
163
+ def shared?
164
+ shared == 1
165
+ end
166
+
167
+ private
168
+
169
+ # Derives status from active flag when status not present.
170
+ # Used for /nodes/{node}/storage API which doesn't return status field.
171
+ #
172
+ # @return [String, nil] derived status or nil if active_flag not set
173
+ def derive_status_from_active
174
+ return nil if @active_flag.nil?
175
+
176
+ @active_flag == 1 ? "available" : "unavailable"
177
+ end
178
+ end
179
+ end
180
+ end