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.
- checksums.yaml +7 -0
- data/.claude/rules/branch-before-changes.md +52 -0
- data/.claude/rules/documentation-updates.md +104 -0
- data/.claude/rules/git-workflow.md +84 -0
- data/.claude/rules/proxmox-api-docs.md +58 -0
- data/.claude/rules/rbs-signatures.md +80 -0
- data/.claude/rules/refactoring-as-design-option.md +35 -0
- data/.claude/scheduled_tasks.lock +1 -0
- data/.claude/settings.json +51 -0
- data/.mcp.json +8 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +138 -0
- data/CLAUDE.md +211 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +143 -0
- data/Rakefile +8 -0
- data/docs/proxmox-api-update.sh +96 -0
- data/exe/pvectl +5 -0
- data/lib/pvectl/argv_preprocessor.rb +334 -0
- data/lib/pvectl/cli.rb +102 -0
- data/lib/pvectl/commands/apt.rb +389 -0
- data/lib/pvectl/commands/clone_container.rb +230 -0
- data/lib/pvectl/commands/clone_vm.rb +331 -0
- data/lib/pvectl/commands/cloudinit/command.rb +122 -0
- data/lib/pvectl/commands/cloudinit/dump.rb +94 -0
- data/lib/pvectl/commands/cloudinit/pending.rb +137 -0
- data/lib/pvectl/commands/cloudinit/regenerate.rb +79 -0
- data/lib/pvectl/commands/config/command.rb +65 -0
- data/lib/pvectl/commands/config/get_contexts.rb +68 -0
- data/lib/pvectl/commands/config/set_cluster.rb +103 -0
- data/lib/pvectl/commands/config/set_context.rb +136 -0
- data/lib/pvectl/commands/config/set_credentials.rb +181 -0
- data/lib/pvectl/commands/config/use_context.rb +69 -0
- data/lib/pvectl/commands/config/view.rb +67 -0
- data/lib/pvectl/commands/console.rb +93 -0
- data/lib/pvectl/commands/console_ct.rb +187 -0
- data/lib/pvectl/commands/console_vm.rb +187 -0
- data/lib/pvectl/commands/container_lifecycle_command.rb +77 -0
- data/lib/pvectl/commands/create_backup.rb +173 -0
- data/lib/pvectl/commands/create_container.rb +141 -0
- data/lib/pvectl/commands/create_resource_command.rb +244 -0
- data/lib/pvectl/commands/create_snapshot.rb +242 -0
- data/lib/pvectl/commands/create_vm.rb +267 -0
- data/lib/pvectl/commands/delete_backup.rb +139 -0
- data/lib/pvectl/commands/delete_command.rb +119 -0
- data/lib/pvectl/commands/delete_container.rb +30 -0
- data/lib/pvectl/commands/delete_snapshot.rb +248 -0
- data/lib/pvectl/commands/delete_vm.rb +127 -0
- data/lib/pvectl/commands/describe/command.rb +251 -0
- data/lib/pvectl/commands/edit_container.rb +56 -0
- data/lib/pvectl/commands/edit_dns.rb +149 -0
- data/lib/pvectl/commands/edit_hosts.rb +135 -0
- data/lib/pvectl/commands/edit_node.rb +54 -0
- data/lib/pvectl/commands/edit_resource_command.rb +180 -0
- data/lib/pvectl/commands/edit_vm.rb +154 -0
- data/lib/pvectl/commands/edit_volume.rb +189 -0
- data/lib/pvectl/commands/feature_command.rb +230 -0
- data/lib/pvectl/commands/feature_container.rb +21 -0
- data/lib/pvectl/commands/feature_vm.rb +94 -0
- data/lib/pvectl/commands/get/command.rb +360 -0
- data/lib/pvectl/commands/get/handlers/backups.rb +76 -0
- data/lib/pvectl/commands/get/handlers/capabilities.rb +107 -0
- data/lib/pvectl/commands/get/handlers/containers.rb +148 -0
- data/lib/pvectl/commands/get/handlers/disks.rb +107 -0
- data/lib/pvectl/commands/get/handlers/dns.rb +94 -0
- data/lib/pvectl/commands/get/handlers/hosts.rb +94 -0
- data/lib/pvectl/commands/get/handlers/nodes.rb +162 -0
- data/lib/pvectl/commands/get/handlers/services.rb +81 -0
- data/lib/pvectl/commands/get/handlers/snapshots.rb +97 -0
- data/lib/pvectl/commands/get/handlers/storage.rb +118 -0
- data/lib/pvectl/commands/get/handlers/subscription.rb +69 -0
- data/lib/pvectl/commands/get/handlers/tasks.rb +89 -0
- data/lib/pvectl/commands/get/handlers/templates.rb +175 -0
- data/lib/pvectl/commands/get/handlers/time.rb +118 -0
- data/lib/pvectl/commands/get/handlers/vms.rb +145 -0
- data/lib/pvectl/commands/get/handlers/volume.rb +134 -0
- data/lib/pvectl/commands/get/resource_handler.rb +63 -0
- data/lib/pvectl/commands/get/resource_registry.rb +18 -0
- data/lib/pvectl/commands/get/watch_loop.rb +129 -0
- data/lib/pvectl/commands/irreversible_command.rb +265 -0
- data/lib/pvectl/commands/logs/command.rb +275 -0
- data/lib/pvectl/commands/logs/handlers/journal.rb +46 -0
- data/lib/pvectl/commands/logs/handlers/syslog.rb +53 -0
- data/lib/pvectl/commands/logs/handlers/task_detail.rb +52 -0
- data/lib/pvectl/commands/logs/handlers/task_logs.rb +115 -0
- data/lib/pvectl/commands/logs/resource_handler.rb +46 -0
- data/lib/pvectl/commands/logs/resource_registry.rb +22 -0
- data/lib/pvectl/commands/migrate_command.rb +282 -0
- data/lib/pvectl/commands/migrate_container.rb +23 -0
- data/lib/pvectl/commands/migrate_vm.rb +122 -0
- data/lib/pvectl/commands/move_disk_command.rb +239 -0
- data/lib/pvectl/commands/move_disk_container.rb +21 -0
- data/lib/pvectl/commands/move_disk_vm.rb +127 -0
- data/lib/pvectl/commands/ping.rb +249 -0
- data/lib/pvectl/commands/pull.rb +342 -0
- data/lib/pvectl/commands/push.rb +352 -0
- data/lib/pvectl/commands/reset.rb +64 -0
- data/lib/pvectl/commands/resource_lifecycle_command.rb +277 -0
- data/lib/pvectl/commands/resource_registry.rb +73 -0
- data/lib/pvectl/commands/restart.rb +70 -0
- data/lib/pvectl/commands/restart_container.rb +18 -0
- data/lib/pvectl/commands/restore_backup.rb +236 -0
- data/lib/pvectl/commands/resume.rb +57 -0
- data/lib/pvectl/commands/rollback_snapshot.rb +228 -0
- data/lib/pvectl/commands/sendkey_vm.rb +205 -0
- data/lib/pvectl/commands/service.rb +293 -0
- data/lib/pvectl/commands/set_container.rb +50 -0
- data/lib/pvectl/commands/set_node.rb +52 -0
- data/lib/pvectl/commands/set_resource_command.rb +185 -0
- data/lib/pvectl/commands/set_vm.rb +136 -0
- data/lib/pvectl/commands/set_volume.rb +212 -0
- data/lib/pvectl/commands/shared_config_parsers.rb +126 -0
- data/lib/pvectl/commands/shared_flags.rb +155 -0
- data/lib/pvectl/commands/shutdown.rb +73 -0
- data/lib/pvectl/commands/shutdown_container.rb +18 -0
- data/lib/pvectl/commands/start.rb +79 -0
- data/lib/pvectl/commands/start_container.rb +18 -0
- data/lib/pvectl/commands/stop.rb +75 -0
- data/lib/pvectl/commands/stop_container.rb +18 -0
- data/lib/pvectl/commands/suspend.rb +64 -0
- data/lib/pvectl/commands/template_command.rb +205 -0
- data/lib/pvectl/commands/template_container.rb +27 -0
- data/lib/pvectl/commands/template_vm.rb +106 -0
- data/lib/pvectl/commands/top/command.rb +206 -0
- data/lib/pvectl/commands/top/handlers/containers.rb +61 -0
- data/lib/pvectl/commands/top/handlers/nodes.rb +61 -0
- data/lib/pvectl/commands/top/handlers/vms.rb +61 -0
- data/lib/pvectl/commands/top/resource_handler.rb +46 -0
- data/lib/pvectl/commands/top/resource_registry.rb +22 -0
- data/lib/pvectl/commands/unlink_disk_vm.rb +232 -0
- data/lib/pvectl/commands/vm_lifecycle_command.rb +77 -0
- data/lib/pvectl/commands/wakeonlan_node.rb +153 -0
- data/lib/pvectl/config/errors.rb +62 -0
- data/lib/pvectl/config/models/cluster.rb +180 -0
- data/lib/pvectl/config/models/context.rb +100 -0
- data/lib/pvectl/config/models/resolved_config.rb +171 -0
- data/lib/pvectl/config/models/user.rb +133 -0
- data/lib/pvectl/config/provider.rb +297 -0
- data/lib/pvectl/config/service.rb +300 -0
- data/lib/pvectl/config/store.rb +161 -0
- data/lib/pvectl/config/wizard.rb +309 -0
- data/lib/pvectl/config_serializer.rb +1034 -0
- data/lib/pvectl/connection/retry_handler.rb +161 -0
- data/lib/pvectl/connection.rb +157 -0
- data/lib/pvectl/console/terminal_session.rb +449 -0
- data/lib/pvectl/editor_session.rb +157 -0
- data/lib/pvectl/exit_codes.rb +43 -0
- data/lib/pvectl/formatters/base.rb +55 -0
- data/lib/pvectl/formatters/color_support.rb +90 -0
- data/lib/pvectl/formatters/json.rb +45 -0
- data/lib/pvectl/formatters/output_helper.rb +77 -0
- data/lib/pvectl/formatters/registry.rb +72 -0
- data/lib/pvectl/formatters/table.rb +235 -0
- data/lib/pvectl/formatters/wide.rb +93 -0
- data/lib/pvectl/formatters/yaml.rb +49 -0
- data/lib/pvectl/manifest_serializer.rb +142 -0
- data/lib/pvectl/models/apt_package.rb +107 -0
- data/lib/pvectl/models/backup.rb +173 -0
- data/lib/pvectl/models/base.rb +49 -0
- data/lib/pvectl/models/capability.rb +62 -0
- data/lib/pvectl/models/container.rb +205 -0
- data/lib/pvectl/models/container_operation_result.rb +27 -0
- data/lib/pvectl/models/dns_config.rb +54 -0
- data/lib/pvectl/models/hosts_file.rb +47 -0
- data/lib/pvectl/models/journal_entry.rb +16 -0
- data/lib/pvectl/models/network_interface.rb +85 -0
- data/lib/pvectl/models/node.rb +195 -0
- data/lib/pvectl/models/node_operation_result.rb +45 -0
- data/lib/pvectl/models/operation_result.rb +110 -0
- data/lib/pvectl/models/physical_disk.rb +193 -0
- data/lib/pvectl/models/service.rb +80 -0
- data/lib/pvectl/models/snapshot.rb +101 -0
- data/lib/pvectl/models/snapshot_description.rb +39 -0
- data/lib/pvectl/models/storage.rb +180 -0
- data/lib/pvectl/models/subscription.rb +87 -0
- data/lib/pvectl/models/syslog_entry.rb +17 -0
- data/lib/pvectl/models/task.rb +95 -0
- data/lib/pvectl/models/task_entry.rb +52 -0
- data/lib/pvectl/models/task_log_line.rb +17 -0
- data/lib/pvectl/models/time_config.rb +47 -0
- data/lib/pvectl/models/vm.rb +137 -0
- data/lib/pvectl/models/vm_operation_result.rb +27 -0
- data/lib/pvectl/models/volume.rb +133 -0
- data/lib/pvectl/models/volume_operation_result.rb +26 -0
- data/lib/pvectl/parsers/cloud_init_config.rb +92 -0
- data/lib/pvectl/parsers/disk_config.rb +97 -0
- data/lib/pvectl/parsers/lxc_mount_config.rb +98 -0
- data/lib/pvectl/parsers/lxc_net_config.rb +97 -0
- data/lib/pvectl/parsers/net_config.rb +95 -0
- data/lib/pvectl/parsers/smart_text.rb +42 -0
- data/lib/pvectl/plugin_loader.rb +157 -0
- data/lib/pvectl/presenters/apt_package.rb +99 -0
- data/lib/pvectl/presenters/backup.rb +128 -0
- data/lib/pvectl/presenters/base.rb +283 -0
- data/lib/pvectl/presenters/capability.rb +104 -0
- data/lib/pvectl/presenters/config/context.rb +80 -0
- data/lib/pvectl/presenters/container.rb +574 -0
- data/lib/pvectl/presenters/container_operation_result.rb +109 -0
- data/lib/pvectl/presenters/disk.rb +184 -0
- data/lib/pvectl/presenters/dns_config.rb +68 -0
- data/lib/pvectl/presenters/hosts_file.rb +61 -0
- data/lib/pvectl/presenters/journal_entry.rb +20 -0
- data/lib/pvectl/presenters/node.rb +762 -0
- data/lib/pvectl/presenters/node_operation_result.rb +50 -0
- data/lib/pvectl/presenters/operation_result.rb +61 -0
- data/lib/pvectl/presenters/service.rb +76 -0
- data/lib/pvectl/presenters/snapshot.rb +239 -0
- data/lib/pvectl/presenters/snapshot_operation_result.rb +125 -0
- data/lib/pvectl/presenters/storage.rb +329 -0
- data/lib/pvectl/presenters/subscription.rb +189 -0
- data/lib/pvectl/presenters/syslog_entry.rb +20 -0
- data/lib/pvectl/presenters/task_entry.rb +69 -0
- data/lib/pvectl/presenters/task_log_line.rb +20 -0
- data/lib/pvectl/presenters/template.rb +76 -0
- data/lib/pvectl/presenters/time_config.rb +86 -0
- data/lib/pvectl/presenters/top_container.rb +112 -0
- data/lib/pvectl/presenters/top_node.rb +115 -0
- data/lib/pvectl/presenters/top_presenter.rb +59 -0
- data/lib/pvectl/presenters/top_vm.rb +105 -0
- data/lib/pvectl/presenters/vm.rb +853 -0
- data/lib/pvectl/presenters/vm_operation_result.rb +109 -0
- data/lib/pvectl/presenters/volume.rb +136 -0
- data/lib/pvectl/presenters/volume_operation_result.rb +58 -0
- data/lib/pvectl/repositories/apt.rb +93 -0
- data/lib/pvectl/repositories/backup.rb +186 -0
- data/lib/pvectl/repositories/base.rb +110 -0
- data/lib/pvectl/repositories/capabilities.rb +96 -0
- data/lib/pvectl/repositories/container.rb +503 -0
- data/lib/pvectl/repositories/disk.rb +87 -0
- data/lib/pvectl/repositories/dns.rb +54 -0
- data/lib/pvectl/repositories/hosts.rb +63 -0
- data/lib/pvectl/repositories/journal.rb +23 -0
- data/lib/pvectl/repositories/node.rb +537 -0
- data/lib/pvectl/repositories/service.rb +139 -0
- data/lib/pvectl/repositories/snapshot.rb +133 -0
- data/lib/pvectl/repositories/storage.rb +302 -0
- data/lib/pvectl/repositories/subscription.rb +77 -0
- data/lib/pvectl/repositories/syslog.rb +25 -0
- data/lib/pvectl/repositories/task.rb +82 -0
- data/lib/pvectl/repositories/task_list.rb +30 -0
- data/lib/pvectl/repositories/task_log.rb +31 -0
- data/lib/pvectl/repositories/time_config.rb +53 -0
- data/lib/pvectl/repositories/vm.rb +616 -0
- data/lib/pvectl/repositories/volume.rb +306 -0
- data/lib/pvectl/selectors/base.rb +201 -0
- data/lib/pvectl/selectors/container.rb +116 -0
- data/lib/pvectl/selectors/disk.rb +59 -0
- data/lib/pvectl/selectors/vm.rb +116 -0
- data/lib/pvectl/selectors/volume.rb +59 -0
- data/lib/pvectl/services/backup.rb +209 -0
- data/lib/pvectl/services/clone_container.rb +260 -0
- data/lib/pvectl/services/clone_vm.rb +265 -0
- data/lib/pvectl/services/cloudinit.rb +96 -0
- data/lib/pvectl/services/console.rb +152 -0
- data/lib/pvectl/services/container_lifecycle.rb +124 -0
- data/lib/pvectl/services/create_container.rb +179 -0
- data/lib/pvectl/services/create_vm.rb +191 -0
- data/lib/pvectl/services/edit_container.rb +125 -0
- data/lib/pvectl/services/edit_dns.rb +159 -0
- data/lib/pvectl/services/edit_hosts.rb +78 -0
- data/lib/pvectl/services/edit_node.rb +147 -0
- data/lib/pvectl/services/edit_vm.rb +125 -0
- data/lib/pvectl/services/edit_volume.rb +224 -0
- data/lib/pvectl/services/get/resource_service.rb +98 -0
- data/lib/pvectl/services/move_disk.rb +132 -0
- data/lib/pvectl/services/pull_config.rb +94 -0
- data/lib/pvectl/services/push_config.rb +524 -0
- data/lib/pvectl/services/resize_volume.rb +253 -0
- data/lib/pvectl/services/resource_delete.rb +169 -0
- data/lib/pvectl/services/resource_migration.rb +170 -0
- data/lib/pvectl/services/sendkey.rb +108 -0
- data/lib/pvectl/services/service_lifecycle.rb +89 -0
- data/lib/pvectl/services/set_container.rb +128 -0
- data/lib/pvectl/services/set_node.rb +236 -0
- data/lib/pvectl/services/set_vm.rb +128 -0
- data/lib/pvectl/services/set_volume.rb +126 -0
- data/lib/pvectl/services/snapshot.rb +261 -0
- data/lib/pvectl/services/task_listing.rb +75 -0
- data/lib/pvectl/services/unlink_disk.rb +86 -0
- data/lib/pvectl/services/vm_lifecycle.rb +124 -0
- data/lib/pvectl/services/wakeonlan.rb +79 -0
- data/lib/pvectl/utils/resource_resolver.rb +80 -0
- data/lib/pvectl/version.rb +13 -0
- data/lib/pvectl/wizards/create_container.rb +105 -0
- data/lib/pvectl/wizards/create_vm.rb +98 -0
- data/lib/pvectl.rb +439 -0
- data/sig/external/gli.rbs +16 -0
- data/sig/external/proxmox_api.rbs +10 -0
- data/sig/pvectl/argv_preprocessor.rbs +53 -0
- data/sig/pvectl/cli.rbs +26 -0
- data/sig/pvectl/commands/apt.rbs +47 -0
- data/sig/pvectl/commands/clone_container.rbs +31 -0
- data/sig/pvectl/commands/clone_vm.rbs +33 -0
- data/sig/pvectl/commands/cloudinit/command.rbs +13 -0
- data/sig/pvectl/commands/cloudinit/dump.rbs +13 -0
- data/sig/pvectl/commands/cloudinit/pending.rbs +17 -0
- data/sig/pvectl/commands/cloudinit/regenerate.rbs +11 -0
- data/sig/pvectl/commands/config/command.rbs +9 -0
- data/sig/pvectl/commands/config/get_contexts.rbs +11 -0
- data/sig/pvectl/commands/config/set_cluster.rbs +11 -0
- data/sig/pvectl/commands/config/set_context.rbs +15 -0
- data/sig/pvectl/commands/config/set_credentials.rbs +15 -0
- data/sig/pvectl/commands/config/use_context.rbs +11 -0
- data/sig/pvectl/commands/config/view.rbs +11 -0
- data/sig/pvectl/commands/console.rbs +9 -0
- data/sig/pvectl/commands/console_ct.rbs +27 -0
- data/sig/pvectl/commands/console_vm.rbs +27 -0
- data/sig/pvectl/commands/container_lifecycle_command.rbs +25 -0
- data/sig/pvectl/commands/create_backup.rbs +29 -0
- data/sig/pvectl/commands/create_container.rbs +30 -0
- data/sig/pvectl/commands/create_resource_command.rbs +53 -0
- data/sig/pvectl/commands/create_snapshot.rbs +35 -0
- data/sig/pvectl/commands/create_vm.rbs +30 -0
- data/sig/pvectl/commands/delete_backup.rbs +25 -0
- data/sig/pvectl/commands/delete_command.rbs +45 -0
- data/sig/pvectl/commands/delete_container.rbs +11 -0
- data/sig/pvectl/commands/delete_snapshot.rbs +35 -0
- data/sig/pvectl/commands/delete_vm.rbs +13 -0
- data/sig/pvectl/commands/describe/command.rbs +27 -0
- data/sig/pvectl/commands/edit_container.rbs +17 -0
- data/sig/pvectl/commands/edit_dns.rbs +25 -0
- data/sig/pvectl/commands/edit_hosts.rbs +23 -0
- data/sig/pvectl/commands/edit_node.rbs +17 -0
- data/sig/pvectl/commands/edit_resource_command.rbs +35 -0
- data/sig/pvectl/commands/edit_vm.rbs +19 -0
- data/sig/pvectl/commands/edit_volume.rbs +24 -0
- data/sig/pvectl/commands/feature_command.rbs +43 -0
- data/sig/pvectl/commands/feature_container.rbs +10 -0
- data/sig/pvectl/commands/feature_vm.rbs +12 -0
- data/sig/pvectl/commands/get/command.rbs +42 -0
- data/sig/pvectl/commands/get/handlers/backups.rbs +23 -0
- data/sig/pvectl/commands/get/handlers/capabilities.rbs +29 -0
- data/sig/pvectl/commands/get/handlers/containers.rbs +35 -0
- data/sig/pvectl/commands/get/handlers/disks.rbs +27 -0
- data/sig/pvectl/commands/get/handlers/dns.rbs +25 -0
- data/sig/pvectl/commands/get/handlers/hosts.rbs +25 -0
- data/sig/pvectl/commands/get/handlers/nodes.rbs +33 -0
- data/sig/pvectl/commands/get/handlers/services.rbs +23 -0
- data/sig/pvectl/commands/get/handlers/snapshots.rbs +27 -0
- data/sig/pvectl/commands/get/handlers/storage.rbs +25 -0
- data/sig/pvectl/commands/get/handlers/subscription.rbs +25 -0
- data/sig/pvectl/commands/get/handlers/tasks.rbs +28 -0
- data/sig/pvectl/commands/get/handlers/templates.rbs +35 -0
- data/sig/pvectl/commands/get/handlers/time.rbs +29 -0
- data/sig/pvectl/commands/get/handlers/vms.rbs +35 -0
- data/sig/pvectl/commands/get/handlers/volume.rbs +27 -0
- data/sig/pvectl/commands/get/resource_handler.rbs +13 -0
- data/sig/pvectl/commands/get/resource_registry.rbs +8 -0
- data/sig/pvectl/commands/get/watch_loop.rbs +33 -0
- data/sig/pvectl/commands/irreversible_command.rbs +32 -0
- data/sig/pvectl/commands/logs/command.rbs +35 -0
- data/sig/pvectl/commands/logs/handlers/journal.rbs +21 -0
- data/sig/pvectl/commands/logs/handlers/syslog.rbs +21 -0
- data/sig/pvectl/commands/logs/handlers/task_detail.rbs +21 -0
- data/sig/pvectl/commands/logs/handlers/task_logs.rbs +35 -0
- data/sig/pvectl/commands/logs/resource_handler.rbs +11 -0
- data/sig/pvectl/commands/logs/resource_registry.rbs +8 -0
- data/sig/pvectl/commands/migrate_command.rbs +45 -0
- data/sig/pvectl/commands/migrate_container.rbs +11 -0
- data/sig/pvectl/commands/migrate_vm.rbs +13 -0
- data/sig/pvectl/commands/move_disk_command.rbs +43 -0
- data/sig/pvectl/commands/move_disk_container.rbs +11 -0
- data/sig/pvectl/commands/move_disk_vm.rbs +13 -0
- data/sig/pvectl/commands/ping.rbs +39 -0
- data/sig/pvectl/commands/pull.rbs +33 -0
- data/sig/pvectl/commands/push.rbs +32 -0
- data/sig/pvectl/commands/reset.rbs +11 -0
- data/sig/pvectl/commands/resource_lifecycle_command.rbs +55 -0
- data/sig/pvectl/commands/resource_registry.rbs +19 -0
- data/sig/pvectl/commands/restart.rbs +11 -0
- data/sig/pvectl/commands/restart_container.rbs +9 -0
- data/sig/pvectl/commands/restore_backup.rbs +27 -0
- data/sig/pvectl/commands/resume.rbs +11 -0
- data/sig/pvectl/commands/rollback_snapshot.rbs +31 -0
- data/sig/pvectl/commands/sendkey_vm.rbs +25 -0
- data/sig/pvectl/commands/service.rbs +38 -0
- data/sig/pvectl/commands/set_container.rbs +13 -0
- data/sig/pvectl/commands/set_node.rbs +13 -0
- data/sig/pvectl/commands/set_resource_command.rbs +25 -0
- data/sig/pvectl/commands/set_vm.rbs +15 -0
- data/sig/pvectl/commands/set_volume.rbs +24 -0
- data/sig/pvectl/commands/shared_config_parsers.rbs +19 -0
- data/sig/pvectl/commands/shared_flags.rbs +10 -0
- data/sig/pvectl/commands/shutdown.rbs +11 -0
- data/sig/pvectl/commands/shutdown_container.rbs +9 -0
- data/sig/pvectl/commands/start.rbs +11 -0
- data/sig/pvectl/commands/start_container.rbs +9 -0
- data/sig/pvectl/commands/stop.rbs +11 -0
- data/sig/pvectl/commands/stop_container.rbs +9 -0
- data/sig/pvectl/commands/suspend.rbs +11 -0
- data/sig/pvectl/commands/template_command.rbs +21 -0
- data/sig/pvectl/commands/template_container.rbs +10 -0
- data/sig/pvectl/commands/template_vm.rbs +12 -0
- data/sig/pvectl/commands/top/command.rbs +31 -0
- data/sig/pvectl/commands/top/handlers/containers.rbs +21 -0
- data/sig/pvectl/commands/top/handlers/nodes.rbs +21 -0
- data/sig/pvectl/commands/top/handlers/vms.rbs +21 -0
- data/sig/pvectl/commands/top/resource_handler.rbs +11 -0
- data/sig/pvectl/commands/top/resource_registry.rbs +8 -0
- data/sig/pvectl/commands/unlink_disk_vm.rbs +27 -0
- data/sig/pvectl/commands/vm_lifecycle_command.rbs +25 -0
- data/sig/pvectl/commands/wakeonlan_node.rbs +21 -0
- data/sig/pvectl/config/errors.rbs +24 -0
- data/sig/pvectl/config/models/cluster.rbs +39 -0
- data/sig/pvectl/config/models/context.rbs +23 -0
- data/sig/pvectl/config/models/resolved_config.rbs +51 -0
- data/sig/pvectl/config/models/user.rbs +31 -0
- data/sig/pvectl/config/provider.rbs +40 -0
- data/sig/pvectl/config/service.rbs +65 -0
- data/sig/pvectl/config/store.rbs +14 -0
- data/sig/pvectl/config/wizard.rbs +48 -0
- data/sig/pvectl/config_serializer.rbs +121 -0
- data/sig/pvectl/connection/retry_handler.rbs +31 -0
- data/sig/pvectl/connection.rbs +35 -0
- data/sig/pvectl/console/terminal_session.rbs +63 -0
- data/sig/pvectl/editor_session.rbs +33 -0
- data/sig/pvectl/exit_codes.rbs +19 -0
- data/sig/pvectl/formatters/base.rbs +13 -0
- data/sig/pvectl/formatters/color_support.rbs +13 -0
- data/sig/pvectl/formatters/json.rbs +7 -0
- data/sig/pvectl/formatters/output_helper.rbs +9 -0
- data/sig/pvectl/formatters/registry.rbs +13 -0
- data/sig/pvectl/formatters/table.rbs +25 -0
- data/sig/pvectl/formatters/wide.rbs +15 -0
- data/sig/pvectl/formatters/yaml.rbs +7 -0
- data/sig/pvectl/manifest_serializer.rbs +18 -0
- data/sig/pvectl/models/apt_package.rbs +26 -0
- data/sig/pvectl/models/backup.rbs +31 -0
- data/sig/pvectl/models/base.rbs +11 -0
- data/sig/pvectl/models/capability.rbs +16 -0
- data/sig/pvectl/models/container.rbs +44 -0
- data/sig/pvectl/models/container_operation_result.rbs +9 -0
- data/sig/pvectl/models/dns_config.rbs +15 -0
- data/sig/pvectl/models/hosts_file.rbs +13 -0
- data/sig/pvectl/models/journal_entry.rbs +10 -0
- data/sig/pvectl/models/network_interface.rbs +20 -0
- data/sig/pvectl/models/node.rbs +47 -0
- data/sig/pvectl/models/node_operation_result.rbs +12 -0
- data/sig/pvectl/models/operation_result.rbs +21 -0
- data/sig/pvectl/models/physical_disk.rbs +35 -0
- data/sig/pvectl/models/service.rbs +18 -0
- data/sig/pvectl/models/snapshot.rbs +21 -0
- data/sig/pvectl/models/snapshot_description.rbs +18 -0
- data/sig/pvectl/models/storage.rbs +39 -0
- data/sig/pvectl/models/subscription.rbs +24 -0
- data/sig/pvectl/models/syslog_entry.rbs +10 -0
- data/sig/pvectl/models/task.rbs +22 -0
- data/sig/pvectl/models/task_entry.rbs +24 -0
- data/sig/pvectl/models/task_log_line.rbs +10 -0
- data/sig/pvectl/models/time_config.rbs +12 -0
- data/sig/pvectl/models/vm.rbs +32 -0
- data/sig/pvectl/models/vm_operation_result.rbs +9 -0
- data/sig/pvectl/models/volume.rbs +29 -0
- data/sig/pvectl/models/volume_operation_result.rbs +9 -0
- data/sig/pvectl/parsers/cloud_init_config.rbs +15 -0
- data/sig/pvectl/parsers/disk_config.rbs +19 -0
- data/sig/pvectl/parsers/lxc_mount_config.rbs +19 -0
- data/sig/pvectl/parsers/lxc_net_config.rbs +19 -0
- data/sig/pvectl/parsers/net_config.rbs +19 -0
- data/sig/pvectl/parsers/smart_text.rbs +7 -0
- data/sig/pvectl/plugin_loader.rbs +25 -0
- data/sig/pvectl/presenters/apt_package.rbs +19 -0
- data/sig/pvectl/presenters/backup.rbs +25 -0
- data/sig/pvectl/presenters/base.rbs +41 -0
- data/sig/pvectl/presenters/capability.rbs +19 -0
- data/sig/pvectl/presenters/config/context.rbs +17 -0
- data/sig/pvectl/presenters/container.rbs +78 -0
- data/sig/pvectl/presenters/container_operation_result.rbs +19 -0
- data/sig/pvectl/presenters/disk.rbs +31 -0
- data/sig/pvectl/presenters/dns_config.rbs +13 -0
- data/sig/pvectl/presenters/hosts_file.rbs +13 -0
- data/sig/pvectl/presenters/journal_entry.rbs +11 -0
- data/sig/pvectl/presenters/node.rbs +118 -0
- data/sig/pvectl/presenters/node_operation_result.rbs +11 -0
- data/sig/pvectl/presenters/operation_result.rbs +17 -0
- data/sig/pvectl/presenters/service.rbs +15 -0
- data/sig/pvectl/presenters/snapshot.rbs +35 -0
- data/sig/pvectl/presenters/snapshot_operation_result.rbs +27 -0
- data/sig/pvectl/presenters/storage.rbs +59 -0
- data/sig/pvectl/presenters/subscription.rbs +36 -0
- data/sig/pvectl/presenters/syslog_entry.rbs +11 -0
- data/sig/pvectl/presenters/task_entry.rbs +21 -0
- data/sig/pvectl/presenters/task_log_line.rbs +11 -0
- data/sig/pvectl/presenters/template.rbs +15 -0
- data/sig/pvectl/presenters/time_config.rbs +19 -0
- data/sig/pvectl/presenters/top_container.rbs +17 -0
- data/sig/pvectl/presenters/top_node.rbs +17 -0
- data/sig/pvectl/presenters/top_presenter.rbs +13 -0
- data/sig/pvectl/presenters/top_vm.rbs +17 -0
- data/sig/pvectl/presenters/vm.rbs +91 -0
- data/sig/pvectl/presenters/vm_operation_result.rbs +19 -0
- data/sig/pvectl/presenters/volume.rbs +23 -0
- data/sig/pvectl/presenters/volume_operation_result.rbs +11 -0
- data/sig/pvectl/repositories/apt.rbs +17 -0
- data/sig/pvectl/repositories/backup.rbs +27 -0
- data/sig/pvectl/repositories/base.rbs +23 -0
- data/sig/pvectl/repositories/capabilities.rbs +20 -0
- data/sig/pvectl/repositories/container.rbs +63 -0
- data/sig/pvectl/repositories/disk.rbs +17 -0
- data/sig/pvectl/repositories/dns.rbs +13 -0
- data/sig/pvectl/repositories/hosts.rbs +13 -0
- data/sig/pvectl/repositories/journal.rbs +7 -0
- data/sig/pvectl/repositories/node.rbs +68 -0
- data/sig/pvectl/repositories/service.rbs +27 -0
- data/sig/pvectl/repositories/snapshot.rbs +19 -0
- data/sig/pvectl/repositories/storage.rbs +37 -0
- data/sig/pvectl/repositories/subscription.rbs +17 -0
- data/sig/pvectl/repositories/syslog.rbs +7 -0
- data/sig/pvectl/repositories/task.rbs +19 -0
- data/sig/pvectl/repositories/task_list.rbs +7 -0
- data/sig/pvectl/repositories/task_log.rbs +11 -0
- data/sig/pvectl/repositories/time_config.rbs +13 -0
- data/sig/pvectl/repositories/vm.rbs +85 -0
- data/sig/pvectl/repositories/volume.rbs +43 -0
- data/sig/pvectl/selectors/base.rbs +37 -0
- data/sig/pvectl/selectors/container.rbs +19 -0
- data/sig/pvectl/selectors/disk.rbs +13 -0
- data/sig/pvectl/selectors/vm.rbs +19 -0
- data/sig/pvectl/selectors/volume.rbs +13 -0
- data/sig/pvectl/services/backup.rbs +27 -0
- data/sig/pvectl/services/clone_container.rbs +35 -0
- data/sig/pvectl/services/clone_vm.rbs +35 -0
- data/sig/pvectl/services/cloudinit.rbs +19 -0
- data/sig/pvectl/services/console.rbs +23 -0
- data/sig/pvectl/services/container_lifecycle.rbs +26 -0
- data/sig/pvectl/services/create_container.rbs +64 -0
- data/sig/pvectl/services/create_vm.rbs +72 -0
- data/sig/pvectl/services/edit_container.rbs +17 -0
- data/sig/pvectl/services/edit_dns.rbs +23 -0
- data/sig/pvectl/services/edit_hosts.rbs +13 -0
- data/sig/pvectl/services/edit_node.rbs +21 -0
- data/sig/pvectl/services/edit_vm.rbs +17 -0
- data/sig/pvectl/services/edit_volume.rbs +18 -0
- data/sig/pvectl/services/get/resource_service.rbs +23 -0
- data/sig/pvectl/services/move_disk.rbs +21 -0
- data/sig/pvectl/services/pull_config.rbs +18 -0
- data/sig/pvectl/services/push_config.rbs +37 -0
- data/sig/pvectl/services/resize_volume.rbs +47 -0
- data/sig/pvectl/services/resource_delete.rbs +27 -0
- data/sig/pvectl/services/resource_migration.rbs +29 -0
- data/sig/pvectl/services/sendkey.rbs +19 -0
- data/sig/pvectl/services/service_lifecycle.rbs +17 -0
- data/sig/pvectl/services/set_container.rbs +14 -0
- data/sig/pvectl/services/set_node.rbs +23 -0
- data/sig/pvectl/services/set_vm.rbs +14 -0
- data/sig/pvectl/services/set_volume.rbs +12 -0
- data/sig/pvectl/services/snapshot.rbs +35 -0
- data/sig/pvectl/services/task_listing.rbs +13 -0
- data/sig/pvectl/services/unlink_disk.rbs +17 -0
- data/sig/pvectl/services/vm_lifecycle.rbs +26 -0
- data/sig/pvectl/services/wakeonlan.rbs +17 -0
- data/sig/pvectl/utils/resource_resolver.rbs +17 -0
- data/sig/pvectl/wizards/create_container.rbs +21 -0
- data/sig/pvectl/wizards/create_vm.rbs +21 -0
- data/sig/pvectl.rbs +9 -0
- metadata +675 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Presenters
|
|
5
|
+
# Presenter for VM lifecycle operation results.
|
|
6
|
+
#
|
|
7
|
+
# Formats VmOperationResult models for table/JSON/YAML output.
|
|
8
|
+
#
|
|
9
|
+
# @example Using with formatter
|
|
10
|
+
# presenter = VmOperationResult.new
|
|
11
|
+
# formatter = Formatters::Table.new
|
|
12
|
+
# output = formatter.format(results, presenter)
|
|
13
|
+
#
|
|
14
|
+
class VmOperationResult < OperationResult
|
|
15
|
+
# Returns column headers for standard table output.
|
|
16
|
+
#
|
|
17
|
+
# @return [Array<String>] column headers
|
|
18
|
+
def columns
|
|
19
|
+
%w[VMID NAME NODE STATUS MESSAGE]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns additional columns for wide output.
|
|
23
|
+
#
|
|
24
|
+
# @return [Array<String>] extra column headers
|
|
25
|
+
def extra_columns
|
|
26
|
+
%w[TASK DURATION]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Converts result to table row values.
|
|
30
|
+
#
|
|
31
|
+
# For clone operations, displays the new (cloned) VM data.
|
|
32
|
+
# For all other operations, displays the source VM data.
|
|
33
|
+
#
|
|
34
|
+
# @param model [Models::VmOperationResult] result model
|
|
35
|
+
# @param context [Hash] optional context
|
|
36
|
+
# @return [Array<String>] row values
|
|
37
|
+
def to_row(model, **_context)
|
|
38
|
+
if model.operation == :clone && model.resource
|
|
39
|
+
[
|
|
40
|
+
model.resource[:new_vmid].to_s,
|
|
41
|
+
model.resource[:name] || "VM-#{model.resource[:new_vmid]}",
|
|
42
|
+
model.resource[:node] || model.vm&.node,
|
|
43
|
+
status_display(model),
|
|
44
|
+
model.message
|
|
45
|
+
]
|
|
46
|
+
else
|
|
47
|
+
[
|
|
48
|
+
model.vm.vmid.to_s,
|
|
49
|
+
display_name(model.vm),
|
|
50
|
+
model.vm.node,
|
|
51
|
+
status_display(model),
|
|
52
|
+
model.message
|
|
53
|
+
]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Returns additional values for wide output.
|
|
58
|
+
#
|
|
59
|
+
# @param model [Models::VmOperationResult] result model
|
|
60
|
+
# @param context [Hash] optional context
|
|
61
|
+
# @return [Array<String>] extra values
|
|
62
|
+
def extra_values(model, **_context)
|
|
63
|
+
[
|
|
64
|
+
task_upid(model),
|
|
65
|
+
duration_display(model)
|
|
66
|
+
]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Converts result to hash for JSON/YAML output.
|
|
70
|
+
#
|
|
71
|
+
# For clone operations, displays the new (cloned) VM data.
|
|
72
|
+
# For all other operations, displays the source VM data.
|
|
73
|
+
#
|
|
74
|
+
# @param model [Models::VmOperationResult] result model
|
|
75
|
+
# @return [Hash] hash representation
|
|
76
|
+
def to_hash(model)
|
|
77
|
+
if model.operation == :clone && model.resource
|
|
78
|
+
{
|
|
79
|
+
"vmid" => model.resource[:new_vmid],
|
|
80
|
+
"name" => model.resource[:name],
|
|
81
|
+
"node" => model.resource[:node] || model.vm&.node,
|
|
82
|
+
"status" => model.status_text,
|
|
83
|
+
"message" => model.message,
|
|
84
|
+
"task_upid" => model.task_upid || model.task&.upid
|
|
85
|
+
}
|
|
86
|
+
else
|
|
87
|
+
{
|
|
88
|
+
"vmid" => model.vm.vmid,
|
|
89
|
+
"name" => model.vm.name,
|
|
90
|
+
"node" => model.vm.node,
|
|
91
|
+
"status" => model.status_text,
|
|
92
|
+
"message" => model.message,
|
|
93
|
+
"task_upid" => model.task_upid || model.task&.upid
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
# Returns display name for VM.
|
|
101
|
+
#
|
|
102
|
+
# @param vm [Models::Vm] VM model
|
|
103
|
+
# @return [String] display name
|
|
104
|
+
def display_name(vm)
|
|
105
|
+
vm.name || "VM-#{vm.vmid}"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Presenters
|
|
5
|
+
# Presenter for virtual disks (volumes) attached to VMs and containers.
|
|
6
|
+
#
|
|
7
|
+
# Defines column layout and formatting for table output.
|
|
8
|
+
# Standard columns show node, resource type, ID, name, storage, size, and format.
|
|
9
|
+
# Wide columns add volume ID, cache, discard, SSD, iothread, and backup flags.
|
|
10
|
+
#
|
|
11
|
+
# @example Using with formatter
|
|
12
|
+
# presenter = Volume.new
|
|
13
|
+
# formatter = Formatters::Table.new
|
|
14
|
+
# output = formatter.format(volumes, presenter)
|
|
15
|
+
#
|
|
16
|
+
# @see Pvectl::Models::Volume Volume model
|
|
17
|
+
# @see Pvectl::Formatters::Table Table formatter
|
|
18
|
+
#
|
|
19
|
+
class Volume < Base
|
|
20
|
+
# Returns column headers for standard table output.
|
|
21
|
+
#
|
|
22
|
+
# @return [Array<String>] column headers
|
|
23
|
+
def columns
|
|
24
|
+
%w[NODE RESOURCE ID NAME STORAGE SIZE FORMAT]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Returns additional column headers for wide output.
|
|
28
|
+
#
|
|
29
|
+
# @return [Array<String>] extra column headers
|
|
30
|
+
def extra_columns
|
|
31
|
+
%w[VOLUME-ID CACHE DISCARD SSD IOTHREAD BACKUP]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Converts Volume model to table row values.
|
|
35
|
+
#
|
|
36
|
+
# @param model [Models::Volume] Volume model
|
|
37
|
+
# @param _context [Hash] optional context
|
|
38
|
+
# @return [Array<String>] row values matching columns order
|
|
39
|
+
def to_row(model, **_context)
|
|
40
|
+
@volume = model
|
|
41
|
+
[
|
|
42
|
+
volume.node || "-",
|
|
43
|
+
volume.resource_type || "-",
|
|
44
|
+
volume.resource_id&.to_s || "-",
|
|
45
|
+
volume.name || "-",
|
|
46
|
+
volume.storage || "-",
|
|
47
|
+
volume.size || "-",
|
|
48
|
+
volume.format || "-"
|
|
49
|
+
]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns additional values for wide output.
|
|
53
|
+
#
|
|
54
|
+
# @param model [Models::Volume] Volume model
|
|
55
|
+
# @param _context [Hash] optional context
|
|
56
|
+
# @return [Array<String>] extra values matching extra_columns order
|
|
57
|
+
def extra_values(model, **_context)
|
|
58
|
+
@volume = model
|
|
59
|
+
[
|
|
60
|
+
volume.volume_id || "-",
|
|
61
|
+
volume.cache || "-",
|
|
62
|
+
volume.discard || "-",
|
|
63
|
+
volume.ssd&.to_s || "-",
|
|
64
|
+
volume.iothread&.to_s || "-",
|
|
65
|
+
volume.backup&.to_s || "-"
|
|
66
|
+
]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Converts Volume model to hash for JSON/YAML output.
|
|
70
|
+
#
|
|
71
|
+
# @param model [Models::Volume] Volume model
|
|
72
|
+
# @return [Hash{String => untyped}] hash representation with string keys
|
|
73
|
+
def to_hash(model)
|
|
74
|
+
@volume = model
|
|
75
|
+
{
|
|
76
|
+
"name" => volume.name,
|
|
77
|
+
"storage" => volume.storage,
|
|
78
|
+
"volume_id" => volume.volume_id,
|
|
79
|
+
"volid" => volume.volid,
|
|
80
|
+
"size" => volume.size,
|
|
81
|
+
"format" => volume.format,
|
|
82
|
+
"resource_type" => volume.resource_type,
|
|
83
|
+
"resource_id" => volume.resource_id,
|
|
84
|
+
"node" => volume.node,
|
|
85
|
+
"content" => volume.content,
|
|
86
|
+
"cache" => volume.cache,
|
|
87
|
+
"discard" => volume.discard,
|
|
88
|
+
"ssd" => volume.ssd,
|
|
89
|
+
"iothread" => volume.iothread,
|
|
90
|
+
"backup" => volume.backup,
|
|
91
|
+
"mp" => volume.mp
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Returns detailed description for describe command output.
|
|
96
|
+
#
|
|
97
|
+
# @param model [Models::Volume] Volume model
|
|
98
|
+
# @return [Hash{String => Hash{String, String}}] nested hash with Volume Info section
|
|
99
|
+
def to_description(model)
|
|
100
|
+
@volume = model
|
|
101
|
+
{ "Volume Info" => volume_info_section }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
# @return [Models::Volume] the current volume being presented
|
|
107
|
+
attr_reader :volume
|
|
108
|
+
|
|
109
|
+
# Builds the Volume Info section hash.
|
|
110
|
+
# Optional fields are only included when they have values.
|
|
111
|
+
#
|
|
112
|
+
# @return [Hash{String => String}] volume info key-value pairs
|
|
113
|
+
def volume_info_section
|
|
114
|
+
info = {
|
|
115
|
+
"Name" => volume.name || "-",
|
|
116
|
+
"Storage" => volume.storage || "-",
|
|
117
|
+
"Volume ID" => volume.volume_id || "-",
|
|
118
|
+
"Full Volume ID" => volume.volid || "-",
|
|
119
|
+
"Size" => volume.size || "-",
|
|
120
|
+
"Format" => volume.format || "-",
|
|
121
|
+
"Resource Type" => volume.resource_type || "-",
|
|
122
|
+
"Resource ID" => volume.resource_id&.to_s || "-",
|
|
123
|
+
"Node" => volume.node || "-"
|
|
124
|
+
}
|
|
125
|
+
info["Content"] = volume.content if volume.content
|
|
126
|
+
info["Cache"] = volume.cache if volume.cache
|
|
127
|
+
info["Discard"] = volume.discard if volume.discard
|
|
128
|
+
info["SSD"] = volume.ssd if volume.ssd
|
|
129
|
+
info["IO Thread"] = volume.iothread if volume.iothread
|
|
130
|
+
info["Backup"] = volume.backup if volume.backup
|
|
131
|
+
info["Mount Point"] = volume.mp if volume.mp
|
|
132
|
+
info
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Presenters
|
|
5
|
+
# Presenter for volume operation results (set/edit).
|
|
6
|
+
#
|
|
7
|
+
# Formats VolumeOperationResult models for table/JSON/YAML output.
|
|
8
|
+
#
|
|
9
|
+
# @example Using with formatter
|
|
10
|
+
# presenter = VolumeOperationResult.new
|
|
11
|
+
# formatter = Formatters::Table.new
|
|
12
|
+
# output = formatter.format(results, presenter)
|
|
13
|
+
#
|
|
14
|
+
class VolumeOperationResult < OperationResult
|
|
15
|
+
# Returns column headers for standard table output.
|
|
16
|
+
#
|
|
17
|
+
# @return [Array<String>] column headers
|
|
18
|
+
def columns
|
|
19
|
+
%w[NODE RESOURCE ID DISK OPERATION STATUS MESSAGE]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Converts result to table row values.
|
|
23
|
+
#
|
|
24
|
+
# @param model [Models::VolumeOperationResult] result model
|
|
25
|
+
# @param context [Hash] optional context
|
|
26
|
+
# @return [Array<String>] row values
|
|
27
|
+
def to_row(model, **_context)
|
|
28
|
+
vol = model.volume
|
|
29
|
+
[
|
|
30
|
+
vol&.node || "-",
|
|
31
|
+
vol&.resource_type || "-",
|
|
32
|
+
vol&.resource_id&.to_s || "-",
|
|
33
|
+
vol&.name || "-",
|
|
34
|
+
model.operation&.to_s || "-",
|
|
35
|
+
status_display(model),
|
|
36
|
+
model.message
|
|
37
|
+
]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Converts result to hash for JSON/YAML output.
|
|
41
|
+
#
|
|
42
|
+
# @param model [Models::VolumeOperationResult] result model
|
|
43
|
+
# @return [Hash] hash representation
|
|
44
|
+
def to_hash(model)
|
|
45
|
+
vol = model.volume
|
|
46
|
+
{
|
|
47
|
+
"node" => vol&.node,
|
|
48
|
+
"resource_type" => vol&.resource_type,
|
|
49
|
+
"resource_id" => vol&.resource_id,
|
|
50
|
+
"disk" => vol&.name,
|
|
51
|
+
"operation" => model.operation&.to_s,
|
|
52
|
+
"status" => model.status_text,
|
|
53
|
+
"message" => model.message
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Repositories
|
|
5
|
+
# Repository for Proxmox APT package management on cluster nodes.
|
|
6
|
+
#
|
|
7
|
+
# Wraps the `/nodes/{node}/apt/*` API endpoints. Provides:
|
|
8
|
+
# - listing pending package updates (GET /apt/update)
|
|
9
|
+
# - refreshing the package index (POST /apt/update — apt-get update)
|
|
10
|
+
# - reading per-package changelogs (GET /apt/changelog)
|
|
11
|
+
# - listing important Proxmox package versions (GET /apt/versions)
|
|
12
|
+
#
|
|
13
|
+
# @example Listing pending updates on a node
|
|
14
|
+
# repo = Apt.new(connection)
|
|
15
|
+
# updates = repo.pending("pve1")
|
|
16
|
+
# updates.each { |p| puts "#{p.package}: #{p.old_version} -> #{p.version}" }
|
|
17
|
+
#
|
|
18
|
+
# @example Triggering a package index refresh
|
|
19
|
+
# upid = repo.refresh("pve1", notify: false, quiet: true)
|
|
20
|
+
#
|
|
21
|
+
# @see Pvectl::Models::AptPackage AptPackage model
|
|
22
|
+
# @see Pvectl::Connection API connection
|
|
23
|
+
#
|
|
24
|
+
class Apt < Base
|
|
25
|
+
# Lists pending APT updates available on a node.
|
|
26
|
+
#
|
|
27
|
+
# @param node [String] node name
|
|
28
|
+
# @return [Array<Models::AptPackage>] pending package updates
|
|
29
|
+
def pending(node)
|
|
30
|
+
response = connection.client["nodes/#{node}/apt/update"].get
|
|
31
|
+
packages = unwrap(response)
|
|
32
|
+
packages.map { |data| build_model(data.merge(node: node)) }
|
|
33
|
+
rescue StandardError
|
|
34
|
+
[]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Refreshes the package index on a node (equivalent to apt-get update).
|
|
38
|
+
#
|
|
39
|
+
# Returns the Proxmox task UPID — the operation runs asynchronously.
|
|
40
|
+
#
|
|
41
|
+
# @param node [String] node name
|
|
42
|
+
# @param notify [Boolean] whether to send a notification about new packages
|
|
43
|
+
# @param quiet [Boolean] whether to suppress progress output
|
|
44
|
+
# @return [String] task UPID
|
|
45
|
+
def refresh(node, notify: false, quiet: false)
|
|
46
|
+
params = {}
|
|
47
|
+
params[:notify] = 1 if notify
|
|
48
|
+
params[:quiet] = 1 if quiet
|
|
49
|
+
response = connection.client["nodes/#{node}/apt/update"].post(params)
|
|
50
|
+
data = extract_data(response)
|
|
51
|
+
data.is_a?(String) ? data : data.to_s
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Fetches the changelog for a package on a node.
|
|
55
|
+
#
|
|
56
|
+
# @param node [String] node name
|
|
57
|
+
# @param package [String] package name
|
|
58
|
+
# @param version [String, nil] specific package version (optional)
|
|
59
|
+
# @return [String] changelog text (empty string on error)
|
|
60
|
+
def changelog(node, package, version: nil)
|
|
61
|
+
params = { name: package }
|
|
62
|
+
params[:version] = version if version
|
|
63
|
+
response = connection.client["nodes/#{node}/apt/changelog"].get(params: params)
|
|
64
|
+
data = extract_data(response)
|
|
65
|
+
data.is_a?(String) ? data : data.to_s
|
|
66
|
+
rescue StandardError
|
|
67
|
+
""
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Lists important Proxmox package versions installed on a node.
|
|
71
|
+
#
|
|
72
|
+
# @param node [String] node name
|
|
73
|
+
# @return [Array<Models::AptPackage>] installed package versions
|
|
74
|
+
def versions(node)
|
|
75
|
+
response = connection.client["nodes/#{node}/apt/versions"].get
|
|
76
|
+
packages = unwrap(response)
|
|
77
|
+
packages.map { |data| build_model(data.merge(node: node)) }
|
|
78
|
+
rescue StandardError
|
|
79
|
+
[]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
protected
|
|
83
|
+
|
|
84
|
+
# Builds AptPackage model from API response data.
|
|
85
|
+
#
|
|
86
|
+
# @param data [Hash] API response hash
|
|
87
|
+
# @return [Models::AptPackage] AptPackage model instance
|
|
88
|
+
def build_model(data)
|
|
89
|
+
Models::AptPackage.new(data)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
|
|
5
|
+
module Pvectl
|
|
6
|
+
module Repositories
|
|
7
|
+
# Repository for backup operations in Proxmox.
|
|
8
|
+
#
|
|
9
|
+
# Handles listing, creating, deleting, and restoring backups
|
|
10
|
+
# via the Proxmox API (vzdump).
|
|
11
|
+
#
|
|
12
|
+
# @example Listing backups
|
|
13
|
+
# repo = Backup.new(connection)
|
|
14
|
+
# backups = repo.list(node: "pve1", storage: "local")
|
|
15
|
+
#
|
|
16
|
+
# @example Creating a backup
|
|
17
|
+
# upid = repo.create(100, "pve1", storage: "local", mode: "snapshot")
|
|
18
|
+
#
|
|
19
|
+
# @example Restoring a backup
|
|
20
|
+
# upid = repo.restore("local:backup/vzdump-qemu-100.vma.zst", "pve1", vmid: 200)
|
|
21
|
+
#
|
|
22
|
+
# @see Pvectl::Models::Backup Backup model
|
|
23
|
+
# @see Pvectl::Connection API connection
|
|
24
|
+
#
|
|
25
|
+
class Backup < Base
|
|
26
|
+
# Lists backups from storage.
|
|
27
|
+
#
|
|
28
|
+
# When node and storage are not specified, discovers all nodes and
|
|
29
|
+
# backup-capable storages automatically.
|
|
30
|
+
#
|
|
31
|
+
# @param vmid [Integer, nil] filter by VM ID
|
|
32
|
+
# @param storage [String, nil] storage name (default: all backup storages)
|
|
33
|
+
# @param node [String, nil] node name (default: all nodes)
|
|
34
|
+
# @return [Array<Models::Backup>] backup models
|
|
35
|
+
def list(vmid: nil, storage: nil, node: nil)
|
|
36
|
+
nodes = node ? [node] : list_nodes
|
|
37
|
+
storages_by_node = storage ? Hash[nodes.map { |n| [n, [storage]] }] : nil
|
|
38
|
+
|
|
39
|
+
backups = []
|
|
40
|
+
nodes.each do |n|
|
|
41
|
+
backup_storages = storages_by_node ? storages_by_node[n] : list_backup_storages(n)
|
|
42
|
+
backup_storages.each do |s|
|
|
43
|
+
backups.concat(list_from_storage(n, s, vmid: vmid))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
backups
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Creates a backup using vzdump.
|
|
50
|
+
#
|
|
51
|
+
# @param vmid [Integer] VM/container ID
|
|
52
|
+
# @param node [String] node name
|
|
53
|
+
# @param storage [String] target storage
|
|
54
|
+
# @param mode [String] backup mode (snapshot, suspend, stop)
|
|
55
|
+
# @param compress [String] compression (zstd, gzip, lzo, 0)
|
|
56
|
+
# @param notes [String, nil] backup notes
|
|
57
|
+
# @param protected [Boolean] protect from deletion
|
|
58
|
+
# @return [String] task UPID
|
|
59
|
+
def create(vmid, node, storage:, mode: "snapshot", compress: "zstd", notes: nil, protected: false)
|
|
60
|
+
params = {
|
|
61
|
+
vmid: vmid,
|
|
62
|
+
storage: storage,
|
|
63
|
+
mode: mode,
|
|
64
|
+
compress: compress
|
|
65
|
+
}
|
|
66
|
+
params[:notes] = notes if notes
|
|
67
|
+
params[:protected] = 1 if protected
|
|
68
|
+
|
|
69
|
+
connection.client["nodes/#{node}/vzdump"].post(params)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Deletes a backup.
|
|
73
|
+
#
|
|
74
|
+
# @param volid [String] full volume ID
|
|
75
|
+
# @param node [String] node name
|
|
76
|
+
# @return [String, nil] task UPID or nil
|
|
77
|
+
def delete(volid, node)
|
|
78
|
+
storage = parse_storage(volid)
|
|
79
|
+
encoded_volid = ERB::Util.url_encode(volid)
|
|
80
|
+
connection.client["nodes/#{node}/storage/#{storage}/content/#{encoded_volid}"].delete
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Restores a backup to a new or existing VM/container.
|
|
84
|
+
#
|
|
85
|
+
# @param volid [String] backup volume ID
|
|
86
|
+
# @param node [String] node name
|
|
87
|
+
# @param vmid [Integer] target VM ID
|
|
88
|
+
# @param storage [String, nil] target storage
|
|
89
|
+
# @param force [Boolean] overwrite existing VM
|
|
90
|
+
# @param start [Boolean] start after restore
|
|
91
|
+
# @param unique [Boolean] regenerate unique properties
|
|
92
|
+
# @return [String] task UPID
|
|
93
|
+
def restore(volid, node, vmid:, storage: nil, force: false, start: false, unique: false)
|
|
94
|
+
resource_type = detect_type_from_volid(volid)
|
|
95
|
+
endpoint = resource_type == :lxc ? "lxc" : "qemu"
|
|
96
|
+
|
|
97
|
+
params = {
|
|
98
|
+
archive: volid,
|
|
99
|
+
vmid: vmid
|
|
100
|
+
}
|
|
101
|
+
params[:storage] = storage if storage
|
|
102
|
+
params[:force] = 1 if force
|
|
103
|
+
params[:start] = 1 if start
|
|
104
|
+
params[:unique] = 1 if unique
|
|
105
|
+
|
|
106
|
+
connection.client["nodes/#{node}/#{endpoint}"].post(params)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# Lists all nodes in the cluster.
|
|
112
|
+
#
|
|
113
|
+
# @return [Array<String>] node names
|
|
114
|
+
def list_nodes
|
|
115
|
+
response = connection.client["nodes"].get
|
|
116
|
+
response.map { |n| n[:node] || n["node"] }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Lists storages that support backup content on a node.
|
|
120
|
+
#
|
|
121
|
+
# @param node [String] node name
|
|
122
|
+
# @return [Array<String>] storage names with backup capability
|
|
123
|
+
def list_backup_storages(node)
|
|
124
|
+
response = connection.client["nodes/#{node}/storage"].get
|
|
125
|
+
response.select do |s|
|
|
126
|
+
content = s[:content] || s["content"] || ""
|
|
127
|
+
content.include?("backup")
|
|
128
|
+
end.map { |s| s[:storage] || s["storage"] }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Lists backups from a specific storage on a node.
|
|
132
|
+
#
|
|
133
|
+
# @param node [String] node name
|
|
134
|
+
# @param storage [String] storage name
|
|
135
|
+
# @param vmid [Integer, nil] optional VM ID filter
|
|
136
|
+
# @return [Array<Models::Backup>] backup models
|
|
137
|
+
def list_from_storage(node, storage, vmid: nil)
|
|
138
|
+
response = connection.client["nodes/#{node}/storage/#{storage}/content"].get(params: { content: "backup" })
|
|
139
|
+
|
|
140
|
+
backups = response.map do |data|
|
|
141
|
+
build_backup_model(data, node, storage)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
vmid ? backups.select { |b| b.vmid == vmid } : backups
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Builds a Backup model from API response data.
|
|
148
|
+
#
|
|
149
|
+
# @param data [Hash] API response hash
|
|
150
|
+
# @param node [String] node name
|
|
151
|
+
# @param storage [String] storage name
|
|
152
|
+
# @return [Models::Backup] backup model instance
|
|
153
|
+
def build_backup_model(data, node, storage)
|
|
154
|
+
Models::Backup.new(
|
|
155
|
+
volid: data[:volid] || data["volid"],
|
|
156
|
+
vmid: data[:vmid] || data["vmid"],
|
|
157
|
+
node: node,
|
|
158
|
+
storage: storage,
|
|
159
|
+
size: data[:size] || data["size"],
|
|
160
|
+
ctime: data[:ctime] || data["ctime"],
|
|
161
|
+
format: data[:format] || data["format"],
|
|
162
|
+
notes: data[:notes] || data["notes"],
|
|
163
|
+
protected: (data[:protected] || data["protected"]) == 1
|
|
164
|
+
)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Extracts storage name from volid.
|
|
168
|
+
#
|
|
169
|
+
# @param volid [String] full volume identifier
|
|
170
|
+
# @return [String] storage name
|
|
171
|
+
def parse_storage(volid)
|
|
172
|
+
volid.split(":").first
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Detects resource type from volid pattern.
|
|
176
|
+
#
|
|
177
|
+
# @param volid [String] backup volume identifier
|
|
178
|
+
# @return [Symbol] :qemu or :lxc
|
|
179
|
+
def detect_type_from_volid(volid)
|
|
180
|
+
return :lxc if volid.include?("vzdump-lxc")
|
|
181
|
+
|
|
182
|
+
:qemu
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Repositories
|
|
5
|
+
# Abstract base class for repositories.
|
|
6
|
+
#
|
|
7
|
+
# Repositories encapsulate Proxmox API communication and are responsible
|
|
8
|
+
# for converting raw API data to domain models. Each repository handles
|
|
9
|
+
# one resource type (VMs, Containers, Nodes, etc.).
|
|
10
|
+
#
|
|
11
|
+
# @abstract Subclass and implement {#list}, {#get}, and {#build_model}.
|
|
12
|
+
#
|
|
13
|
+
# @example Implementing a repository
|
|
14
|
+
# class Vm < Base
|
|
15
|
+
# def list(node: nil)
|
|
16
|
+
# response = connection.client["cluster/resources"].get(params: { type: "vm" })
|
|
17
|
+
# response.map { |data| build_model(data) }
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# def get(vmid)
|
|
21
|
+
# list.find { |vm| vm.vmid == vmid.to_i }
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# protected
|
|
25
|
+
#
|
|
26
|
+
# def build_model(data)
|
|
27
|
+
# Models::Vm.new(data)
|
|
28
|
+
# end
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# @see Pvectl::Connection API connection wrapper
|
|
32
|
+
# @see Pvectl::Models::Base Model base class
|
|
33
|
+
#
|
|
34
|
+
class Base
|
|
35
|
+
# Creates repository with connection.
|
|
36
|
+
#
|
|
37
|
+
# @param connection [Connection] Proxmox API connection
|
|
38
|
+
def initialize(connection)
|
|
39
|
+
@connection = connection
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Lists all resources.
|
|
43
|
+
#
|
|
44
|
+
# @return [Array<Models::Base>] collection of models
|
|
45
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
46
|
+
def list
|
|
47
|
+
raise NotImplementedError, "#{self.class}#list must be implemented"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Gets a single resource by ID.
|
|
51
|
+
#
|
|
52
|
+
# @param id [String, Integer] resource identifier
|
|
53
|
+
# @return [Models::Base, nil] model or nil if not found
|
|
54
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
55
|
+
def get(id)
|
|
56
|
+
raise NotImplementedError, "#{self.class}#get must be implemented"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
protected
|
|
60
|
+
|
|
61
|
+
# @return [Connection] the API connection
|
|
62
|
+
attr_reader :connection
|
|
63
|
+
|
|
64
|
+
# Builds model from API response data.
|
|
65
|
+
#
|
|
66
|
+
# @param data [Hash] API response hash
|
|
67
|
+
# @return [Models::Base] model instance
|
|
68
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
69
|
+
def build_model(data)
|
|
70
|
+
raise NotImplementedError, "#{self.class}#build_model must be implemented"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Unwraps API response to array format.
|
|
74
|
+
# Handles: Array (passthrough), Hash with :data key, Hash without :data.
|
|
75
|
+
#
|
|
76
|
+
# @param response [Array, Hash, nil] API response
|
|
77
|
+
# @return [Array] unwrapped array
|
|
78
|
+
def unwrap(response)
|
|
79
|
+
case response
|
|
80
|
+
when Array then response
|
|
81
|
+
when Hash then response[:data] || response.to_a
|
|
82
|
+
when nil then []
|
|
83
|
+
else response.to_a
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Extracts data from hash response.
|
|
88
|
+
# If response has :data key, returns its value. Otherwise returns response.
|
|
89
|
+
#
|
|
90
|
+
# @param response [Hash, Object] API response
|
|
91
|
+
# @return [Hash, Object] extracted data
|
|
92
|
+
def extract_data(response)
|
|
93
|
+
return response unless response.is_a?(Hash)
|
|
94
|
+
|
|
95
|
+
response[:data] || response
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Creates model instances from API response.
|
|
99
|
+
#
|
|
100
|
+
# @param response [Array, Hash, nil] API response (will be unwrapped)
|
|
101
|
+
# @param model_class [Class] model class to instantiate
|
|
102
|
+
# @return [Array] array of model instances
|
|
103
|
+
def models_from(response, model_class)
|
|
104
|
+
return [] if response.nil?
|
|
105
|
+
|
|
106
|
+
unwrap(response).map { |data| model_class.new(data) }
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|