mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
wsh connreinstall (#317)
This commit is contained in:
parent
fa69406550
commit
afd83f0f6f
38
cmd/wsh/cmd/wshcmd-connreinstall.go
Normal file
38
cmd/wsh/cmd/wshcmd-connreinstall.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/remote"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/wshrpc/wshclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
var connReinstallCmd = &cobra.Command{
|
||||||
|
Use: "connreinstall",
|
||||||
|
Short: "reinstall wsh on a connection",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Run: connReinstallRun,
|
||||||
|
PreRunE: preRunSetupRpcClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(connReinstallCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func connReinstallRun(cmd *cobra.Command, args []string) {
|
||||||
|
connName := args[0]
|
||||||
|
_, err := remote.ParseOpts(connName)
|
||||||
|
if err != nil {
|
||||||
|
WriteStderr("[error] cannot parse connection name: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = wshclient.ConnReinstallWshCommand(RpcClient, connName, &wshrpc.RpcOpts{Timeout: 60000})
|
||||||
|
if err != nil {
|
||||||
|
WriteStderr("[error] getting metadata: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
WriteStdout("wsh reinstalled on connection %q\n", connName)
|
||||||
|
}
|
@ -17,6 +17,26 @@ class WshServerType {
|
|||||||
return WOS.wshServerRpcHelper_call("authenticate", data, opts);
|
return WOS.wshServerRpcHelper_call("authenticate", data, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// command "conndisconnect" [call]
|
||||||
|
ConnDisconnectCommand(data: string, opts?: RpcOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("conndisconnect", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "connensure" [call]
|
||||||
|
ConnEnsureCommand(data: string, opts?: RpcOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("connensure", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "connforceconnect" [call]
|
||||||
|
ConnForceConnectCommand(data: string, opts?: RpcOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("connforceconnect", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "connreinstallwsh" [call]
|
||||||
|
ConnReinstallWshCommand(data: string, opts?: RpcOpts): Promise<void> {
|
||||||
|
return WOS.wshServerRpcHelper_call("connreinstallwsh", data, opts);
|
||||||
|
}
|
||||||
|
|
||||||
// command "controllerinput" [call]
|
// command "controllerinput" [call]
|
||||||
ControllerInputCommand(data: CommandBlockInputData, opts?: RpcOpts): Promise<void> {
|
ControllerInputCommand(data: CommandBlockInputData, opts?: RpcOpts): Promise<void> {
|
||||||
return WOS.wshServerRpcHelper_call("controllerinput", data, opts);
|
return WOS.wshServerRpcHelper_call("controllerinput", data, opts);
|
||||||
|
1
frontend/types/gotypes.d.ts
vendored
1
frontend/types/gotypes.d.ts
vendored
@ -154,6 +154,7 @@ declare global {
|
|||||||
status: string;
|
status: string;
|
||||||
connection: string;
|
connection: string;
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
|
hasconnected: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ type SSHConn struct {
|
|||||||
ConnController *ssh.Session
|
ConnController *ssh.Session
|
||||||
Error string
|
Error string
|
||||||
HasWaiter *atomic.Bool
|
HasWaiter *atomic.Bool
|
||||||
|
LastConnectTime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAllConnStatus() []wshrpc.ConnStatus {
|
func GetAllConnStatus() []wshrpc.ConnStatus {
|
||||||
@ -70,10 +71,11 @@ func (conn *SSHConn) DeriveConnStatus() wshrpc.ConnStatus {
|
|||||||
conn.Lock.Lock()
|
conn.Lock.Lock()
|
||||||
defer conn.Lock.Unlock()
|
defer conn.Lock.Unlock()
|
||||||
return wshrpc.ConnStatus{
|
return wshrpc.ConnStatus{
|
||||||
Status: conn.Status,
|
Status: conn.Status,
|
||||||
Connected: conn.Status == Status_Connected,
|
Connected: conn.Status == Status_Connected,
|
||||||
Connection: conn.Opts.String(),
|
Connection: conn.Opts.String(),
|
||||||
Error: conn.Error,
|
HasConnected: (conn.LastConnectTime > 0),
|
||||||
|
Error: conn.Error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +245,15 @@ func (conn *SSHConn) StartConnServer() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *SSHConn) checkAndInstallWsh(ctx context.Context, clientDisplayName string) error {
|
type WshInstallOpts struct {
|
||||||
|
Force bool
|
||||||
|
NoUserPrompt bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *SSHConn) CheckAndInstallWsh(ctx context.Context, clientDisplayName string, opts *WshInstallOpts) error {
|
||||||
|
if opts == nil {
|
||||||
|
opts = &WshInstallOpts{}
|
||||||
|
}
|
||||||
client := conn.GetClient()
|
client := conn.GetClient()
|
||||||
if client == nil {
|
if client == nil {
|
||||||
return fmt.Errorf("client is nil")
|
return fmt.Errorf("client is nil")
|
||||||
@ -251,12 +261,15 @@ func (conn *SSHConn) checkAndInstallWsh(ctx context.Context, clientDisplayName s
|
|||||||
// check that correct wsh extensions are installed
|
// check that correct wsh extensions are installed
|
||||||
expectedVersion := fmt.Sprintf("wsh v%s", wavebase.WaveVersion)
|
expectedVersion := fmt.Sprintf("wsh v%s", wavebase.WaveVersion)
|
||||||
clientVersion, err := remote.GetWshVersion(client)
|
clientVersion, err := remote.GetWshVersion(client)
|
||||||
if err == nil && clientVersion == expectedVersion {
|
if err == nil && clientVersion == expectedVersion && !opts.Force {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var queryText string
|
var queryText string
|
||||||
var title string
|
var title string
|
||||||
if err != nil {
|
if opts.Force {
|
||||||
|
queryText = fmt.Sprintf("ReInstalling Wave Shell Extensions (%s) on `%s`\n", wavebase.WaveVersion, clientDisplayName)
|
||||||
|
title = "Install Wave Shell Extensions"
|
||||||
|
} else if err != nil {
|
||||||
queryText = fmt.Sprintf("Wave requires Wave Shell Extensions to be \n"+
|
queryText = fmt.Sprintf("Wave requires Wave Shell Extensions to be \n"+
|
||||||
"installed on `%s` \n"+
|
"installed on `%s` \n"+
|
||||||
"to ensure a seamless experience. \n\n"+
|
"to ensure a seamless experience. \n\n"+
|
||||||
@ -269,16 +282,18 @@ func (conn *SSHConn) checkAndInstallWsh(ctx context.Context, clientDisplayName s
|
|||||||
"Would you like to update?", clientDisplayName, clientVersion, expectedVersion)
|
"Would you like to update?", clientDisplayName, clientVersion, expectedVersion)
|
||||||
title = "Update Wave Shell Extensions"
|
title = "Update Wave Shell Extensions"
|
||||||
}
|
}
|
||||||
request := &userinput.UserInputRequest{
|
if !opts.NoUserPrompt {
|
||||||
ResponseType: "confirm",
|
request := &userinput.UserInputRequest{
|
||||||
QueryText: queryText,
|
ResponseType: "confirm",
|
||||||
Title: title,
|
QueryText: queryText,
|
||||||
Markdown: true,
|
Title: title,
|
||||||
CheckBoxMsg: "Don't show me this again",
|
Markdown: true,
|
||||||
}
|
CheckBoxMsg: "Don't show me this again",
|
||||||
response, err := userinput.GetUserInput(ctx, request)
|
}
|
||||||
if err != nil || !response.Confirm {
|
response, err := userinput.GetUserInput(ctx, request)
|
||||||
return err
|
if err != nil || !response.Confirm {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log.Printf("attempting to install wsh to `%s`", clientDisplayName)
|
log.Printf("attempting to install wsh to `%s`", clientDisplayName)
|
||||||
clientOs, err := remote.GetClientOs(client)
|
clientOs, err := remote.GetClientOs(client)
|
||||||
@ -337,6 +352,7 @@ func (conn *SSHConn) Connect(ctx context.Context) error {
|
|||||||
conn.close_nolock()
|
conn.close_nolock()
|
||||||
} else {
|
} else {
|
||||||
conn.Status = Status_Connected
|
conn.Status = Status_Connected
|
||||||
|
conn.LastConnectTime = time.Now().UnixMilli()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
conn.FireConnChangeEvent()
|
conn.FireConnChangeEvent()
|
||||||
@ -363,7 +379,7 @@ func (conn *SSHConn) connectInternal(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
installErr := conn.checkAndInstallWsh(ctx, clientDisplayName)
|
installErr := conn.CheckAndInstallWsh(ctx, clientDisplayName, nil)
|
||||||
if installErr != nil {
|
if installErr != nil {
|
||||||
return fmt.Errorf("conncontroller %s wsh install error: %v", conn.GetName(), installErr)
|
return fmt.Errorf("conncontroller %s wsh install error: %v", conn.GetName(), installErr)
|
||||||
}
|
}
|
||||||
@ -385,14 +401,13 @@ func (conn *SSHConn) waitForDisconnect() {
|
|||||||
}
|
}
|
||||||
err := client.Wait()
|
err := client.Wait()
|
||||||
conn.WithLock(func() {
|
conn.WithLock(func() {
|
||||||
if err != nil {
|
// disconnects happen for a variety of reasons (like network, etc. and are typically transient)
|
||||||
if conn.Status != Status_Disconnected {
|
// so we just set the status to "disconnected" here (not error)
|
||||||
// don't set the error if our status is disconnected (because this error was caused by an explicit close)
|
// don't overwrite any existing error (or error status)
|
||||||
conn.Status = Status_Error
|
if err != nil && conn.Error == "" {
|
||||||
conn.Error = err.Error()
|
conn.Error = err.Error()
|
||||||
}
|
}
|
||||||
} else {
|
if conn.Status != Status_Error {
|
||||||
// not sure if this is possible, because I think Wait() always returns an error (although that's not in the docs)
|
|
||||||
conn.Status = Status_Disconnected
|
conn.Status = Status_Disconnected
|
||||||
}
|
}
|
||||||
conn.close_nolock()
|
conn.close_nolock()
|
||||||
|
@ -24,6 +24,30 @@ func AuthenticateCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) (
|
|||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// command "conndisconnect", wshserver.ConnDisconnectCommand
|
||||||
|
func ConnDisconnectCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||||
|
_, err := sendRpcRequestCallHelper[any](w, "conndisconnect", data, opts)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "connensure", wshserver.ConnEnsureCommand
|
||||||
|
func ConnEnsureCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||||
|
_, err := sendRpcRequestCallHelper[any](w, "connensure", data, opts)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "connforceconnect", wshserver.ConnForceConnectCommand
|
||||||
|
func ConnForceConnectCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||||
|
_, err := sendRpcRequestCallHelper[any](w, "connforceconnect", data, opts)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// command "connreinstallwsh", wshserver.ConnReinstallWshCommand
|
||||||
|
func ConnReinstallWshCommand(w *wshutil.WshRpc, data string, opts *wshrpc.RpcOpts) error {
|
||||||
|
_, err := sendRpcRequestCallHelper[any](w, "connreinstallwsh", data, opts)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// command "controllerinput", wshserver.ControllerInputCommand
|
// command "controllerinput", wshserver.ControllerInputCommand
|
||||||
func ControllerInputCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockInputData, opts *wshrpc.RpcOpts) error {
|
func ControllerInputCommand(w *wshutil.WshRpc, data wshrpc.CommandBlockInputData, opts *wshrpc.RpcOpts) error {
|
||||||
_, err := sendRpcRequestCallHelper[any](w, "controllerinput", data, opts)
|
_, err := sendRpcRequestCallHelper[any](w, "controllerinput", data, opts)
|
||||||
|
@ -63,6 +63,11 @@ const (
|
|||||||
Command_RemoteWriteFile = "remotewritefile"
|
Command_RemoteWriteFile = "remotewritefile"
|
||||||
Command_RemoteFileDelete = "remotefiledelete"
|
Command_RemoteFileDelete = "remotefiledelete"
|
||||||
Command_RemoteFileJoiin = "remotefilejoin"
|
Command_RemoteFileJoiin = "remotefilejoin"
|
||||||
|
|
||||||
|
Command_ConnEnsure = "connensure"
|
||||||
|
Command_ConnReinstallWsh = "connreinstallwsh"
|
||||||
|
Command_ConnForceConnect = "connforceconnect"
|
||||||
|
Command_ConnDisconnect = "conndisconnect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RespOrErrorUnion[T any] struct {
|
type RespOrErrorUnion[T any] struct {
|
||||||
@ -98,6 +103,12 @@ type WshRpcInterface interface {
|
|||||||
TestCommand(ctx context.Context, data string) error
|
TestCommand(ctx context.Context, data string) error
|
||||||
SetConfigCommand(ctx context.Context, data wconfig.MetaSettingsType) error
|
SetConfigCommand(ctx context.Context, data wconfig.MetaSettingsType) error
|
||||||
|
|
||||||
|
// connection functions
|
||||||
|
ConnEnsureCommand(ctx context.Context, connName string) error
|
||||||
|
ConnReinstallWshCommand(ctx context.Context, connName string) error
|
||||||
|
ConnForceConnectCommand(ctx context.Context, connName string) error
|
||||||
|
ConnDisconnectCommand(ctx context.Context, connName string) error
|
||||||
|
|
||||||
// eventrecv is special, it's handled internally by WshRpc with EventListener
|
// eventrecv is special, it's handled internally by WshRpc with EventListener
|
||||||
EventRecvCommand(ctx context.Context, data WaveEvent) error
|
EventRecvCommand(ctx context.Context, data WaveEvent) error
|
||||||
|
|
||||||
@ -344,8 +355,9 @@ type TimeSeriesData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConnStatus struct {
|
type ConnStatus struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Connection string `json:"connection"`
|
Connection string `json:"connection"`
|
||||||
Connected bool `json:"connected"`
|
Connected bool `json:"connected"`
|
||||||
Error string `json:"error,omitempty"`
|
HasConnected bool `json:"hasconnected"` // true if it has *ever* connected successfully
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ import (
|
|||||||
"github.com/wavetermdev/thenextwave/pkg/blockcontroller"
|
"github.com/wavetermdev/thenextwave/pkg/blockcontroller"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/eventbus"
|
"github.com/wavetermdev/thenextwave/pkg/eventbus"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/filestore"
|
"github.com/wavetermdev/thenextwave/pkg/filestore"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/remote"
|
||||||
|
"github.com/wavetermdev/thenextwave/pkg/remote/conncontroller"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/waveai"
|
"github.com/wavetermdev/thenextwave/pkg/waveai"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
"github.com/wavetermdev/thenextwave/pkg/waveobj"
|
||||||
"github.com/wavetermdev/thenextwave/pkg/wconfig"
|
"github.com/wavetermdev/thenextwave/pkg/wconfig"
|
||||||
@ -467,3 +469,27 @@ func (ws *WshServer) SetConfigCommand(ctx context.Context, data wconfig.MetaSett
|
|||||||
log.Printf("SETCONFIG: %v\n", data)
|
log.Printf("SETCONFIG: %v\n", data)
|
||||||
return wconfig.SetBaseConfigValue(data.MetaMapType)
|
return wconfig.SetBaseConfigValue(data.MetaMapType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ws *WshServer) ConnEnsureCommand(ctx context.Context, connName string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *WshServer) ConnDisconnectCommand(ctx context.Context, connName string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *WshServer) ConnForceConnectCommand(ctx context.Context, connName string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *WshServer) ConnReinstallWshCommand(ctx context.Context, connName string) error {
|
||||||
|
connOpts, err := remote.ParseOpts(connName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error parsing connection name: %w", err)
|
||||||
|
}
|
||||||
|
conn := conncontroller.GetConn(ctx, connOpts, false)
|
||||||
|
if conn == nil {
|
||||||
|
return fmt.Errorf("connection not found: %s", connName)
|
||||||
|
}
|
||||||
|
return conn.CheckAndInstallWsh(ctx, connName, &conncontroller.WshInstallOpts{Force: true, NoUserPrompt: true})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user