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,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
|
|
6
|
+
module Pvectl
|
|
7
|
+
module Config
|
|
8
|
+
# Handles YAML configuration file persistence.
|
|
9
|
+
#
|
|
10
|
+
# Store manages saving configuration to YAML files with proper
|
|
11
|
+
# secure file permissions. It ensures config files are created
|
|
12
|
+
# with mode 0600 (owner read/write only) and directories with
|
|
13
|
+
# mode 0700 (owner access only).
|
|
14
|
+
#
|
|
15
|
+
# @example Saving configuration
|
|
16
|
+
# store = Store.new
|
|
17
|
+
# store.save("~/.pvectl/config", config_hash)
|
|
18
|
+
#
|
|
19
|
+
# @example Updating current context
|
|
20
|
+
# store.update_current_context("~/.pvectl/config", "production")
|
|
21
|
+
#
|
|
22
|
+
class Store
|
|
23
|
+
# Secure file permissions (owner read/write only)
|
|
24
|
+
SECURE_MODE = 0o600
|
|
25
|
+
|
|
26
|
+
# Secure directory permissions (owner access only)
|
|
27
|
+
SECURE_DIR_MODE = 0o700
|
|
28
|
+
|
|
29
|
+
# Saves configuration to a YAML file with secure permissions.
|
|
30
|
+
#
|
|
31
|
+
# Creates the parent directory if it doesn't exist, with secure
|
|
32
|
+
# permissions. The config file is written with mode 0600.
|
|
33
|
+
#
|
|
34
|
+
# @param path [String] path to configuration file
|
|
35
|
+
# @param config [Hash] configuration to save
|
|
36
|
+
# @return [void]
|
|
37
|
+
# @raise [Errno::EACCES] if permission denied
|
|
38
|
+
def save(path, config)
|
|
39
|
+
dir = File.dirname(path)
|
|
40
|
+
|
|
41
|
+
unless File.directory?(dir)
|
|
42
|
+
FileUtils.mkdir_p(dir)
|
|
43
|
+
File.chmod(SECURE_DIR_MODE, dir)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
File.write(path, YAML.dump(config))
|
|
47
|
+
File.chmod(SECURE_MODE, path)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Updates only the current-context in an existing config file.
|
|
51
|
+
#
|
|
52
|
+
# Preserves all other configuration data and file permissions.
|
|
53
|
+
#
|
|
54
|
+
# @param path [String] path to configuration file
|
|
55
|
+
# @param context_name [String] new current context name
|
|
56
|
+
# @return [void]
|
|
57
|
+
# @raise [ConfigNotFoundError] if file does not exist
|
|
58
|
+
def update_current_context(path, context_name)
|
|
59
|
+
raise ConfigNotFoundError, "Configuration file not found: #{path}" unless File.exist?(path)
|
|
60
|
+
|
|
61
|
+
config = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
|
|
62
|
+
config["current-context"] = context_name
|
|
63
|
+
|
|
64
|
+
# Preserve original permissions
|
|
65
|
+
mode = File.stat(path).mode & 0o777
|
|
66
|
+
File.write(path, YAML.dump(config))
|
|
67
|
+
File.chmod(mode, path)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Adds or updates a context in the configuration file.
|
|
71
|
+
#
|
|
72
|
+
# If a context with the same name exists, it is replaced.
|
|
73
|
+
# Otherwise, the new context is appended.
|
|
74
|
+
#
|
|
75
|
+
# @param path [String] path to configuration file
|
|
76
|
+
# @param context [Models::Context] context to add or update
|
|
77
|
+
# @return [void]
|
|
78
|
+
# @raise [ConfigNotFoundError] if file does not exist
|
|
79
|
+
def upsert_context(path, context)
|
|
80
|
+
raise ConfigNotFoundError, "Configuration file not found: #{path}" unless File.exist?(path)
|
|
81
|
+
|
|
82
|
+
config = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
|
|
83
|
+
contexts = config["contexts"] ||= []
|
|
84
|
+
|
|
85
|
+
# Find existing context index
|
|
86
|
+
existing_index = contexts.find_index { |c| c["name"] == context.name }
|
|
87
|
+
|
|
88
|
+
if existing_index
|
|
89
|
+
contexts[existing_index] = context.to_hash
|
|
90
|
+
else
|
|
91
|
+
contexts << context.to_hash
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Preserve original permissions
|
|
95
|
+
mode = File.stat(path).mode & 0o777
|
|
96
|
+
File.write(path, YAML.dump(config))
|
|
97
|
+
File.chmod(mode, path)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Adds or updates a cluster in the configuration file.
|
|
101
|
+
#
|
|
102
|
+
# If a cluster with the same name exists, it is replaced.
|
|
103
|
+
# Otherwise, the new cluster is appended.
|
|
104
|
+
#
|
|
105
|
+
# @param path [String] path to configuration file
|
|
106
|
+
# @param cluster [Models::Cluster] cluster to add or update
|
|
107
|
+
# @return [void]
|
|
108
|
+
# @raise [ConfigNotFoundError] if file does not exist
|
|
109
|
+
def upsert_cluster(path, cluster)
|
|
110
|
+
raise ConfigNotFoundError, "Configuration file not found: #{path}" unless File.exist?(path)
|
|
111
|
+
|
|
112
|
+
config = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
|
|
113
|
+
clusters = config["clusters"] ||= []
|
|
114
|
+
|
|
115
|
+
# Find existing cluster index
|
|
116
|
+
existing_index = clusters.find_index { |c| c["name"] == cluster.name }
|
|
117
|
+
|
|
118
|
+
if existing_index
|
|
119
|
+
clusters[existing_index] = cluster.to_hash
|
|
120
|
+
else
|
|
121
|
+
clusters << cluster.to_hash
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Preserve original permissions
|
|
125
|
+
mode = File.stat(path).mode & 0o777
|
|
126
|
+
File.write(path, YAML.dump(config))
|
|
127
|
+
File.chmod(mode, path)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Adds or updates a user in the configuration file.
|
|
131
|
+
#
|
|
132
|
+
# If a user with the same name exists, it is replaced.
|
|
133
|
+
# Otherwise, the new user is appended.
|
|
134
|
+
#
|
|
135
|
+
# @param path [String] path to configuration file
|
|
136
|
+
# @param user [Models::User] user to add or update
|
|
137
|
+
# @return [void]
|
|
138
|
+
# @raise [ConfigNotFoundError] if file does not exist
|
|
139
|
+
def upsert_user(path, user)
|
|
140
|
+
raise ConfigNotFoundError, "Configuration file not found: #{path}" unless File.exist?(path)
|
|
141
|
+
|
|
142
|
+
config = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
|
|
143
|
+
users = config["users"] ||= []
|
|
144
|
+
|
|
145
|
+
# Find existing user index
|
|
146
|
+
existing_index = users.find_index { |u| u["name"] == user.name }
|
|
147
|
+
|
|
148
|
+
if existing_index
|
|
149
|
+
users[existing_index] = user.to_hash
|
|
150
|
+
else
|
|
151
|
+
users << user.to_hash
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Preserve original permissions
|
|
155
|
+
mode = File.stat(path).mode & 0o777
|
|
156
|
+
File.write(path, YAML.dump(config))
|
|
157
|
+
File.chmod(mode, path)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pvectl
|
|
4
|
+
module Config
|
|
5
|
+
# Interactive configuration wizard for first-time setup.
|
|
6
|
+
#
|
|
7
|
+
# Wizard guides users through initial configuration by prompting
|
|
8
|
+
# for server URL, authentication credentials, and SSL settings.
|
|
9
|
+
# It only runs when stdin is a TTY (not in pipes or scripts).
|
|
10
|
+
#
|
|
11
|
+
# @example Checking if wizard is available
|
|
12
|
+
# if Wizard.available?
|
|
13
|
+
# wizard = Wizard.new
|
|
14
|
+
# config = wizard.run
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# @example Using custom prompt (for testing)
|
|
18
|
+
# wizard = Wizard.new(prompt: mock_prompt)
|
|
19
|
+
# config = wizard.run
|
|
20
|
+
#
|
|
21
|
+
class Wizard
|
|
22
|
+
# Checks if the wizard can run (stdin is a TTY).
|
|
23
|
+
#
|
|
24
|
+
# @return [Boolean] true if stdin is a TTY
|
|
25
|
+
def self.available?
|
|
26
|
+
$stdin.tty?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Creates a new Wizard instance.
|
|
30
|
+
#
|
|
31
|
+
# @param prompt [Object, nil] prompt object for user input (default: built-in)
|
|
32
|
+
def initialize(prompt: nil)
|
|
33
|
+
@prompt = prompt || create_default_prompt
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Runs the interactive wizard and returns configuration.
|
|
37
|
+
#
|
|
38
|
+
# @return [Hash] configuration hash ready for YAML serialization
|
|
39
|
+
def run
|
|
40
|
+
server = prompt_server
|
|
41
|
+
verify_ssl = prompt_ssl
|
|
42
|
+
auth_type = prompt_auth_type
|
|
43
|
+
credentials = prompt_credentials(auth_type)
|
|
44
|
+
context_name = prompt_context_name
|
|
45
|
+
|
|
46
|
+
build_config(
|
|
47
|
+
server: server,
|
|
48
|
+
verify_ssl: verify_ssl,
|
|
49
|
+
auth_type: auth_type,
|
|
50
|
+
credentials: credentials,
|
|
51
|
+
context_name: context_name
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
attr_reader :prompt
|
|
58
|
+
|
|
59
|
+
# Creates a default prompt using TTY::Prompt if available.
|
|
60
|
+
#
|
|
61
|
+
# @return [Object] prompt object
|
|
62
|
+
def create_default_prompt
|
|
63
|
+
# Try to load TTY::Prompt if available
|
|
64
|
+
begin
|
|
65
|
+
require "tty-prompt"
|
|
66
|
+
TTY::Prompt.new
|
|
67
|
+
rescue LoadError
|
|
68
|
+
# Fallback to simple prompt
|
|
69
|
+
SimplePrompt.new
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Prompts for the Proxmox server URL.
|
|
74
|
+
#
|
|
75
|
+
# @return [String] server URL
|
|
76
|
+
def prompt_server
|
|
77
|
+
prompt.ask("Proxmox server URL (e.g., https://pve.example.com:8006):")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Prompts for SSL verification preference.
|
|
81
|
+
#
|
|
82
|
+
# @return [Boolean] true if SSL should be verified
|
|
83
|
+
def prompt_ssl
|
|
84
|
+
prompt.yes?("Verify SSL certificate?")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Prompts for authentication type selection.
|
|
88
|
+
#
|
|
89
|
+
# @return [Symbol] :token or :password
|
|
90
|
+
def prompt_auth_type
|
|
91
|
+
prompt.select("Authentication method:", [
|
|
92
|
+
{ name: "API Token (recommended)", value: :token },
|
|
93
|
+
{ name: "Username/Password", value: :password }
|
|
94
|
+
])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Prompts for authentication credentials.
|
|
98
|
+
#
|
|
99
|
+
# @param auth_type [Symbol] :token or :password
|
|
100
|
+
# @return [Hash] credentials hash
|
|
101
|
+
def prompt_credentials(auth_type)
|
|
102
|
+
if auth_type == :token
|
|
103
|
+
{
|
|
104
|
+
token_id: prompt.ask("Token ID (e.g., root@pam!tokenid):"),
|
|
105
|
+
token_secret: prompt.mask("Token Secret:")
|
|
106
|
+
}
|
|
107
|
+
else
|
|
108
|
+
{
|
|
109
|
+
username: prompt.ask("Username (e.g., root@pam):"),
|
|
110
|
+
password: prompt.mask("Password:")
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Prompts for context name.
|
|
116
|
+
#
|
|
117
|
+
# @return [String] context name
|
|
118
|
+
def prompt_context_name
|
|
119
|
+
prompt.ask("Context name:", default: "default")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Builds the configuration hash from collected data.
|
|
123
|
+
#
|
|
124
|
+
# @param server [String] server URL
|
|
125
|
+
# @param verify_ssl [Boolean] SSL verification
|
|
126
|
+
# @param auth_type [Symbol] authentication type
|
|
127
|
+
# @param credentials [Hash] authentication credentials
|
|
128
|
+
# @param context_name [String] context name
|
|
129
|
+
# @return [Hash] configuration hash
|
|
130
|
+
def build_config(server:, verify_ssl:, auth_type:, credentials:, context_name:)
|
|
131
|
+
cluster_name = context_name
|
|
132
|
+
user_name = "#{context_name}-user"
|
|
133
|
+
|
|
134
|
+
{
|
|
135
|
+
"apiVersion" => "pvectl/v1",
|
|
136
|
+
"kind" => "Config",
|
|
137
|
+
"clusters" => [
|
|
138
|
+
{
|
|
139
|
+
"name" => cluster_name,
|
|
140
|
+
"cluster" => {
|
|
141
|
+
"server" => server,
|
|
142
|
+
"insecure-skip-tls-verify" => !verify_ssl
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"users" => [
|
|
147
|
+
build_user_config(user_name, auth_type, credentials)
|
|
148
|
+
],
|
|
149
|
+
"contexts" => [
|
|
150
|
+
{
|
|
151
|
+
"name" => context_name,
|
|
152
|
+
"context" => {
|
|
153
|
+
"cluster" => cluster_name,
|
|
154
|
+
"user" => user_name
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
"current-context" => context_name
|
|
159
|
+
}
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Builds user configuration hash.
|
|
163
|
+
#
|
|
164
|
+
# @param name [String] user name
|
|
165
|
+
# @param auth_type [Symbol] :token or :password
|
|
166
|
+
# @param credentials [Hash] credentials
|
|
167
|
+
# @return [Hash] user configuration
|
|
168
|
+
def build_user_config(name, auth_type, credentials)
|
|
169
|
+
user_data = if auth_type == :token
|
|
170
|
+
{
|
|
171
|
+
"token-id" => credentials[:token_id],
|
|
172
|
+
"token-secret" => credentials[:token_secret]
|
|
173
|
+
}
|
|
174
|
+
else
|
|
175
|
+
{
|
|
176
|
+
"username" => credentials[:username],
|
|
177
|
+
"password" => credentials[:password]
|
|
178
|
+
}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
{
|
|
182
|
+
"name" => name,
|
|
183
|
+
"user" => user_data
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Validates server URL format.
|
|
188
|
+
#
|
|
189
|
+
# @param url [String] URL to validate
|
|
190
|
+
# @return [Boolean] true if valid
|
|
191
|
+
def valid_server_url?(url)
|
|
192
|
+
return false if url.nil? || url.empty?
|
|
193
|
+
|
|
194
|
+
uri = URI.parse(url)
|
|
195
|
+
uri.scheme == "https" && !uri.host.nil?
|
|
196
|
+
rescue URI::InvalidURIError
|
|
197
|
+
false
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Validates token ID format.
|
|
201
|
+
#
|
|
202
|
+
# @param token_id [String] token ID to validate
|
|
203
|
+
# @return [Boolean] true if valid (contains @ and !)
|
|
204
|
+
def valid_token_id?(token_id)
|
|
205
|
+
return false if token_id.nil? || token_id.empty?
|
|
206
|
+
|
|
207
|
+
token_id.include?("@") && token_id.include?("!")
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Simple fallback prompt when TTY::Prompt is not available.
|
|
212
|
+
#
|
|
213
|
+
# Provides basic input methods without fancy formatting.
|
|
214
|
+
#
|
|
215
|
+
class SimplePrompt
|
|
216
|
+
# Asks a question and returns the answer.
|
|
217
|
+
#
|
|
218
|
+
# @param question [String] question to ask
|
|
219
|
+
# @param default [Object, nil] default value
|
|
220
|
+
# @param required [Boolean] whether a non-empty answer is required
|
|
221
|
+
# @param convert [Symbol, nil] type conversion (+:int+, +:float+, +:bool+)
|
|
222
|
+
# @return [Object] user input (converted if requested)
|
|
223
|
+
def ask(question, default: nil, required: false, convert: nil, **)
|
|
224
|
+
loop do
|
|
225
|
+
print "#{question} "
|
|
226
|
+
print "[#{default}] " if default
|
|
227
|
+
input = $stdin.gets&.chomp
|
|
228
|
+
value = input.nil? || input.empty? ? default : input
|
|
229
|
+
|
|
230
|
+
if required && (value.nil? || value.to_s.empty?)
|
|
231
|
+
puts "Value is required."
|
|
232
|
+
next
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
return convert_value(value, convert)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Asks a yes/no question.
|
|
240
|
+
#
|
|
241
|
+
# @param question [String] question to ask
|
|
242
|
+
# @return [Boolean] true for yes
|
|
243
|
+
def yes?(question, **)
|
|
244
|
+
print "#{question} (y/n) "
|
|
245
|
+
input = $stdin.gets&.chomp&.downcase
|
|
246
|
+
%w[y yes].include?(input)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Prompts for selection from choices.
|
|
250
|
+
#
|
|
251
|
+
# @param question [String] question to ask
|
|
252
|
+
# @param choices [Array] list of choices
|
|
253
|
+
# @return [Object] selected value
|
|
254
|
+
def select(question, choices, **)
|
|
255
|
+
puts question
|
|
256
|
+
choices.each_with_index do |choice, index|
|
|
257
|
+
name = choice.is_a?(Hash) ? choice[:name] : choice
|
|
258
|
+
puts " #{index + 1}. #{name}"
|
|
259
|
+
end
|
|
260
|
+
print "Enter number: "
|
|
261
|
+
input = $stdin.gets&.chomp&.to_i || 1
|
|
262
|
+
choice = choices[input - 1] || choices.first
|
|
263
|
+
choice.is_a?(Hash) ? choice[:value] : choice
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Asks for masked input (password).
|
|
267
|
+
#
|
|
268
|
+
# @param question [String] question to ask
|
|
269
|
+
# @return [String] user input
|
|
270
|
+
def mask(question, **)
|
|
271
|
+
print "#{question} "
|
|
272
|
+
begin
|
|
273
|
+
$stdin.noecho { $stdin.gets&.chomp }
|
|
274
|
+
rescue NoMethodError
|
|
275
|
+
# Fallback if noecho not available
|
|
276
|
+
$stdin.gets&.chomp
|
|
277
|
+
ensure
|
|
278
|
+
puts
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def ok(_message); end
|
|
283
|
+
|
|
284
|
+
def warn(_message); end
|
|
285
|
+
|
|
286
|
+
def error(_message); end
|
|
287
|
+
|
|
288
|
+
private
|
|
289
|
+
|
|
290
|
+
# Converts a string value to the requested type.
|
|
291
|
+
#
|
|
292
|
+
# @param value [Object] raw value
|
|
293
|
+
# @param type [Symbol, nil] target type (+:int+, +:float+, +:bool+)
|
|
294
|
+
# @return [Object] converted value
|
|
295
|
+
def convert_value(value, type)
|
|
296
|
+
return value if type.nil? || value.nil?
|
|
297
|
+
|
|
298
|
+
case type
|
|
299
|
+
when :int, :integer then value.to_s.empty? ? value : Integer(value)
|
|
300
|
+
when :float then value.to_s.empty? ? value : Float(value)
|
|
301
|
+
when :bool, :boolean
|
|
302
|
+
%w[y yes true 1].include?(value.to_s.downcase)
|
|
303
|
+
else
|
|
304
|
+
value
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|