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,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
module Top
|
|
6
|
+
module Handlers
|
|
7
|
+
# Handler for Top command VM metrics display.
|
|
8
|
+
#
|
|
9
|
+
# Wraps Get::Handlers::Vms to fetch VM data and pairs it
|
|
10
|
+
# with TopVm presenter for metrics-focused output.
|
|
11
|
+
#
|
|
12
|
+
# @example Using via ResourceRegistry
|
|
13
|
+
# handler = Top::ResourceRegistry.for("vms")
|
|
14
|
+
# vms = handler.list(sort: "cpu")
|
|
15
|
+
# presenter = handler.presenter
|
|
16
|
+
#
|
|
17
|
+
# @see Pvectl::Commands::Get::Handlers::Vms Get handler
|
|
18
|
+
# @see Pvectl::Presenters::TopVm Top presenter
|
|
19
|
+
#
|
|
20
|
+
class Vms
|
|
21
|
+
include Top::ResourceHandler
|
|
22
|
+
|
|
23
|
+
# Creates handler with optional Get handler for dependency injection.
|
|
24
|
+
#
|
|
25
|
+
# @param get_handler [Get::Handlers::Vms, nil] handler (default: create new)
|
|
26
|
+
def initialize(get_handler: nil)
|
|
27
|
+
@get_handler = get_handler
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Lists VMs with optional sorting.
|
|
31
|
+
#
|
|
32
|
+
# @param sort [String, nil] sort field (cpu, memory, disk)
|
|
33
|
+
# @return [Array<Models::Vm>] collection of VM models
|
|
34
|
+
def list(sort: nil, **_)
|
|
35
|
+
get_handler.list(sort: sort)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Returns Top-specific presenter for VMs.
|
|
39
|
+
#
|
|
40
|
+
# @return [Presenters::TopVm] TopVm presenter instance
|
|
41
|
+
def presenter
|
|
42
|
+
Presenters::TopVm.new
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# Returns Get handler, creating it if necessary.
|
|
48
|
+
#
|
|
49
|
+
# @return [Get::Handlers::Vms] Vms get handler
|
|
50
|
+
def get_handler
|
|
51
|
+
@get_handler ||= Get::Handlers::Vms.new
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
Pvectl::Commands::Top::ResourceRegistry.register(
|
|
60
|
+
"vms", Pvectl::Commands::Top::Handlers::Vms, aliases: ["vm"]
|
|
61
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
module Top
|
|
6
|
+
# Interface module for Top command handlers.
|
|
7
|
+
#
|
|
8
|
+
# Each handler wraps a Get handler and returns a Top-specific presenter
|
|
9
|
+
# for metrics-focused display (CPU%, MEM%, etc.).
|
|
10
|
+
#
|
|
11
|
+
# @abstract Include in handler class and implement required methods.
|
|
12
|
+
#
|
|
13
|
+
# @example Implementing a handler
|
|
14
|
+
# class NodesHandler
|
|
15
|
+
# include Top::ResourceHandler
|
|
16
|
+
#
|
|
17
|
+
# def list(sort: nil, **_)
|
|
18
|
+
# get_handler.list(sort: sort)
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# def presenter
|
|
22
|
+
# Presenters::TopNode.new
|
|
23
|
+
# end
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
module ResourceHandler
|
|
27
|
+
# Lists resources with optional sorting.
|
|
28
|
+
#
|
|
29
|
+
# @param options [Hash] keyword arguments (e.g., sort:)
|
|
30
|
+
# @return [Array<Object>] collection of model objects
|
|
31
|
+
# @raise [NotImplementedError] if not implemented by including class
|
|
32
|
+
def list(**options)
|
|
33
|
+
raise NotImplementedError, "#{self.class}#list must be implemented"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns the Top-specific presenter for this resource type.
|
|
37
|
+
#
|
|
38
|
+
# @return [Presenters::Base] presenter instance
|
|
39
|
+
# @raise [NotImplementedError] if not implemented by including class
|
|
40
|
+
def presenter
|
|
41
|
+
raise NotImplementedError, "#{self.class}#presenter must be implemented"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
module Top
|
|
6
|
+
# Registry for Top command resource handlers.
|
|
7
|
+
#
|
|
8
|
+
# Inherits registration and lookup from Commands::ResourceRegistry,
|
|
9
|
+
# maintaining its own isolated set of handlers.
|
|
10
|
+
#
|
|
11
|
+
# @example Registering a handler
|
|
12
|
+
# Top::ResourceRegistry.register("nodes", Handlers::Nodes, aliases: ["node"])
|
|
13
|
+
#
|
|
14
|
+
# @example Looking up a handler
|
|
15
|
+
# handler = Top::ResourceRegistry.for("nodes")
|
|
16
|
+
#
|
|
17
|
+
# @see Pvectl::Commands::ResourceRegistry Base registry
|
|
18
|
+
#
|
|
19
|
+
class ResourceRegistry < Commands::ResourceRegistry; end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
# Handler for the `pvectl unlink disk vm` command.
|
|
6
|
+
#
|
|
7
|
+
# Removes one or more disks from a VM configuration. By default, the
|
|
8
|
+
# disk entry is converted to `unused[n]` (the underlying volume is
|
|
9
|
+
# preserved). With `--force`, the underlying volume is physically
|
|
10
|
+
# deleted.
|
|
11
|
+
#
|
|
12
|
+
# @example Soft unlink (keeps volume as unused0)
|
|
13
|
+
# pvectl unlink disk vm 100 scsi1
|
|
14
|
+
#
|
|
15
|
+
# @example Unlink multiple disks
|
|
16
|
+
# pvectl unlink disk vm 100 scsi1,virtio0
|
|
17
|
+
#
|
|
18
|
+
# @example Hard delete the underlying volume
|
|
19
|
+
# pvectl unlink disk vm 100 scsi1 --force --yes
|
|
20
|
+
#
|
|
21
|
+
class UnlinkDiskVm
|
|
22
|
+
# Registers the unlink command with the CLI.
|
|
23
|
+
#
|
|
24
|
+
# @param cli [GLI::App] the CLI application object
|
|
25
|
+
# @return [void]
|
|
26
|
+
def self.register(cli)
|
|
27
|
+
cli.desc "Unlink a disk from a resource"
|
|
28
|
+
cli.long_desc <<~HELP
|
|
29
|
+
DESCRIPTION
|
|
30
|
+
Remove one or more disks from a VM configuration.
|
|
31
|
+
|
|
32
|
+
By default, the disk entry is moved to `unused[n]` in the VM
|
|
33
|
+
config — the underlying volume is preserved so it can be
|
|
34
|
+
re-attached or inspected later. With --force, the underlying
|
|
35
|
+
volume is physically deleted and cannot be recovered.
|
|
36
|
+
|
|
37
|
+
Multiple disks may be removed in a single call by passing a
|
|
38
|
+
comma-separated list (e.g. "scsi1,virtio0").
|
|
39
|
+
|
|
40
|
+
EXAMPLES
|
|
41
|
+
Soft unlink (keeps the volume as unused0):
|
|
42
|
+
$ pvectl unlink disk vm 100 scsi1
|
|
43
|
+
|
|
44
|
+
Unlink multiple disks at once:
|
|
45
|
+
$ pvectl unlink disk vm 100 scsi1,virtio0
|
|
46
|
+
|
|
47
|
+
Permanently delete the underlying volume:
|
|
48
|
+
$ pvectl unlink disk vm 100 scsi1 --force --yes
|
|
49
|
+
|
|
50
|
+
Skip confirmation prompt:
|
|
51
|
+
$ pvectl unlink disk vm 100 scsi1 -y
|
|
52
|
+
|
|
53
|
+
NOTES
|
|
54
|
+
--force is destructive: the underlying volume is removed and
|
|
55
|
+
cannot be recovered. Without --force, the volume can be
|
|
56
|
+
re-attached later (e.g. via `pvectl set vm`).
|
|
57
|
+
|
|
58
|
+
The command operates only on QEMU virtual machines; LXC
|
|
59
|
+
containers are not supported by the Proxmox /unlink endpoint.
|
|
60
|
+
|
|
61
|
+
SEE ALSO
|
|
62
|
+
pvectl help describe vm Show VM configuration including disks
|
|
63
|
+
pvectl help edit volume Edit volume properties interactively
|
|
64
|
+
pvectl help set vm Modify VM configuration (re-attach unused)
|
|
65
|
+
HELP
|
|
66
|
+
cli.arg_name "RESOURCE_TYPE ID DISK_LIST"
|
|
67
|
+
cli.command :unlink do |c|
|
|
68
|
+
c.desc "Skip confirmation prompt"
|
|
69
|
+
c.switch [:yes, :y], negatable: false
|
|
70
|
+
|
|
71
|
+
c.desc "Physically delete the underlying volume(s)"
|
|
72
|
+
c.switch [:force], negatable: false
|
|
73
|
+
|
|
74
|
+
c.action do |global_options, options, args|
|
|
75
|
+
resource_type = args.shift
|
|
76
|
+
scope = args.shift
|
|
77
|
+
|
|
78
|
+
exit_code = case [resource_type, scope]
|
|
79
|
+
when %w[disk vm]
|
|
80
|
+
Commands::UnlinkDiskVm.execute(args, options, global_options)
|
|
81
|
+
else
|
|
82
|
+
$stderr.puts "Error: Unknown unlink target: #{resource_type} #{scope}".strip
|
|
83
|
+
$stderr.puts "Valid form: unlink disk vm <id> <disk_list>"
|
|
84
|
+
ExitCodes::USAGE_ERROR
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
exit exit_code if exit_code != 0
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Executes the unlink disk vm command.
|
|
93
|
+
#
|
|
94
|
+
# @param args [Array<String>] command arguments (VMID, DISK_LIST)
|
|
95
|
+
# @param options [Hash] command options
|
|
96
|
+
# @param global_options [Hash] global CLI options
|
|
97
|
+
# @return [Integer] exit code
|
|
98
|
+
def self.execute(args, options, global_options)
|
|
99
|
+
new(args, options, global_options).execute
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @param args [Array<String>] command arguments
|
|
103
|
+
# @param options [Hash] command options
|
|
104
|
+
# @param global_options [Hash] global CLI options
|
|
105
|
+
def initialize(args, options, global_options)
|
|
106
|
+
@args = args
|
|
107
|
+
@options = options
|
|
108
|
+
@global_options = global_options
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Executes the unlink disk vm command.
|
|
112
|
+
#
|
|
113
|
+
# @return [Integer] exit code
|
|
114
|
+
def execute
|
|
115
|
+
vmid_arg = @args[0]
|
|
116
|
+
disk_list = @args[1]
|
|
117
|
+
|
|
118
|
+
return usage_error("VMID required") if vmid_arg.nil? || vmid_arg.to_s.empty?
|
|
119
|
+
return usage_error("Disk list required (e.g., scsi1 or scsi1,virtio0)") if disk_list.nil? || disk_list.to_s.empty?
|
|
120
|
+
return usage_error("Invalid VMID: #{vmid_arg}") unless vmid_arg.to_s.match?(/\A\d+\z/)
|
|
121
|
+
|
|
122
|
+
vmid = vmid_arg.to_i
|
|
123
|
+
load_config
|
|
124
|
+
node = resolve_node(vmid)
|
|
125
|
+
return ExitCodes::NOT_FOUND if node.nil?
|
|
126
|
+
|
|
127
|
+
return ExitCodes::SUCCESS unless confirm_operation(vmid, disk_list)
|
|
128
|
+
|
|
129
|
+
repo = build_repository
|
|
130
|
+
service = Pvectl::Services::UnlinkDisk.new(repository: repo)
|
|
131
|
+
result = service.execute(
|
|
132
|
+
vmid: vmid,
|
|
133
|
+
node: node,
|
|
134
|
+
disk_ids: disk_list,
|
|
135
|
+
force: @options[:force] == true
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
output_result(result)
|
|
139
|
+
result.failed? ? ExitCodes::GENERAL_ERROR : ExitCodes::SUCCESS
|
|
140
|
+
rescue Pvectl::Config::ConfigNotFoundError,
|
|
141
|
+
Pvectl::Config::InvalidConfigError,
|
|
142
|
+
Pvectl::Config::ContextNotFoundError,
|
|
143
|
+
Pvectl::Config::ClusterNotFoundError,
|
|
144
|
+
Pvectl::Config::UserNotFoundError
|
|
145
|
+
raise
|
|
146
|
+
rescue StandardError => e
|
|
147
|
+
$stderr.puts "Error: #{e.message}"
|
|
148
|
+
ExitCodes::GENERAL_ERROR
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private
|
|
152
|
+
|
|
153
|
+
# Loads configuration.
|
|
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
|
+
# Resolves the node for a VMID.
|
|
163
|
+
#
|
|
164
|
+
# @param vmid [Integer] VM identifier
|
|
165
|
+
# @return [String, nil] node name or nil if not found
|
|
166
|
+
def resolve_node(vmid)
|
|
167
|
+
connection = Pvectl::Connection.new(@config)
|
|
168
|
+
resolver = Pvectl::Utils::ResourceResolver.new(connection)
|
|
169
|
+
resolved = resolver.resolve(vmid)
|
|
170
|
+
|
|
171
|
+
unless resolved && resolved[:type] == :qemu
|
|
172
|
+
$stderr.puts "Error: VM #{vmid} not found"
|
|
173
|
+
return nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
resolved[:node]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Builds the VM repository.
|
|
180
|
+
#
|
|
181
|
+
# @return [Repositories::Vm] VM repository
|
|
182
|
+
def build_repository
|
|
183
|
+
connection = Pvectl::Connection.new(@config)
|
|
184
|
+
Pvectl::Repositories::Vm.new(connection)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Confirms the unlink operation with the user, if not auto-approved.
|
|
188
|
+
#
|
|
189
|
+
# @param vmid [Integer] VM identifier
|
|
190
|
+
# @param disk_list [String] comma-separated disk list
|
|
191
|
+
# @return [Boolean] true to proceed, false to cancel
|
|
192
|
+
def confirm_operation(vmid, disk_list)
|
|
193
|
+
return true if @options[:yes]
|
|
194
|
+
|
|
195
|
+
$stdout.puts "About to unlink disk(s) #{disk_list} from VM #{vmid}."
|
|
196
|
+
if @options[:force]
|
|
197
|
+
$stdout.puts ""
|
|
198
|
+
$stdout.puts "WARNING: --force will delete the underlying volume(s) permanently."
|
|
199
|
+
$stdout.puts ""
|
|
200
|
+
end
|
|
201
|
+
$stdout.print "Proceed? [y/N]: "
|
|
202
|
+
$stdout.flush
|
|
203
|
+
|
|
204
|
+
answer = $stdin.gets&.strip&.downcase
|
|
205
|
+
answer == "y"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Outputs the operation result via the configured formatter.
|
|
209
|
+
#
|
|
210
|
+
# @param result [Models::VmOperationResult] operation result
|
|
211
|
+
# @return [void]
|
|
212
|
+
def output_result(result)
|
|
213
|
+
presenter = Pvectl::Presenters::VmOperationResult.new
|
|
214
|
+
format = @global_options[:output] || "table"
|
|
215
|
+
color_flag = @global_options[:color]
|
|
216
|
+
|
|
217
|
+
formatter = Pvectl::Formatters::Registry.for(format)
|
|
218
|
+
output = formatter.format([result], presenter, color: color_flag)
|
|
219
|
+
$stdout.puts output
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Outputs a usage error message and returns the corresponding exit code.
|
|
223
|
+
#
|
|
224
|
+
# @param message [String] error message
|
|
225
|
+
# @return [Integer] usage error exit code
|
|
226
|
+
def usage_error(message)
|
|
227
|
+
$stderr.puts "Error: #{message}"
|
|
228
|
+
ExitCodes::USAGE_ERROR
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
# VM-specific lifecycle command hooks.
|
|
6
|
+
#
|
|
7
|
+
# Provides VM repository, selector, service, and presenter
|
|
8
|
+
# to ResourceLifecycleCommand's template methods.
|
|
9
|
+
#
|
|
10
|
+
# @example Usage
|
|
11
|
+
# class Start
|
|
12
|
+
# include VmLifecycleCommand
|
|
13
|
+
# OPERATION = :start
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
module VmLifecycleCommand
|
|
17
|
+
include ResourceLifecycleCommand
|
|
18
|
+
|
|
19
|
+
# Extends the including class with ClassMethods from ResourceLifecycleCommand.
|
|
20
|
+
#
|
|
21
|
+
# @param base [Class] the class including this module
|
|
22
|
+
def self.included(base)
|
|
23
|
+
base.extend(ResourceLifecycleCommand::ClassMethods)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
# @return [Array<String>] supported resource types
|
|
29
|
+
def supported_resources
|
|
30
|
+
%w[vm]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [String] human label for VM resources
|
|
34
|
+
def resource_label
|
|
35
|
+
"VM"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [String] human label for VM IDs
|
|
39
|
+
def resource_id_label
|
|
40
|
+
"VMID"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Builds VM repository.
|
|
44
|
+
#
|
|
45
|
+
# @param connection [Connection] API connection
|
|
46
|
+
# @return [Repositories::Vm] VM repository
|
|
47
|
+
def build_repository(connection)
|
|
48
|
+
Pvectl::Repositories::Vm.new(connection)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Builds VM lifecycle service.
|
|
52
|
+
#
|
|
53
|
+
# @param repo [Repositories::Vm] VM repository
|
|
54
|
+
# @param task_repo [Repositories::Task] task repository
|
|
55
|
+
# @param options [Hash] service options
|
|
56
|
+
# @return [Services::VmLifecycle] VM lifecycle service
|
|
57
|
+
def build_service(repo, task_repo, options)
|
|
58
|
+
Pvectl::Services::VmLifecycle.new(repo, task_repo, options)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Builds VM operation result presenter.
|
|
62
|
+
#
|
|
63
|
+
# @return [Presenters::VmOperationResult] presenter
|
|
64
|
+
def build_presenter
|
|
65
|
+
Pvectl::Presenters::VmOperationResult.new
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Builds VM selector from strings.
|
|
69
|
+
#
|
|
70
|
+
# @param strings [Array<String>] selector strings
|
|
71
|
+
# @return [Selectors::Vm] parsed selector
|
|
72
|
+
def build_selector(strings)
|
|
73
|
+
Pvectl::Selectors::Vm.parse_all(strings)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
# Handler for the `pvectl wakeonlan node` command.
|
|
6
|
+
#
|
|
7
|
+
# Sends a Wake-on-LAN magic packet to a cluster node. The target node
|
|
8
|
+
# must have its MAC address registered in the cluster configuration
|
|
9
|
+
# (via `pvecm` or the web UI) — without it, Proxmox cannot assemble
|
|
10
|
+
# the packet and the command returns an error.
|
|
11
|
+
#
|
|
12
|
+
# The Proxmox API returns the MAC address used for the packet on
|
|
13
|
+
# success, which is surfaced in the output for confirmation.
|
|
14
|
+
#
|
|
15
|
+
# @example Wake up a node
|
|
16
|
+
# pvectl wakeonlan node pve3
|
|
17
|
+
#
|
|
18
|
+
# @example JSON output for scripting
|
|
19
|
+
# pvectl wakeonlan node pve3 -o json
|
|
20
|
+
#
|
|
21
|
+
class WakeonlanNode
|
|
22
|
+
# Registers the `wakeonlan node` command with the CLI.
|
|
23
|
+
#
|
|
24
|
+
# @param cli [GLI::App] the CLI application object
|
|
25
|
+
# @return [void]
|
|
26
|
+
def self.register(cli)
|
|
27
|
+
cli.desc "Send Wake-on-LAN packet to a cluster node"
|
|
28
|
+
cli.long_desc <<~HELP
|
|
29
|
+
Trigger a Wake-on-LAN magic packet to a cluster node via the
|
|
30
|
+
Proxmox API (POST /nodes/{node}/wakeonlan).
|
|
31
|
+
|
|
32
|
+
EXAMPLES
|
|
33
|
+
Wake a node:
|
|
34
|
+
$ pvectl wakeonlan node pve3
|
|
35
|
+
|
|
36
|
+
Output as JSON:
|
|
37
|
+
$ pvectl wakeonlan node pve3 -o json
|
|
38
|
+
|
|
39
|
+
NOTES
|
|
40
|
+
The target node must have its MAC address registered in the
|
|
41
|
+
cluster configuration beforehand. Use `pvecm` or the Proxmox
|
|
42
|
+
web UI to set the MAC for each node before relying on WoL.
|
|
43
|
+
|
|
44
|
+
The packet is sent by another online node in the cluster, so
|
|
45
|
+
at least one other node must be reachable.
|
|
46
|
+
|
|
47
|
+
SEE ALSO
|
|
48
|
+
pvectl help get nodes List nodes and current status
|
|
49
|
+
pvectl help describe node Show node details
|
|
50
|
+
HELP
|
|
51
|
+
cli.arg_name "RESOURCE_TYPE NAME"
|
|
52
|
+
cli.command :wakeonlan do |c|
|
|
53
|
+
c.action do |global_options, _options, args|
|
|
54
|
+
resource_type = args.shift
|
|
55
|
+
resource_name = args.shift
|
|
56
|
+
|
|
57
|
+
unless resource_type == "node"
|
|
58
|
+
$stderr.puts "Error: Only `pvectl wakeonlan node <NAME>` is supported"
|
|
59
|
+
exit Pvectl::ExitCodes::USAGE_ERROR
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
cmd = WakeonlanNode.new(resource_name, {}, global_options)
|
|
63
|
+
exit_code = cmd.execute
|
|
64
|
+
exit exit_code if exit_code != 0
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Creates a new command instance.
|
|
70
|
+
#
|
|
71
|
+
# @param node_name [String, nil] target node name
|
|
72
|
+
# @param options [Hash] command options
|
|
73
|
+
# @param global_options [Hash] global CLI options
|
|
74
|
+
# @param service [Services::Wakeonlan, nil] injected service (testing)
|
|
75
|
+
def initialize(node_name, options, global_options, service: nil)
|
|
76
|
+
@node_name = node_name
|
|
77
|
+
@options = options
|
|
78
|
+
@global_options = global_options
|
|
79
|
+
@service = service
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Executes the wakeonlan command.
|
|
83
|
+
#
|
|
84
|
+
# @return [Integer] exit code
|
|
85
|
+
def execute
|
|
86
|
+
return usage_error("NODE name is required") if @node_name.nil? || @node_name.to_s.empty?
|
|
87
|
+
|
|
88
|
+
result = service.execute(node_name: @node_name)
|
|
89
|
+
render(result)
|
|
90
|
+
|
|
91
|
+
result.successful? ? ExitCodes::SUCCESS : ExitCodes::GENERAL_ERROR
|
|
92
|
+
rescue Pvectl::Config::ConfigNotFoundError,
|
|
93
|
+
Pvectl::Config::InvalidConfigError,
|
|
94
|
+
Pvectl::Config::ContextNotFoundError,
|
|
95
|
+
Pvectl::Config::ClusterNotFoundError,
|
|
96
|
+
Pvectl::Config::UserNotFoundError
|
|
97
|
+
raise
|
|
98
|
+
rescue Timeout::Error, Errno::ECONNREFUSED, SocketError => e
|
|
99
|
+
$stderr.puts "Error: #{e.message}"
|
|
100
|
+
ExitCodes::CONNECTION_ERROR
|
|
101
|
+
rescue StandardError => e
|
|
102
|
+
$stderr.puts "Error: #{e.message}"
|
|
103
|
+
ExitCodes::GENERAL_ERROR
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
# Lazily builds the Wakeonlan service from current config.
|
|
109
|
+
#
|
|
110
|
+
# @return [Services::Wakeonlan]
|
|
111
|
+
def service
|
|
112
|
+
@service ||= begin
|
|
113
|
+
config_service = Pvectl::Config::Service.new
|
|
114
|
+
config_service.load(config: @global_options[:config])
|
|
115
|
+
connection = Pvectl::Connection.new(config_service.current_config)
|
|
116
|
+
node_repo = Pvectl::Repositories::Node.new(connection)
|
|
117
|
+
Pvectl::Services::Wakeonlan.new(node_repository: node_repo)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Renders the operation result using the requested output format.
|
|
122
|
+
#
|
|
123
|
+
# @param result [Models::NodeOperationResult]
|
|
124
|
+
# @return [void]
|
|
125
|
+
def render(result)
|
|
126
|
+
format = @global_options[:output] || "table"
|
|
127
|
+
presenter = Pvectl::Presenters::NodeOperationResult.new
|
|
128
|
+
formatter = Pvectl::Formatters::Registry.for(format)
|
|
129
|
+
puts formatter.format([result], presenter, color_enabled: color_enabled)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Determines color output based on global flag and TTY status.
|
|
133
|
+
#
|
|
134
|
+
# @return [Boolean]
|
|
135
|
+
def color_enabled
|
|
136
|
+
explicit = @global_options[:color]
|
|
137
|
+
return explicit unless explicit.nil?
|
|
138
|
+
|
|
139
|
+
$stdout.tty?
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Outputs a usage error and returns the proper exit code.
|
|
143
|
+
#
|
|
144
|
+
# @param msg [String]
|
|
145
|
+
# @return [Integer]
|
|
146
|
+
def usage_error(msg)
|
|
147
|
+
$stderr.puts "Error: #{msg}"
|
|
148
|
+
$stderr.puts "Usage: pvectl wakeonlan node <NODE>"
|
|
149
|
+
ExitCodes::USAGE_ERROR
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Config
|
|
5
|
+
# Base error class for all configuration-related exceptions.
|
|
6
|
+
#
|
|
7
|
+
# All configuration errors inherit from this class, allowing
|
|
8
|
+
# consumers to catch all config errors with a single rescue clause.
|
|
9
|
+
#
|
|
10
|
+
# @example Catching all configuration errors
|
|
11
|
+
# begin
|
|
12
|
+
# service.load(config: path)
|
|
13
|
+
# rescue Pvectl::Config::ConfigError => e
|
|
14
|
+
# $stderr.puts "Configuration error: #{e.message}"
|
|
15
|
+
# exit Pvectl::ExitCodes::CONFIG_ERROR
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
class ConfigError < StandardError; end
|
|
19
|
+
|
|
20
|
+
# Raised when the configuration file cannot be found at the specified path.
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# raise ConfigNotFoundError, "Configuration file not found: ~/.pvectl/config"
|
|
24
|
+
#
|
|
25
|
+
class ConfigNotFoundError < ConfigError; end
|
|
26
|
+
|
|
27
|
+
# Raised when the configuration file contains invalid YAML or structure.
|
|
28
|
+
#
|
|
29
|
+
# @example
|
|
30
|
+
# raise InvalidConfigError, "Invalid YAML syntax at line 5"
|
|
31
|
+
#
|
|
32
|
+
class InvalidConfigError < ConfigError; end
|
|
33
|
+
|
|
34
|
+
# Raised when a referenced context does not exist in the configuration.
|
|
35
|
+
#
|
|
36
|
+
# @example
|
|
37
|
+
# raise ContextNotFoundError, "Context 'production' not found"
|
|
38
|
+
#
|
|
39
|
+
class ContextNotFoundError < ConfigError; end
|
|
40
|
+
|
|
41
|
+
# Raised when a context references a cluster that does not exist.
|
|
42
|
+
#
|
|
43
|
+
# @example
|
|
44
|
+
# raise ClusterNotFoundError, "Cluster 'main' not found in configuration"
|
|
45
|
+
#
|
|
46
|
+
class ClusterNotFoundError < ConfigError; end
|
|
47
|
+
|
|
48
|
+
# Raised when a context references a user that does not exist.
|
|
49
|
+
#
|
|
50
|
+
# @example
|
|
51
|
+
# raise UserNotFoundError, "User 'admin' not found in configuration"
|
|
52
|
+
#
|
|
53
|
+
class UserNotFoundError < ConfigError; end
|
|
54
|
+
|
|
55
|
+
# Raised when no valid credentials are available for authentication.
|
|
56
|
+
#
|
|
57
|
+
# @example
|
|
58
|
+
# raise MissingCredentialsError, "No valid credentials found. Provide token or username/password"
|
|
59
|
+
#
|
|
60
|
+
class MissingCredentialsError < ConfigError; end
|
|
61
|
+
end
|
|
62
|
+
end
|