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,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
module Config
|
|
6
|
+
# Handler for the `pvectl config use-context` command.
|
|
7
|
+
#
|
|
8
|
+
# Switches the active context in the configuration file.
|
|
9
|
+
# The context name must exist in the configuration.
|
|
10
|
+
#
|
|
11
|
+
# @example Usage
|
|
12
|
+
# pvectl config use-context production
|
|
13
|
+
# pvectl config use-context dev
|
|
14
|
+
#
|
|
15
|
+
class UseContext
|
|
16
|
+
# Registers the use-context subcommand.
|
|
17
|
+
#
|
|
18
|
+
# @param parent [GLI::Command] parent config command
|
|
19
|
+
# @return [void]
|
|
20
|
+
def self.register_subcommand(parent)
|
|
21
|
+
parent.desc "Switch to a different context"
|
|
22
|
+
parent.long_desc <<~HELP
|
|
23
|
+
Switch the active context. The context determines which Proxmox
|
|
24
|
+
cluster and credentials are used for subsequent commands.
|
|
25
|
+
|
|
26
|
+
EXAMPLES
|
|
27
|
+
Switch to production:
|
|
28
|
+
$ pvectl config use-context production
|
|
29
|
+
|
|
30
|
+
NOTES
|
|
31
|
+
Changes are persisted to the config file immediately.
|
|
32
|
+
Use PVECTL_CONTEXT env var for temporary overrides.
|
|
33
|
+
HELP
|
|
34
|
+
parent.command :"use-context" do |use_ctx|
|
|
35
|
+
use_ctx.arg_name "CONTEXT_NAME"
|
|
36
|
+
use_ctx.action do |global_options, _options, args|
|
|
37
|
+
if args.empty?
|
|
38
|
+
$stderr.puts "Error: context name is required"
|
|
39
|
+
exit ExitCodes::USAGE_ERROR
|
|
40
|
+
end
|
|
41
|
+
exit_code = execute(args[0], global_options)
|
|
42
|
+
exit exit_code if exit_code != 0
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Executes the use-context command.
|
|
48
|
+
#
|
|
49
|
+
# @param context_name [String] name of the context to switch to
|
|
50
|
+
# @param global_options [Hash] global CLI options (includes :config path)
|
|
51
|
+
# @return [Integer] exit code (0 for success)
|
|
52
|
+
# @raise [Config::ContextNotFoundError] if context doesn't exist
|
|
53
|
+
def self.execute(context_name, global_options)
|
|
54
|
+
config_path = global_options[:config]
|
|
55
|
+
service = Pvectl::Config::Service.new
|
|
56
|
+
service.load(config: config_path)
|
|
57
|
+
|
|
58
|
+
service.use_context(context_name)
|
|
59
|
+
|
|
60
|
+
puts "Switched to context \"#{context_name}\"."
|
|
61
|
+
0
|
|
62
|
+
rescue Pvectl::Config::ContextNotFoundError => e
|
|
63
|
+
$stderr.puts "Error: #{e.message}"
|
|
64
|
+
ExitCodes::CONFIG_ERROR
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "yaml"
|
|
5
|
+
|
|
6
|
+
module Pvectl
|
|
7
|
+
module Commands
|
|
8
|
+
module Config
|
|
9
|
+
# Handler for the `pvectl config view` command.
|
|
10
|
+
#
|
|
11
|
+
# Displays the current configuration with secrets masked.
|
|
12
|
+
# Secrets (token-secret, password) are replaced with ********.
|
|
13
|
+
#
|
|
14
|
+
# @example Usage
|
|
15
|
+
# pvectl config view
|
|
16
|
+
# pvectl config view -o json
|
|
17
|
+
#
|
|
18
|
+
class View
|
|
19
|
+
# Registers the view subcommand.
|
|
20
|
+
#
|
|
21
|
+
# @param parent [GLI::Command] parent config command
|
|
22
|
+
# @return [void]
|
|
23
|
+
def self.register_subcommand(parent)
|
|
24
|
+
parent.desc "Display current configuration with masked secrets"
|
|
25
|
+
parent.long_desc <<~HELP
|
|
26
|
+
Display the current configuration file contents. Secrets (token
|
|
27
|
+
secrets, passwords) are masked for security.
|
|
28
|
+
|
|
29
|
+
EXAMPLES
|
|
30
|
+
$ pvectl config view
|
|
31
|
+
$ pvectl config view -o yaml
|
|
32
|
+
HELP
|
|
33
|
+
parent.command :view do |view|
|
|
34
|
+
view.action do |global_options, _options, _args|
|
|
35
|
+
exit_code = execute(global_options)
|
|
36
|
+
exit exit_code if exit_code != 0
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Executes the view command.
|
|
42
|
+
#
|
|
43
|
+
# @param global_options [Hash] global CLI options (includes :config, :output)
|
|
44
|
+
# @return [Integer] exit code (0 for success)
|
|
45
|
+
def self.execute(global_options)
|
|
46
|
+
config_path = global_options[:config]
|
|
47
|
+
output_format = global_options[:output] || "yaml"
|
|
48
|
+
|
|
49
|
+
service = Pvectl::Config::Service.new
|
|
50
|
+
service.load(config: config_path)
|
|
51
|
+
|
|
52
|
+
masked_config = service.masked_config
|
|
53
|
+
|
|
54
|
+
case output_format
|
|
55
|
+
when "json"
|
|
56
|
+
puts JSON.pretty_generate(masked_config)
|
|
57
|
+
else
|
|
58
|
+
# Default to YAML for human-readable output
|
|
59
|
+
puts masked_config.to_yaml
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
0
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
# CLI registration for the `pvectl console` command.
|
|
6
|
+
#
|
|
7
|
+
# Opens an interactive terminal console to a VM or container via
|
|
8
|
+
# WebSocket-based termproxy. Dispatches to {ConsoleVm} or {ConsoleCt}
|
|
9
|
+
# based on the resource type argument.
|
|
10
|
+
#
|
|
11
|
+
# @example Open console to a VM
|
|
12
|
+
# pvectl console vm 100
|
|
13
|
+
#
|
|
14
|
+
# @example Open console to a container
|
|
15
|
+
# pvectl console ct 200
|
|
16
|
+
#
|
|
17
|
+
# @example Open console with explicit credentials
|
|
18
|
+
# pvectl console vm 100 --user root@pam --password secret
|
|
19
|
+
#
|
|
20
|
+
class Console
|
|
21
|
+
# Supported resource type arguments.
|
|
22
|
+
SUPPORTED_RESOURCES = %w[vm ct container].freeze
|
|
23
|
+
|
|
24
|
+
# Registers the console command with the CLI.
|
|
25
|
+
#
|
|
26
|
+
# @param cli [GLI::App] the CLI application object
|
|
27
|
+
# @return [void]
|
|
28
|
+
def self.register(cli)
|
|
29
|
+
cli.desc "Open interactive terminal console to a VM or container"
|
|
30
|
+
cli.long_desc <<~HELP
|
|
31
|
+
Open an interactive terminal session to a VM or container via
|
|
32
|
+
WebSocket-based termproxy (xtermjs protocol).
|
|
33
|
+
|
|
34
|
+
EXAMPLES
|
|
35
|
+
Open console to a VM:
|
|
36
|
+
$ pvectl console vm 100
|
|
37
|
+
|
|
38
|
+
Open console to a container:
|
|
39
|
+
$ pvectl console ct 200
|
|
40
|
+
|
|
41
|
+
Specify node explicitly:
|
|
42
|
+
$ pvectl console vm 100 --node pve1
|
|
43
|
+
|
|
44
|
+
Provide credentials (prompted for password if omitted):
|
|
45
|
+
$ pvectl console vm 100 --user root@pam
|
|
46
|
+
|
|
47
|
+
NOTES
|
|
48
|
+
Console requires session authentication (username/password). If your
|
|
49
|
+
config only has an API token, pvectl will prompt for credentials.
|
|
50
|
+
|
|
51
|
+
Disconnect with Ctrl+].
|
|
52
|
+
|
|
53
|
+
The console uses a WebSocket connection. Network interruptions will
|
|
54
|
+
close the session.
|
|
55
|
+
|
|
56
|
+
SEE ALSO
|
|
57
|
+
pvectl help describe View VM/container configuration
|
|
58
|
+
pvectl help start Start a stopped VM before connecting
|
|
59
|
+
HELP
|
|
60
|
+
cli.arg_name "RESOURCE_TYPE ID"
|
|
61
|
+
cli.command :console do |c|
|
|
62
|
+
c.desc "Filter by node name"
|
|
63
|
+
c.flag [:node, :n], arg_name: "NODE"
|
|
64
|
+
|
|
65
|
+
c.desc "Username for session authentication"
|
|
66
|
+
c.flag [:user], arg_name: "USER"
|
|
67
|
+
|
|
68
|
+
c.desc "Password for session authentication"
|
|
69
|
+
c.flag [:password], arg_name: "PASSWORD"
|
|
70
|
+
|
|
71
|
+
c.action do |global_options, options, args|
|
|
72
|
+
resource_type = args.shift
|
|
73
|
+
resource_id = args.shift
|
|
74
|
+
|
|
75
|
+
unless resource_type && SUPPORTED_RESOURCES.include?(resource_type)
|
|
76
|
+
$stderr.puts "Error: Resource type required (vm, ct)"
|
|
77
|
+
exit Pvectl::ExitCodes::USAGE_ERROR
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
exit_code = case resource_type
|
|
81
|
+
when "ct", "container"
|
|
82
|
+
ConsoleCt.execute(resource_id, options, global_options)
|
|
83
|
+
else
|
|
84
|
+
ConsoleVm.execute(resource_id, options, global_options)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
exit exit_code if exit_code != 0
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "io/console"
|
|
4
|
+
|
|
5
|
+
module Pvectl
|
|
6
|
+
module Commands
|
|
7
|
+
# Handler for the `pvectl console ct` command.
|
|
8
|
+
#
|
|
9
|
+
# Opens an interactive terminal console session to an LXC container
|
|
10
|
+
# via WebSocket-based termproxy. Requires a running container and
|
|
11
|
+
# interactive terminal (TTY).
|
|
12
|
+
#
|
|
13
|
+
# @example Open console to container 200
|
|
14
|
+
# pvectl console ct 200
|
|
15
|
+
#
|
|
16
|
+
# @example Open console with explicit credentials
|
|
17
|
+
# pvectl console ct 200 --user root@pam --password secret
|
|
18
|
+
#
|
|
19
|
+
class ConsoleCt
|
|
20
|
+
# Executes the console container command.
|
|
21
|
+
#
|
|
22
|
+
# @param ctid [String, nil] container identifier
|
|
23
|
+
# @param options [Hash] command options (:user, :password)
|
|
24
|
+
# @param global_options [Hash] global CLI options
|
|
25
|
+
# @return [Integer] exit code
|
|
26
|
+
def self.execute(ctid, options, global_options)
|
|
27
|
+
new(ctid, options, global_options).execute
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Initializes a console container command.
|
|
31
|
+
#
|
|
32
|
+
# @param ctid [String, nil] container identifier
|
|
33
|
+
# @param options [Hash] command options
|
|
34
|
+
# @param global_options [Hash] global CLI options
|
|
35
|
+
def initialize(ctid, options, global_options)
|
|
36
|
+
@ctid = ctid
|
|
37
|
+
@options = options
|
|
38
|
+
@global_options = global_options
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Executes the console flow.
|
|
42
|
+
#
|
|
43
|
+
# @return [Integer] exit code
|
|
44
|
+
def execute
|
|
45
|
+
return usage_error("CTID is required") unless @ctid
|
|
46
|
+
return usage_error("Console requires an interactive terminal (TTY)") unless $stdin.tty?
|
|
47
|
+
|
|
48
|
+
load_config
|
|
49
|
+
connection = Pvectl::Connection.new(@config)
|
|
50
|
+
repo = Pvectl::Repositories::Container.new(connection)
|
|
51
|
+
|
|
52
|
+
resource = repo.get(@ctid.to_i)
|
|
53
|
+
return not_found("Container #{@ctid} not found") unless resource
|
|
54
|
+
|
|
55
|
+
username, password = resolve_credentials
|
|
56
|
+
return ExitCodes::GENERAL_ERROR if username.nil? || password.nil?
|
|
57
|
+
|
|
58
|
+
$stderr.puts "Connecting to container #{resource.vmid} (#{resource.name || 'unnamed'}) on node #{resource.node}..."
|
|
59
|
+
|
|
60
|
+
Pvectl::Services::Console.new.run(
|
|
61
|
+
resource: resource,
|
|
62
|
+
resource_path: resource_path,
|
|
63
|
+
server: @config.server,
|
|
64
|
+
username: username,
|
|
65
|
+
password: password,
|
|
66
|
+
verify_ssl: @config.verify_ssl
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
ExitCodes::SUCCESS
|
|
70
|
+
rescue Services::Console::ResourceNotRunningError => e
|
|
71
|
+
$stderr.puts "Error: #{e.message}"
|
|
72
|
+
ExitCodes::GENERAL_ERROR
|
|
73
|
+
rescue Services::Console::AuthenticationError => e
|
|
74
|
+
$stderr.puts "Error: #{e.message}"
|
|
75
|
+
ExitCodes::PERMISSION_DENIED
|
|
76
|
+
rescue Pvectl::Config::ConfigNotFoundError,
|
|
77
|
+
Pvectl::Config::InvalidConfigError,
|
|
78
|
+
Pvectl::Config::ContextNotFoundError,
|
|
79
|
+
Pvectl::Config::ClusterNotFoundError,
|
|
80
|
+
Pvectl::Config::UserNotFoundError,
|
|
81
|
+
Pvectl::Config::MissingCredentialsError
|
|
82
|
+
raise # re-raise for CLI handler
|
|
83
|
+
rescue Errno::ECONNREFUSED, SocketError, Timeout::Error => e
|
|
84
|
+
$stderr.puts "Error: Cannot connect to console: #{e.message}"
|
|
85
|
+
ExitCodes::CONNECTION_ERROR
|
|
86
|
+
rescue StandardError => e
|
|
87
|
+
$stderr.puts "Error: #{e.message}"
|
|
88
|
+
ExitCodes::GENERAL_ERROR
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
# Returns the API resource path for an LXC container.
|
|
94
|
+
#
|
|
95
|
+
# @return [String] resource path segment
|
|
96
|
+
def resource_path
|
|
97
|
+
"lxc/#{@ctid}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Resolves authentication credentials for the console session.
|
|
101
|
+
#
|
|
102
|
+
# Priority: CLI flags > config file > interactive prompt.
|
|
103
|
+
# Extracts default username from token_id when available.
|
|
104
|
+
#
|
|
105
|
+
# @return [Array<String, String>, Array<nil, nil>] [username, password] or [nil, nil] if cancelled
|
|
106
|
+
def resolve_credentials
|
|
107
|
+
username = @options[:user]
|
|
108
|
+
password = @options[:password]
|
|
109
|
+
|
|
110
|
+
if username.nil? && password.nil? && @config.username && @config.password
|
|
111
|
+
username = @config.username
|
|
112
|
+
password = @config.password
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
if username.nil? && @config.token_id
|
|
116
|
+
# Extract default username from token_id (e.g., "root@pam!pvectl" -> "root@pam")
|
|
117
|
+
default_username = @config.token_id.split("!").first
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# When credentials come from config (username+password pair), use them directly.
|
|
121
|
+
# Otherwise, prompt interactively — always show both prompts so the user knows
|
|
122
|
+
# which username will be used and can change it.
|
|
123
|
+
if password.nil?
|
|
124
|
+
username = prompt_username(username || default_username)
|
|
125
|
+
return [nil, nil] if username.nil?
|
|
126
|
+
|
|
127
|
+
password = prompt_password
|
|
128
|
+
end
|
|
129
|
+
return [nil, nil] if password.nil?
|
|
130
|
+
|
|
131
|
+
[username, password]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Prompts the user for a username.
|
|
135
|
+
#
|
|
136
|
+
# @param default [String, nil] default username to suggest
|
|
137
|
+
# @return [String, nil] entered username or nil if cancelled
|
|
138
|
+
def prompt_username(default = nil)
|
|
139
|
+
prompt = default ? "Username [#{default}]: " : "Username: "
|
|
140
|
+
$stderr.print prompt
|
|
141
|
+
input = $stdin.gets&.strip
|
|
142
|
+
return nil if input.nil?
|
|
143
|
+
|
|
144
|
+
input.empty? ? default : input
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Prompts the user for a password (hidden input).
|
|
148
|
+
#
|
|
149
|
+
# @return [String, nil] entered password or nil if cancelled
|
|
150
|
+
def prompt_password
|
|
151
|
+
$stderr.print "Password: "
|
|
152
|
+
password = $stdin.noecho(&:gets)&.strip
|
|
153
|
+
$stderr.puts # newline after hidden input
|
|
154
|
+
return nil if password.nil? || password.empty?
|
|
155
|
+
|
|
156
|
+
password
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Loads configuration from file or environment.
|
|
160
|
+
#
|
|
161
|
+
# @return [void]
|
|
162
|
+
def load_config
|
|
163
|
+
service = Pvectl::Config::Service.new
|
|
164
|
+
service.load(config: @global_options[:config])
|
|
165
|
+
@config = service.current_config
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Outputs a usage error and returns the exit code.
|
|
169
|
+
#
|
|
170
|
+
# @param message [String] error message
|
|
171
|
+
# @return [Integer] USAGE_ERROR exit code
|
|
172
|
+
def usage_error(message)
|
|
173
|
+
$stderr.puts "Error: #{message}"
|
|
174
|
+
ExitCodes::USAGE_ERROR
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Outputs a not-found error and returns the exit code.
|
|
178
|
+
#
|
|
179
|
+
# @param message [String] error message
|
|
180
|
+
# @return [Integer] NOT_FOUND exit code
|
|
181
|
+
def not_found(message)
|
|
182
|
+
$stderr.puts "Error: #{message}"
|
|
183
|
+
ExitCodes::NOT_FOUND
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "io/console"
|
|
4
|
+
|
|
5
|
+
module Pvectl
|
|
6
|
+
module Commands
|
|
7
|
+
# Handler for the `pvectl console vm` command.
|
|
8
|
+
#
|
|
9
|
+
# Opens an interactive terminal console session to a QEMU virtual machine
|
|
10
|
+
# via WebSocket-based termproxy. Requires a running VM and interactive
|
|
11
|
+
# terminal (TTY).
|
|
12
|
+
#
|
|
13
|
+
# @example Open console to VM 100
|
|
14
|
+
# pvectl console vm 100
|
|
15
|
+
#
|
|
16
|
+
# @example Open console with explicit credentials
|
|
17
|
+
# pvectl console vm 100 --user root@pam --password secret
|
|
18
|
+
#
|
|
19
|
+
class ConsoleVm
|
|
20
|
+
# Executes the console VM command.
|
|
21
|
+
#
|
|
22
|
+
# @param vmid [String, nil] VM identifier
|
|
23
|
+
# @param options [Hash] command options (:user, :password)
|
|
24
|
+
# @param global_options [Hash] global CLI options
|
|
25
|
+
# @return [Integer] exit code
|
|
26
|
+
def self.execute(vmid, options, global_options)
|
|
27
|
+
new(vmid, options, global_options).execute
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Initializes a console VM command.
|
|
31
|
+
#
|
|
32
|
+
# @param vmid [String, nil] VM identifier
|
|
33
|
+
# @param options [Hash] command options
|
|
34
|
+
# @param global_options [Hash] global CLI options
|
|
35
|
+
def initialize(vmid, options, global_options)
|
|
36
|
+
@vmid = vmid
|
|
37
|
+
@options = options
|
|
38
|
+
@global_options = global_options
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Executes the console flow.
|
|
42
|
+
#
|
|
43
|
+
# @return [Integer] exit code
|
|
44
|
+
def execute
|
|
45
|
+
return usage_error("VMID is required") unless @vmid
|
|
46
|
+
return usage_error("Console requires an interactive terminal (TTY)") unless $stdin.tty?
|
|
47
|
+
|
|
48
|
+
load_config
|
|
49
|
+
connection = Pvectl::Connection.new(@config)
|
|
50
|
+
repo = Pvectl::Repositories::Vm.new(connection)
|
|
51
|
+
|
|
52
|
+
resource = repo.get(@vmid.to_i)
|
|
53
|
+
return not_found("VM #{@vmid} not found") unless resource
|
|
54
|
+
|
|
55
|
+
username, password = resolve_credentials
|
|
56
|
+
return ExitCodes::GENERAL_ERROR if username.nil? || password.nil?
|
|
57
|
+
|
|
58
|
+
$stderr.puts "Connecting to VM #{resource.vmid} (#{resource.name || 'unnamed'}) on node #{resource.node}..."
|
|
59
|
+
|
|
60
|
+
Pvectl::Services::Console.new.run(
|
|
61
|
+
resource: resource,
|
|
62
|
+
resource_path: resource_path,
|
|
63
|
+
server: @config.server,
|
|
64
|
+
username: username,
|
|
65
|
+
password: password,
|
|
66
|
+
verify_ssl: @config.verify_ssl
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
ExitCodes::SUCCESS
|
|
70
|
+
rescue Services::Console::ResourceNotRunningError => e
|
|
71
|
+
$stderr.puts "Error: #{e.message}"
|
|
72
|
+
ExitCodes::GENERAL_ERROR
|
|
73
|
+
rescue Services::Console::AuthenticationError => e
|
|
74
|
+
$stderr.puts "Error: #{e.message}"
|
|
75
|
+
ExitCodes::PERMISSION_DENIED
|
|
76
|
+
rescue Pvectl::Config::ConfigNotFoundError,
|
|
77
|
+
Pvectl::Config::InvalidConfigError,
|
|
78
|
+
Pvectl::Config::ContextNotFoundError,
|
|
79
|
+
Pvectl::Config::ClusterNotFoundError,
|
|
80
|
+
Pvectl::Config::UserNotFoundError,
|
|
81
|
+
Pvectl::Config::MissingCredentialsError
|
|
82
|
+
raise # re-raise for CLI handler
|
|
83
|
+
rescue Errno::ECONNREFUSED, SocketError, Timeout::Error => e
|
|
84
|
+
$stderr.puts "Error: Cannot connect to console: #{e.message}"
|
|
85
|
+
ExitCodes::CONNECTION_ERROR
|
|
86
|
+
rescue StandardError => e
|
|
87
|
+
$stderr.puts "Error: #{e.message}"
|
|
88
|
+
ExitCodes::GENERAL_ERROR
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
# Returns the API resource path for a QEMU VM.
|
|
94
|
+
#
|
|
95
|
+
# @return [String] resource path segment
|
|
96
|
+
def resource_path
|
|
97
|
+
"qemu/#{@vmid}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Resolves authentication credentials for the console session.
|
|
101
|
+
#
|
|
102
|
+
# Priority: CLI flags > config file > interactive prompt.
|
|
103
|
+
# Extracts default username from token_id when available.
|
|
104
|
+
#
|
|
105
|
+
# @return [Array<String, String>, Array<nil, nil>] [username, password] or [nil, nil] if cancelled
|
|
106
|
+
def resolve_credentials
|
|
107
|
+
username = @options[:user]
|
|
108
|
+
password = @options[:password]
|
|
109
|
+
|
|
110
|
+
if username.nil? && password.nil? && @config.username && @config.password
|
|
111
|
+
username = @config.username
|
|
112
|
+
password = @config.password
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
if username.nil? && @config.token_id
|
|
116
|
+
# Extract default username from token_id (e.g., "root@pam!pvectl" -> "root@pam")
|
|
117
|
+
default_username = @config.token_id.split("!").first
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# When credentials come from config (username+password pair), use them directly.
|
|
121
|
+
# Otherwise, prompt interactively — always show both prompts so the user knows
|
|
122
|
+
# which username will be used and can change it.
|
|
123
|
+
if password.nil?
|
|
124
|
+
username = prompt_username(username || default_username)
|
|
125
|
+
return [nil, nil] if username.nil?
|
|
126
|
+
|
|
127
|
+
password = prompt_password
|
|
128
|
+
end
|
|
129
|
+
return [nil, nil] if password.nil?
|
|
130
|
+
|
|
131
|
+
[username, password]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Prompts the user for a username.
|
|
135
|
+
#
|
|
136
|
+
# @param default [String, nil] default username to suggest
|
|
137
|
+
# @return [String, nil] entered username or nil if cancelled
|
|
138
|
+
def prompt_username(default = nil)
|
|
139
|
+
prompt = default ? "Username [#{default}]: " : "Username: "
|
|
140
|
+
$stderr.print prompt
|
|
141
|
+
input = $stdin.gets&.strip
|
|
142
|
+
return nil if input.nil?
|
|
143
|
+
|
|
144
|
+
input.empty? ? default : input
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Prompts the user for a password (hidden input).
|
|
148
|
+
#
|
|
149
|
+
# @return [String, nil] entered password or nil if cancelled
|
|
150
|
+
def prompt_password
|
|
151
|
+
$stderr.print "Password: "
|
|
152
|
+
password = $stdin.noecho(&:gets)&.strip
|
|
153
|
+
$stderr.puts # newline after hidden input
|
|
154
|
+
return nil if password.nil? || password.empty?
|
|
155
|
+
|
|
156
|
+
password
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Loads configuration from file or environment.
|
|
160
|
+
#
|
|
161
|
+
# @return [void]
|
|
162
|
+
def load_config
|
|
163
|
+
service = Pvectl::Config::Service.new
|
|
164
|
+
service.load(config: @global_options[:config])
|
|
165
|
+
@config = service.current_config
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Outputs a usage error and returns the exit code.
|
|
169
|
+
#
|
|
170
|
+
# @param message [String] error message
|
|
171
|
+
# @return [Integer] USAGE_ERROR exit code
|
|
172
|
+
def usage_error(message)
|
|
173
|
+
$stderr.puts "Error: #{message}"
|
|
174
|
+
ExitCodes::USAGE_ERROR
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Outputs a not-found error and returns the exit code.
|
|
178
|
+
#
|
|
179
|
+
# @param message [String] error message
|
|
180
|
+
# @return [Integer] NOT_FOUND exit code
|
|
181
|
+
def not_found(message)
|
|
182
|
+
$stderr.puts "Error: #{message}"
|
|
183
|
+
ExitCodes::NOT_FOUND
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Commands
|
|
5
|
+
# Container-specific lifecycle command hooks.
|
|
6
|
+
#
|
|
7
|
+
# Provides container repository, selector, service, and presenter
|
|
8
|
+
# to ResourceLifecycleCommand's template methods.
|
|
9
|
+
#
|
|
10
|
+
# @example Usage
|
|
11
|
+
# class StartContainer
|
|
12
|
+
# include ContainerLifecycleCommand
|
|
13
|
+
# OPERATION = :start
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
module ContainerLifecycleCommand
|
|
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[container ct]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [String] human label for container resources
|
|
34
|
+
def resource_label
|
|
35
|
+
"container"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [String] human label for container IDs
|
|
39
|
+
def resource_id_label
|
|
40
|
+
"CTID"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Builds container repository.
|
|
44
|
+
#
|
|
45
|
+
# @param connection [Connection] API connection
|
|
46
|
+
# @return [Repositories::Container] container repository
|
|
47
|
+
def build_repository(connection)
|
|
48
|
+
Pvectl::Repositories::Container.new(connection)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Builds container lifecycle service.
|
|
52
|
+
#
|
|
53
|
+
# @param repo [Repositories::Container] container repository
|
|
54
|
+
# @param task_repo [Repositories::Task] task repository
|
|
55
|
+
# @param options [Hash] service options
|
|
56
|
+
# @return [Services::ContainerLifecycle] container lifecycle service
|
|
57
|
+
def build_service(repo, task_repo, options)
|
|
58
|
+
Pvectl::Services::ContainerLifecycle.new(repo, task_repo, options)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Builds container operation result presenter.
|
|
62
|
+
#
|
|
63
|
+
# @return [Presenters::ContainerOperationResult] presenter
|
|
64
|
+
def build_presenter
|
|
65
|
+
Pvectl::Presenters::ContainerOperationResult.new
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Builds container selector from strings.
|
|
69
|
+
#
|
|
70
|
+
# @param strings [Array<String>] selector strings
|
|
71
|
+
# @return [Selectors::Container] parsed selector
|
|
72
|
+
def build_selector(strings)
|
|
73
|
+
Pvectl::Selectors::Container.parse_all(strings)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|