Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var WebshCmd = &cobra.Command{ Use: "websh [flags] [USER@]SERVER [COMMAND]", Short: "Open a websh terminal or execute a command on a server", Long: `Open a websh terminal for interacting with a server or execute a command directly on the server. Supports SSH-like user@host syntax for specifying the username inline. For executing commands, it is highly recommended to wrap the entire command string in quotes to ensure it is interpreted correctly on the remote server.`, Example: ` # Open a websh terminal alpacon websh my-server # Open as root using SSH-like syntax alpacon websh root@my-server # Open with specific user and group alpacon websh admin@my-server alpacon websh -u admin -g developers my-server # Execute a command on a server alpacon websh my-server "ls -la /var/log" alpacon websh root@my-server "systemctl status nginx" # Set environment variables alpacon websh --env="KEY1=VALUE1" --env="KEY2=VALUE2" my-server "echo $KEY1" # Share terminal session alpacon websh --share my-server alpacon websh --share --read-only=true my-server # Join an existing shared session alpacon websh join --url https://myws.us1.alpacon.io/websh/shared/abcd1234?channel=default --password my-session-pass # Session management alpacon websh ls # List active sessions alpacon websh describe SESSION_ID # Show session details alpacon websh watch SESSION_ID # Watch a session (read-only, staff/superuser only) alpacon websh invite SESSION_ID --email user@example.com alpacon websh close SESSION_ID # Close a session alpacon websh force-close SESSION_ID # Force close (admin only) Flags: -u, --username [USER_NAME] Specify the username for command execution. -g, --groupname [GROUP_NAME] Specify the group name for command execution. --env="KEY=VALUE" Set environment variable 'KEY' to 'VALUE'. --env="KEY" Use the current shell's value for 'KEY'. -s, --share Share the terminal via a temporary link. --read-only=[true|false] Set shared session to read-only (default: false). Note: All flags must be placed before the server name. Everything after the server name is treated as the remote command.`, DisableFlagParsing: true, Run: func(cmd *cobra.Command, args []string) { var ( username, groupname, serverName string commandArgs []string share, readOnly bool ) env := make(map[string]string) for i := 0; i < len(args); i++ { switch { case args[i] == "-s" || args[i] == "--share": share = true case args[i] == "-h" || args[i] == "--help": _ = cmd.Help() return case strings.HasPrefix(args[i], "-u") || strings.HasPrefix(args[i], "--username"): username, i = extractValue(args, i) case strings.HasPrefix(args[i], "-g") || strings.HasPrefix(args[i], "--groupname"): groupname, i = extractValue(args, i) case strings.HasPrefix(args[i], "--env"): i = extractEnvValue(args, i, env) case strings.HasPrefix(args[i], "--read-only"): var value string value, i = extractValue(args, i) if value == "" || strings.TrimSpace(strings.ToLower(value)) == "true" { readOnly = true } else if strings.TrimSpace(strings.ToLower(value)) == "false" { readOnly = false } else { utils.CliErrorWithExit("The 'read only' value must be either 'true' or 'false'.") } default: if serverName == "" { serverName = args[i] } else { commandArgs = append(commandArgs, args[i:]...) i = len(args) } } } if serverName == "" { utils.CliErrorWithExit("Server name is required.") } if share && len(commandArgs) > 0 { utils.CliErrorWithExit("The --share flag cannot be used with remote commands. Use --share for interactive sessions only.") } if strings.Contains(serverName, "@") && !strings.Contains(serverName, ":") { sshTarget := utils.ParseSSHTarget(serverName) if username == "" && sshTarget.User != "" { username = sshTarget.User } serverName = sshTarget.Host } alpaconClient, err := client.NewAlpaconAPIClient() if err != nil { utils.CliErrorWithExit("Connection to Alpacon API failed: %s. Consider re-logging.", err) } if len(commandArgs) > 0 { if len(commandArgs) > 1 { utils.CliWarning("Command without quotes may cause unexpected behavior. Consider wrapping the command in quotes.") if !utils.CommandConfirm() { return } } command := strings.Join(commandArgs, " ") result, err := execCmd.RunCommandWithRetry(alpaconClient, serverName, command, username, groupname, env) if err != nil { utils.CliErrorWithExit("%s", err) } fmt.Println(result) } else { session, err := websh.CreateWebshSession(alpaconClient, serverName, username, groupname, share, readOnly) if err != nil { err = utils.HandleCommonErrors(err, serverName, utils.ErrorHandlerCallbacks{ OnMFARequired: func(srv string) error { return mfa.HandleMFAError(alpaconClient, srv) }, OnUsernameRequired: func() error { _, err := iam.HandleUsernameRequired() return err }, CheckMFACompleted: func() (bool, error) { return mfa.CheckMFACompletion(alpaconClient) }, RefreshToken: alpaconClient.RefreshToken, RetryOperation: func() error { session, err = websh.CreateWebshSession(alpaconClient, serverName, username, groupname, share, readOnly) return err }, }) if err != nil { utils.CliErrorWithExit("Failed to create websh session for '%s' server: %s.", serverName, err) } } listenerDone := make(chan *event.SudoListener, 1) go func() { listenerDone <- setupSudoListener(alpaconClient, session.ID, serverName) }() defer func() { select { case sl := <-listenerDone: if sl != nil { sl.Stop() } case <-time.After(3 * time.Second): } }() _ = websh.OpenNewTerminal(alpaconClient, session) } }, }
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.