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,230 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
# Shared functionality for the feature query commands (feature vm, feature ct).
|
|
6
|
+
#
|
|
7
|
+
# Queries whether a Proxmox feature (clone, snapshot, copy) is available for
|
|
8
|
+
# a given VM or container. Availability depends on storage type, snapshot
|
|
9
|
+
# state, and other server-side conditions.
|
|
10
|
+
#
|
|
11
|
+
# Designed with the hybrid Template Method pattern (MoveDiskCommand /
|
|
12
|
+
# MigrateCommand) — specializations only set RESOURCE_TYPE and
|
|
13
|
+
# SUPPORTED_RESOURCES; the FeatureVm specialization additionally implements
|
|
14
|
+
# +.register+ which wires the GLI command.
|
|
15
|
+
#
|
|
16
|
+
# @example Including in a command class
|
|
17
|
+
# class FeatureVm
|
|
18
|
+
# include FeatureCommand
|
|
19
|
+
# RESOURCE_TYPE = :vm
|
|
20
|
+
# SUPPORTED_RESOURCES = %w[vm].freeze
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
module FeatureCommand
|
|
24
|
+
# Valid feature names per Proxmox API (both QEMU and LXC endpoints).
|
|
25
|
+
VALID_FEATURES = %w[clone snapshot copy].freeze
|
|
26
|
+
|
|
27
|
+
# Class methods added when the module is included.
|
|
28
|
+
module ClassMethods
|
|
29
|
+
# Executes the feature query command.
|
|
30
|
+
#
|
|
31
|
+
# @param args [Array<String>] command-positional args ([id, feature])
|
|
32
|
+
# @param options [Hash] command options
|
|
33
|
+
# @param global_options [Hash] global CLI options
|
|
34
|
+
# @return [Integer] exit code
|
|
35
|
+
def execute(args, options, global_options)
|
|
36
|
+
new(args, options, global_options).execute
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Hook called when the module is included.
|
|
41
|
+
#
|
|
42
|
+
# @param base [Class] the class including this module
|
|
43
|
+
def self.included(base)
|
|
44
|
+
base.extend(ClassMethods)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Initializes a feature query command.
|
|
48
|
+
#
|
|
49
|
+
# @param args [Array<String>] command-positional args ([id, feature])
|
|
50
|
+
# @param options [Hash] command options
|
|
51
|
+
# @param global_options [Hash] global CLI options
|
|
52
|
+
def initialize(args, options, global_options)
|
|
53
|
+
@args = Array(args).compact
|
|
54
|
+
@options = options
|
|
55
|
+
@global_options = global_options
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Executes the feature query.
|
|
59
|
+
#
|
|
60
|
+
# @return [Integer] exit code (0 if available, 1 if unavailable, 2 on usage)
|
|
61
|
+
def execute
|
|
62
|
+
return usage_error("#{id_label} is required") if @args.empty?
|
|
63
|
+
return usage_error("FEATURE is required") if @args.size < 2
|
|
64
|
+
|
|
65
|
+
id_str = @args[0]
|
|
66
|
+
feature = @args[1]
|
|
67
|
+
|
|
68
|
+
unless id_str.to_s.match?(/\A\d+\z/)
|
|
69
|
+
return usage_error("Invalid #{id_label}: #{id_str}")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
unless VALID_FEATURES.include?(feature)
|
|
73
|
+
return usage_error(
|
|
74
|
+
"Invalid feature: #{feature} (allowed: #{VALID_FEATURES.join(', ')})"
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
perform_operation(id_str.to_i, feature)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
# Returns the resource type symbol (:vm or :container).
|
|
84
|
+
#
|
|
85
|
+
# @return [Symbol]
|
|
86
|
+
def resource_type_symbol
|
|
87
|
+
self.class::RESOURCE_TYPE
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Returns the human label for the resource ID ("VMID" or "CTID").
|
|
91
|
+
#
|
|
92
|
+
# @return [String]
|
|
93
|
+
def id_label
|
|
94
|
+
resource_type_symbol == :vm ? "VMID" : "CTID"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Returns the singular type name ("VM" or "container") used in error messages.
|
|
98
|
+
#
|
|
99
|
+
# @return [String]
|
|
100
|
+
def type_name
|
|
101
|
+
resource_type_symbol == :vm ? "VM" : "container"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Performs the feature availability check.
|
|
105
|
+
#
|
|
106
|
+
# @param id [Integer] resource identifier
|
|
107
|
+
# @param feature [String] feature name
|
|
108
|
+
# @return [Integer] exit code
|
|
109
|
+
def perform_operation(id, feature)
|
|
110
|
+
load_config
|
|
111
|
+
connection = Pvectl::Connection.new(@config)
|
|
112
|
+
|
|
113
|
+
resource = resolve_resource(connection, id)
|
|
114
|
+
return resource_not_found(id) if resource.nil?
|
|
115
|
+
|
|
116
|
+
result = build_repository(connection)
|
|
117
|
+
.feature_available?(id, resource.node, feature, snapname: @options[:snapname])
|
|
118
|
+
|
|
119
|
+
output_result(result, feature)
|
|
120
|
+
result[:available] ? ExitCodes::SUCCESS : ExitCodes::GENERAL_ERROR
|
|
121
|
+
rescue Pvectl::Config::ConfigNotFoundError,
|
|
122
|
+
Pvectl::Config::InvalidConfigError,
|
|
123
|
+
Pvectl::Config::ContextNotFoundError,
|
|
124
|
+
Pvectl::Config::ClusterNotFoundError,
|
|
125
|
+
Pvectl::Config::UserNotFoundError
|
|
126
|
+
raise
|
|
127
|
+
rescue StandardError => e
|
|
128
|
+
$stderr.puts "Error: #{e.message}"
|
|
129
|
+
ExitCodes::GENERAL_ERROR
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Resolves the resource (VM or container) by ID using the appropriate repository.
|
|
133
|
+
#
|
|
134
|
+
# @param connection [Connection] API connection
|
|
135
|
+
# @param id [Integer] resource ID
|
|
136
|
+
# @return [Models::Vm, Models::Container, nil]
|
|
137
|
+
def resolve_resource(connection, id)
|
|
138
|
+
build_repository(connection).get(id)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Builds the resource repository (VM or Container) for the current type.
|
|
142
|
+
#
|
|
143
|
+
# @param connection [Connection] API connection
|
|
144
|
+
# @return [Repositories::Vm, Repositories::Container]
|
|
145
|
+
def build_repository(connection)
|
|
146
|
+
if resource_type_symbol == :vm
|
|
147
|
+
Pvectl::Repositories::Vm.new(connection)
|
|
148
|
+
else
|
|
149
|
+
Pvectl::Repositories::Container.new(connection)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Loads configuration from file or environment.
|
|
154
|
+
#
|
|
155
|
+
# @return [void]
|
|
156
|
+
def load_config
|
|
157
|
+
service = Pvectl::Config::Service.new
|
|
158
|
+
service.load(config: @global_options[:config])
|
|
159
|
+
@config = service.current_config
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Outputs the result in the requested format.
|
|
163
|
+
#
|
|
164
|
+
# Plain output: "available"/"unavailable" + optional list of capable nodes.
|
|
165
|
+
# JSON/YAML output: structured hash with feature metadata.
|
|
166
|
+
#
|
|
167
|
+
# @param result [Hash] result from +feature_available?+ (:available, :nodes)
|
|
168
|
+
# @param feature [String] feature name
|
|
169
|
+
# @return [void]
|
|
170
|
+
def output_result(result, feature)
|
|
171
|
+
format = (@global_options[:output] || "plain").to_s
|
|
172
|
+
|
|
173
|
+
case format
|
|
174
|
+
when "json"
|
|
175
|
+
require "json"
|
|
176
|
+
$stdout.puts JSON.pretty_generate(payload(result, feature))
|
|
177
|
+
when "yaml"
|
|
178
|
+
require "yaml"
|
|
179
|
+
$stdout.puts YAML.dump(stringify_keys(payload(result, feature)))
|
|
180
|
+
else
|
|
181
|
+
status = result[:available] ? "available" : "unavailable"
|
|
182
|
+
$stdout.puts status
|
|
183
|
+
if result[:available] && !result[:nodes].empty?
|
|
184
|
+
$stdout.puts "nodes: #{result[:nodes].join(', ')}"
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Builds the structured result payload for JSON/YAML output.
|
|
190
|
+
#
|
|
191
|
+
# @param result [Hash] feature_available? result
|
|
192
|
+
# @param feature [String] feature name
|
|
193
|
+
# @return [Hash]
|
|
194
|
+
def payload(result, feature)
|
|
195
|
+
{
|
|
196
|
+
available: result[:available],
|
|
197
|
+
feature: feature,
|
|
198
|
+
snapname: @options[:snapname],
|
|
199
|
+
nodes: result[:nodes]
|
|
200
|
+
}
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Converts symbol keys to strings for YAML output.
|
|
204
|
+
#
|
|
205
|
+
# @param hash [Hash]
|
|
206
|
+
# @return [Hash]
|
|
207
|
+
def stringify_keys(hash)
|
|
208
|
+
hash.each_with_object({}) { |(k, v), acc| acc[k.to_s] = v }
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Outputs usage error and returns the usage exit code.
|
|
212
|
+
#
|
|
213
|
+
# @param message [String]
|
|
214
|
+
# @return [Integer]
|
|
215
|
+
def usage_error(message)
|
|
216
|
+
$stderr.puts "Error: #{message}"
|
|
217
|
+
ExitCodes::USAGE_ERROR
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Outputs "not found" error and returns the not-found exit code.
|
|
221
|
+
#
|
|
222
|
+
# @param id [Integer]
|
|
223
|
+
# @return [Integer]
|
|
224
|
+
def resource_not_found(id)
|
|
225
|
+
$stderr.puts "Error: No #{type_name} found with ID #{id}"
|
|
226
|
+
ExitCodes::NOT_FOUND
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
# Handler for the `pvectl feature ct` command.
|
|
6
|
+
#
|
|
7
|
+
# Queries whether a Proxmox feature (clone, snapshot, copy) is available
|
|
8
|
+
# for an LXC container. The LXC feature endpoint returns only +hasFeature+
|
|
9
|
+
# (no +nodes+ list), so the +nodes+ column is always empty.
|
|
10
|
+
#
|
|
11
|
+
# @example Check whether container 200 supports snapshot
|
|
12
|
+
# pvectl feature ct 200 snapshot
|
|
13
|
+
#
|
|
14
|
+
class FeatureContainer
|
|
15
|
+
include FeatureCommand
|
|
16
|
+
|
|
17
|
+
RESOURCE_TYPE = :container
|
|
18
|
+
SUPPORTED_RESOURCES = %w[container ct].freeze
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
# Handler for the `pvectl feature vm` command.
|
|
6
|
+
#
|
|
7
|
+
# Queries whether a Proxmox feature (clone, snapshot, copy) is available
|
|
8
|
+
# for a virtual machine. Availability depends on storage type, snapshot
|
|
9
|
+
# state, and other server-side conditions.
|
|
10
|
+
#
|
|
11
|
+
# Also registers the top-level `feature` GLI command and dispatches
|
|
12
|
+
# to FeatureVm or FeatureContainer based on the resource type.
|
|
13
|
+
#
|
|
14
|
+
# @example Check whether VM 100 can be cloned
|
|
15
|
+
# pvectl feature vm 100 clone
|
|
16
|
+
#
|
|
17
|
+
# @example Check snapshot feature against a specific snapshot
|
|
18
|
+
# pvectl feature vm 100 snapshot --snapname pre-upgrade
|
|
19
|
+
#
|
|
20
|
+
class FeatureVm
|
|
21
|
+
include FeatureCommand
|
|
22
|
+
|
|
23
|
+
# Registers the feature command with the CLI.
|
|
24
|
+
#
|
|
25
|
+
# @param cli [GLI::App] the CLI application object
|
|
26
|
+
# @return [void]
|
|
27
|
+
def self.register(cli)
|
|
28
|
+
cli.desc "Query whether a feature (clone/snapshot/copy) is available"
|
|
29
|
+
cli.long_desc <<~HELP
|
|
30
|
+
Check whether a Proxmox feature is available for a VM or container.
|
|
31
|
+
Availability depends on the storage type backing the disks, current
|
|
32
|
+
snapshot state, and other server-side conditions.
|
|
33
|
+
|
|
34
|
+
Exit code is 0 when the feature is available, 1 when unavailable,
|
|
35
|
+
5 when the resource is not found, and 2 on invalid usage.
|
|
36
|
+
|
|
37
|
+
EXAMPLES
|
|
38
|
+
Check whether VM 100 can be cloned:
|
|
39
|
+
$ pvectl feature vm 100 clone
|
|
40
|
+
|
|
41
|
+
Check snapshot feature on a container with a specific snapshot:
|
|
42
|
+
$ pvectl feature ct 200 snapshot --snapname pre-upgrade
|
|
43
|
+
|
|
44
|
+
Check copy feature for a VM:
|
|
45
|
+
$ pvectl feature vm 100 copy
|
|
46
|
+
|
|
47
|
+
JSON output (machine-readable):
|
|
48
|
+
$ pvectl feature vm 100 clone -o json
|
|
49
|
+
|
|
50
|
+
NOTES
|
|
51
|
+
Supported features: clone, snapshot, copy.
|
|
52
|
+
|
|
53
|
+
The Proxmox API returns the list of cluster nodes that can host
|
|
54
|
+
the resource after the requested feature is applied. For VMs the
|
|
55
|
+
list is printed under the "nodes:" line; for containers the LXC
|
|
56
|
+
endpoint does not return this list.
|
|
57
|
+
|
|
58
|
+
--snapname is required for some checks (e.g. checking whether a
|
|
59
|
+
specific snapshot can be removed or cloned from).
|
|
60
|
+
|
|
61
|
+
SEE ALSO
|
|
62
|
+
pvectl help clone Clone a VM or container
|
|
63
|
+
pvectl help create snapshot Create a snapshot
|
|
64
|
+
pvectl help get snapshots List snapshots
|
|
65
|
+
HELP
|
|
66
|
+
cli.arg_name "RESOURCE_TYPE ID FEATURE"
|
|
67
|
+
cli.command :feature do |c|
|
|
68
|
+
c.desc "Snapshot name (optional, required for some checks)"
|
|
69
|
+
c.flag [:snapname], arg_name: "NAME"
|
|
70
|
+
|
|
71
|
+
c.action do |global_options, options, args|
|
|
72
|
+
resource_type = args.shift
|
|
73
|
+
|
|
74
|
+
exit_code = case resource_type
|
|
75
|
+
when "vm"
|
|
76
|
+
Commands::FeatureVm.execute(args, options, global_options)
|
|
77
|
+
when "container", "ct"
|
|
78
|
+
Commands::FeatureContainer.execute(args, options, global_options)
|
|
79
|
+
else
|
|
80
|
+
$stderr.puts "Error: Unknown resource type: #{resource_type}"
|
|
81
|
+
$stderr.puts "Valid types: vm, container, ct"
|
|
82
|
+
ExitCodes::USAGE_ERROR
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
exit exit_code if exit_code != 0
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
RESOURCE_TYPE = :vm
|
|
91
|
+
SUPPORTED_RESOURCES = %w[vm].freeze
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
module Get
|
|
6
|
+
# Dispatcher for the `pvectl get <resource_type>` command.
|
|
7
|
+
#
|
|
8
|
+
# Routes requests to appropriate resource handlers based on the
|
|
9
|
+
# resource type argument. Supports watch mode for continuous
|
|
10
|
+
# monitoring and node filtering.
|
|
11
|
+
#
|
|
12
|
+
# Responsibilities:
|
|
13
|
+
# - Control flow (watch vs single execution)
|
|
14
|
+
# - Handler lookup via ResourceRegistry
|
|
15
|
+
# - Error handling for unknown resources and handler exceptions
|
|
16
|
+
#
|
|
17
|
+
# Delegates to:
|
|
18
|
+
# - Services::Get::ResourceService for data fetching and formatting
|
|
19
|
+
#
|
|
20
|
+
# @example Basic usage
|
|
21
|
+
# Commands::Get::Command.execute("nodes", nil, options, global_options)
|
|
22
|
+
#
|
|
23
|
+
# @example With watch mode
|
|
24
|
+
# options = { watch: true, :"watch-interval" => 5 }
|
|
25
|
+
# Commands::Get::Command.execute("vms", nil, options, global_options)
|
|
26
|
+
#
|
|
27
|
+
class Command
|
|
28
|
+
# Registers the get command with the CLI.
|
|
29
|
+
#
|
|
30
|
+
# @param cli [GLI::App] the CLI application object
|
|
31
|
+
# @return [void]
|
|
32
|
+
def self.register(cli)
|
|
33
|
+
cli.desc "List resources in cluster"
|
|
34
|
+
cli.long_desc <<~HELP
|
|
35
|
+
List resources across the Proxmox cluster. Supports multiple resource
|
|
36
|
+
types including nodes, VMs, containers, storage, snapshots, backups,
|
|
37
|
+
templates, and tasks.
|
|
38
|
+
|
|
39
|
+
Results can be filtered by node (--node), formatted in different output
|
|
40
|
+
modes (-o), and auto-refreshed with watch mode (-w).
|
|
41
|
+
|
|
42
|
+
RESOURCE TYPES
|
|
43
|
+
nodes (node) Cluster nodes
|
|
44
|
+
vms (vm) Virtual machines
|
|
45
|
+
containers (ct, cts) LXC containers
|
|
46
|
+
storage (stor) Storage pools
|
|
47
|
+
snapshots (snap) VM/CT snapshots
|
|
48
|
+
backups (backup) Backup volumes
|
|
49
|
+
templates (template) VM and container templates
|
|
50
|
+
tasks (task) Task history
|
|
51
|
+
disks (disk) Physical disks (block devices)
|
|
52
|
+
volumes (volume, vol) Virtual disks attached to VMs/containers
|
|
53
|
+
time Node time and timezone settings
|
|
54
|
+
node-capabilities (caps) Supported QEMU CPU models and machine types
|
|
55
|
+
subscription (sub) Proxmox subscription status per node
|
|
56
|
+
|
|
57
|
+
EXAMPLES
|
|
58
|
+
List all VMs in table format:
|
|
59
|
+
$ pvectl get vms
|
|
60
|
+
|
|
61
|
+
List containers on a specific node as JSON:
|
|
62
|
+
$ pvectl get containers --node pve1 -o json
|
|
63
|
+
|
|
64
|
+
List snapshots for specific VMs:
|
|
65
|
+
$ pvectl get snapshots --vmid 100 --vmid 101
|
|
66
|
+
|
|
67
|
+
Watch cluster nodes with 5-second refresh:
|
|
68
|
+
$ pvectl get nodes -w --watch-interval 5
|
|
69
|
+
|
|
70
|
+
Filter tasks by type and date:
|
|
71
|
+
$ pvectl get tasks --type vzdump --since 2026-01-01
|
|
72
|
+
|
|
73
|
+
Wide output with extra columns:
|
|
74
|
+
$ pvectl get vms -o wide
|
|
75
|
+
|
|
76
|
+
Filter VMs by status (shortcut):
|
|
77
|
+
$ pvectl get vms --status running
|
|
78
|
+
|
|
79
|
+
Filter VMs by selector (supports status, name, tags, pool):
|
|
80
|
+
$ pvectl get vms -l status=running
|
|
81
|
+
$ pvectl get vms -l status=running,tags=prod
|
|
82
|
+
$ pvectl get vms -l name=~web-*
|
|
83
|
+
|
|
84
|
+
List VM volumes:
|
|
85
|
+
$ pvectl get volume vm 100
|
|
86
|
+
|
|
87
|
+
List volumes from storage:
|
|
88
|
+
$ pvectl get volume --storage local-lvm
|
|
89
|
+
|
|
90
|
+
List volumes with filtering:
|
|
91
|
+
$ pvectl get volume vm 100 -l format=raw
|
|
92
|
+
|
|
93
|
+
Show node time and timezone for a single node:
|
|
94
|
+
$ pvectl get time --node pve1
|
|
95
|
+
|
|
96
|
+
Show time and timezone for all online nodes:
|
|
97
|
+
$ pvectl get time
|
|
98
|
+
|
|
99
|
+
List supported CPU models / machine types for a node:
|
|
100
|
+
$ pvectl get node-capabilities --node pve1
|
|
101
|
+
$ pvectl get caps --node pve1 -o json
|
|
102
|
+
|
|
103
|
+
List subscription status across the cluster:
|
|
104
|
+
$ pvectl get subscription
|
|
105
|
+
|
|
106
|
+
Show full license key for one node (key is masked by default):
|
|
107
|
+
$ pvectl get subscription --node pve1 -o wide
|
|
108
|
+
|
|
109
|
+
NOTES
|
|
110
|
+
Use selectors (-l) to filter VMs/containers by status, name, tags, or
|
|
111
|
+
pool. Multiple selectors use AND logic. The --status flag is a shortcut
|
|
112
|
+
for -l status=VALUE and can be combined with other selectors.
|
|
113
|
+
|
|
114
|
+
Task listing defaults to 50 entries; use --limit to change.
|
|
115
|
+
|
|
116
|
+
Watch mode clears the screen on each refresh. Press Ctrl+C to stop.
|
|
117
|
+
|
|
118
|
+
SEE ALSO
|
|
119
|
+
pvectl help describe Show detailed info about a single resource
|
|
120
|
+
pvectl help top Display real-time resource usage metrics
|
|
121
|
+
pvectl help logs Show logs and task history
|
|
122
|
+
HELP
|
|
123
|
+
cli.command :get do |c|
|
|
124
|
+
c.desc "Filter by node name"
|
|
125
|
+
c.flag [:node], arg_name: "NODE"
|
|
126
|
+
|
|
127
|
+
c.desc "Filter by VM/CT ID (repeatable)"
|
|
128
|
+
c.flag [:vmid], arg_name: "VMID", multiple: true
|
|
129
|
+
|
|
130
|
+
c.desc "Filter by storage (for backups)"
|
|
131
|
+
c.flag [:storage], arg_name: "STORAGE"
|
|
132
|
+
|
|
133
|
+
c.desc "Watch for changes with auto-refresh"
|
|
134
|
+
c.switch [:watch, :w], negatable: false
|
|
135
|
+
|
|
136
|
+
c.desc "Watch refresh interval in seconds (default: 2, minimum: 1)"
|
|
137
|
+
c.default_value 2
|
|
138
|
+
c.flag [:"watch-interval"], arg_name: "SECONDS", type: Integer
|
|
139
|
+
|
|
140
|
+
c.desc "Maximum number of entries to show (for tasks)"
|
|
141
|
+
c.default_value 50
|
|
142
|
+
c.flag [:limit], type: Integer, arg_name: "N"
|
|
143
|
+
|
|
144
|
+
c.desc "Show entries since timestamp (YYYY-MM-DD or epoch, for tasks)"
|
|
145
|
+
c.flag [:since], arg_name: "TIMESTAMP"
|
|
146
|
+
|
|
147
|
+
c.desc "Show entries until timestamp (YYYY-MM-DD or epoch, for tasks)"
|
|
148
|
+
c.flag [:until], arg_name: "TIMESTAMP"
|
|
149
|
+
|
|
150
|
+
c.desc "Filter by task type (e.g., qmstart, qmstop, vzdump)"
|
|
151
|
+
c.flag [:type], arg_name: "TYPE"
|
|
152
|
+
|
|
153
|
+
c.desc "Filter by status (running, stopped for VMs/CTs; running, ok, error for tasks)"
|
|
154
|
+
c.flag [:status], arg_name: "STATUS"
|
|
155
|
+
|
|
156
|
+
c.desc "Filter by selector (e.g., status=running,tags=prod)"
|
|
157
|
+
c.flag [:l, :selector], arg_name: "SELECTOR", multiple: true
|
|
158
|
+
|
|
159
|
+
c.desc "Search across all cluster nodes (default for tasks)"
|
|
160
|
+
c.switch [:"all-nodes"], negatable: false
|
|
161
|
+
|
|
162
|
+
c.action do |global_options, options, args|
|
|
163
|
+
resource_type = args[0]
|
|
164
|
+
resource_args = args[1..] || []
|
|
165
|
+
exit_code = execute(resource_type, resource_args, options, global_options)
|
|
166
|
+
exit exit_code if exit_code != 0
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Executes the get command.
|
|
172
|
+
#
|
|
173
|
+
# @param resource_type [String, nil] type of resource to list (e.g., "nodes", "vms")
|
|
174
|
+
# @param args [String, Array, nil] positional arguments (VMIDs for snapshots, or name filter)
|
|
175
|
+
# @param options [Hash] command-specific options
|
|
176
|
+
# - :watch [Boolean] enable continuous monitoring
|
|
177
|
+
# - :"watch-interval" [Integer] refresh interval in seconds
|
|
178
|
+
# - :node [String] filter by node name
|
|
179
|
+
# @param global_options [Hash] global CLI options
|
|
180
|
+
# - :output [String] output format (table, json, yaml, wide)
|
|
181
|
+
# - :color [Boolean, nil] explicit color setting
|
|
182
|
+
# @return [Integer] exit code (0 for success, 2 for unknown resource)
|
|
183
|
+
def self.execute(resource_type, args, options, global_options)
|
|
184
|
+
new(resource_type, args, options, global_options).execute
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Creates a new Get command instance.
|
|
188
|
+
#
|
|
189
|
+
# @param resource_type [String, nil] type of resource to list
|
|
190
|
+
# @param args [String, Array, nil] positional arguments
|
|
191
|
+
# @param options [Hash] command options
|
|
192
|
+
# @param global_options [Hash] global CLI options
|
|
193
|
+
# @param registry [Class] registry class for dependency injection (default: ResourceRegistry)
|
|
194
|
+
def initialize(resource_type, args, options, global_options,
|
|
195
|
+
registry: ResourceRegistry)
|
|
196
|
+
@resource_type = resource_type
|
|
197
|
+
@args = normalize_args(args)
|
|
198
|
+
@options = options
|
|
199
|
+
@global_options = global_options
|
|
200
|
+
@registry = registry
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Executes the get operation.
|
|
204
|
+
#
|
|
205
|
+
# @return [Integer] exit code
|
|
206
|
+
def execute
|
|
207
|
+
return missing_resource_type_error if @resource_type.nil?
|
|
208
|
+
|
|
209
|
+
handler = @registry.for(@resource_type)
|
|
210
|
+
return unknown_resource_error unless handler
|
|
211
|
+
|
|
212
|
+
if @options[:watch]
|
|
213
|
+
run_watch_mode(handler)
|
|
214
|
+
else
|
|
215
|
+
run_once(handler)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
ExitCodes::SUCCESS
|
|
219
|
+
rescue Timeout::Error => e
|
|
220
|
+
output_connection_error(e.message)
|
|
221
|
+
ExitCodes::CONNECTION_ERROR
|
|
222
|
+
rescue Errno::ECONNREFUSED => e
|
|
223
|
+
output_connection_error(e.message)
|
|
224
|
+
ExitCodes::CONNECTION_ERROR
|
|
225
|
+
rescue SocketError => e
|
|
226
|
+
output_connection_error(e.message)
|
|
227
|
+
ExitCodes::CONNECTION_ERROR
|
|
228
|
+
rescue ArgumentError => e
|
|
229
|
+
output_usage_error(e.message)
|
|
230
|
+
ExitCodes::USAGE_ERROR
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
private
|
|
234
|
+
|
|
235
|
+
attr_reader :resource_type, :args, :options, :global_options
|
|
236
|
+
|
|
237
|
+
# Normalizes args to an array.
|
|
238
|
+
#
|
|
239
|
+
# @param args [String, Array, nil] input args
|
|
240
|
+
# @return [Array<String>] normalized args array
|
|
241
|
+
def normalize_args(args)
|
|
242
|
+
case args
|
|
243
|
+
when nil then []
|
|
244
|
+
when Array then args
|
|
245
|
+
else [args.to_s]
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Outputs error for missing resource type argument.
|
|
250
|
+
#
|
|
251
|
+
# @return [Integer] USAGE_ERROR exit code
|
|
252
|
+
def missing_resource_type_error
|
|
253
|
+
$stderr.puts "Error: resource type is required"
|
|
254
|
+
$stderr.puts "Usage: pvectl get RESOURCE_TYPE [NAME] [options]"
|
|
255
|
+
ExitCodes::USAGE_ERROR
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Outputs error for unknown resource type.
|
|
259
|
+
#
|
|
260
|
+
# @return [Integer] USAGE_ERROR exit code
|
|
261
|
+
def unknown_resource_error
|
|
262
|
+
$stderr.puts "Unknown resource type: #{@resource_type}"
|
|
263
|
+
ExitCodes::USAGE_ERROR
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Outputs connection error message.
|
|
267
|
+
#
|
|
268
|
+
# @param message [String] the error message
|
|
269
|
+
# @return [void]
|
|
270
|
+
def output_connection_error(message)
|
|
271
|
+
$stderr.puts "Error: #{message}"
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Outputs usage error message.
|
|
275
|
+
#
|
|
276
|
+
# @param message [String] the error message
|
|
277
|
+
# @return [void]
|
|
278
|
+
def output_usage_error(message)
|
|
279
|
+
$stderr.puts "Error: #{message}"
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Executes a single fetch and display operation.
|
|
283
|
+
#
|
|
284
|
+
# @param handler [ResourceHandler] the resource handler
|
|
285
|
+
# @return [void]
|
|
286
|
+
def run_once(handler)
|
|
287
|
+
service = build_service(handler)
|
|
288
|
+
selector = build_selector(handler)
|
|
289
|
+
output = service.list(
|
|
290
|
+
node: options[:node],
|
|
291
|
+
name: nil,
|
|
292
|
+
args: args,
|
|
293
|
+
storage: options[:storage],
|
|
294
|
+
vmid: options[:vmid],
|
|
295
|
+
limit: options[:limit],
|
|
296
|
+
since: options[:since],
|
|
297
|
+
until_time: options[:until],
|
|
298
|
+
type_filter: options[:type],
|
|
299
|
+
status_filter: options[:status],
|
|
300
|
+
all_nodes: options[:"all-nodes"] || false,
|
|
301
|
+
selector: selector
|
|
302
|
+
)
|
|
303
|
+
puts output
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Executes watch mode with continuous refresh.
|
|
307
|
+
#
|
|
308
|
+
# @param handler [ResourceHandler] the resource handler
|
|
309
|
+
# @return [void]
|
|
310
|
+
def run_watch_mode(handler)
|
|
311
|
+
interval = options[:"watch-interval"] || WatchLoop::DEFAULT_INTERVAL
|
|
312
|
+
watch_loop = WatchLoop.new(interval: interval)
|
|
313
|
+
watch_loop.run { run_once(handler) }
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Builds a selector from -l and --status flags for client-side filtering.
|
|
317
|
+
#
|
|
318
|
+
# For handlers that declare a selector_class (VMs, Containers), --status
|
|
319
|
+
# is translated into a selector condition. For handlers without selector
|
|
320
|
+
# support (e.g., tasks), --status is passed through as status_filter.
|
|
321
|
+
#
|
|
322
|
+
# @param handler [ResourceHandler] the resource handler
|
|
323
|
+
# @return [Selectors::Base, nil] parsed selector or nil if not applicable
|
|
324
|
+
def build_selector(handler)
|
|
325
|
+
selector_class = handler.selector_class
|
|
326
|
+
return nil unless selector_class
|
|
327
|
+
|
|
328
|
+
selector_strings = Array(options[:selector])
|
|
329
|
+
selector_strings << "status=#{options[:status]}" if options[:status]
|
|
330
|
+
|
|
331
|
+
return nil if selector_strings.empty?
|
|
332
|
+
|
|
333
|
+
selector_class.parse_all(selector_strings)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Builds the service for the given handler.
|
|
337
|
+
#
|
|
338
|
+
# @param handler [ResourceHandler] the resource handler
|
|
339
|
+
# @return [Services::Get::ResourceService] the service instance
|
|
340
|
+
def build_service(handler)
|
|
341
|
+
Services::Get::ResourceService.new(
|
|
342
|
+
handler: handler,
|
|
343
|
+
format: global_options[:output] || "table",
|
|
344
|
+
color_enabled: determine_color_enabled
|
|
345
|
+
)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Determines if color output should be enabled.
|
|
349
|
+
#
|
|
350
|
+
# @return [Boolean] true if color should be enabled
|
|
351
|
+
def determine_color_enabled
|
|
352
|
+
explicit = global_options[:color]
|
|
353
|
+
return explicit unless explicit.nil?
|
|
354
|
+
|
|
355
|
+
$stdout.tty?
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end
|