mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-23 16:58:27 +01:00
remote install
This commit is contained in:
parent
d143ca2820
commit
a60680f855
@ -94,6 +94,7 @@ func init() {
|
||||
registerCmdFn("remote:disconnect", RemoteDisconnectCommand)
|
||||
registerCmdFn("remote:connect", RemoteConnectCommand)
|
||||
registerCmdFn("remote:install", RemoteInstallCommand)
|
||||
registerCmdFn("remote:installcancel", RemoteInstallCancelCommand)
|
||||
|
||||
registerCmdFn("window:resize", WindowResizeCommand)
|
||||
|
||||
@ -109,7 +110,7 @@ func getValidCommands() []string {
|
||||
if val.IsAlias {
|
||||
continue
|
||||
}
|
||||
rtn = append(rtn, key)
|
||||
rtn = append(rtn, "/"+key)
|
||||
}
|
||||
return rtn
|
||||
}
|
||||
@ -416,7 +417,33 @@ func UnSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore
|
||||
}
|
||||
|
||||
func RemoteInstallCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
return nil, nil
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mshell := ids.Remote.MShell
|
||||
go mshell.RunInstall()
|
||||
return sstore.ModelUpdate{
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoTitle: fmt.Sprintf("show remote [%s] info", ids.Remote.DisplayName),
|
||||
PtyRemoteId: ids.Remote.RemotePtr.RemoteId,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func RemoteInstallCancelCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
ids, err := resolveUiIds(ctx, pk, R_Session|R_Window|R_Remote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mshell := ids.Remote.MShell
|
||||
go mshell.CancelInstall()
|
||||
return sstore.ModelUpdate{
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoTitle: fmt.Sprintf("show remote [%s] info", ids.Remote.DisplayName),
|
||||
PtyRemoteId: ids.Remote.RemotePtr.RemoteId,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func RemoteConnectCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
@ -424,14 +451,13 @@ func RemoteConnectCommand(ctx context.Context, pk *scpacket.FeCommandPacketType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ids.Remote.RState.IsConnected() {
|
||||
return sstore.InfoMsgUpdate("remote %q already connected (no action taken)", ids.Remote.DisplayName), nil
|
||||
}
|
||||
if ids.Remote.RState.Status == remote.StatusConnecting {
|
||||
return sstore.InfoMsgUpdate("remote %q is already trying to connect (no action taken)", ids.Remote.DisplayName), nil
|
||||
}
|
||||
go ids.Remote.MShell.Launch()
|
||||
return sstore.InfoMsgUpdate("remote %q reconnecting", ids.Remote.DisplayName), nil
|
||||
return sstore.ModelUpdate{
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoTitle: fmt.Sprintf("show remote [%s] info", ids.Remote.DisplayName),
|
||||
PtyRemoteId: ids.Remote.RemotePtr.RemoteId,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func RemoteDisconnectCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
@ -440,16 +466,13 @@ func RemoteDisconnectCommand(ctx context.Context, pk *scpacket.FeCommandPacketTy
|
||||
return nil, err
|
||||
}
|
||||
force := resolveBool(pk.Kwargs["force"], false)
|
||||
status := ids.Remote.MShell.GetStatus()
|
||||
if status != remote.StatusConnected && status != remote.StatusConnecting {
|
||||
return sstore.InfoMsgUpdate("remote %q already disconnected (no action taken)", ids.Remote.DisplayName), nil
|
||||
}
|
||||
numCommands := ids.Remote.MShell.GetNumRunningCommands()
|
||||
if numCommands > 0 && !force {
|
||||
return nil, fmt.Errorf("remote not disconnected, %q has %d running commands. use 'force=1' to force disconnection", ids.Remote.DisplayName)
|
||||
}
|
||||
ids.Remote.MShell.Disconnect()
|
||||
return sstore.InfoMsgUpdate("remote %q disconnected", ids.Remote.DisplayName), nil
|
||||
go ids.Remote.MShell.Disconnect(force)
|
||||
return sstore.ModelUpdate{
|
||||
Info: &sstore.InfoMsgType{
|
||||
InfoTitle: fmt.Sprintf("show remote [%s] info", ids.Remote.DisplayName),
|
||||
PtyRemoteId: ids.Remote.RemotePtr.RemoteId,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func RemoteNewCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (sstore.UpdatePacket, error) {
|
||||
|
@ -54,7 +54,6 @@ func MakeServerCommandStr() string {
|
||||
}
|
||||
|
||||
const (
|
||||
StatusInit = "init"
|
||||
StatusConnected = "connected"
|
||||
StatusConnecting = "connecting"
|
||||
StatusDisconnected = "disconnected"
|
||||
@ -94,7 +93,7 @@ type MShellProc struct {
|
||||
InstallCancelFn context.CancelFunc
|
||||
InstallErr error
|
||||
|
||||
RunningCmds []base.CommandKey
|
||||
RunningCmds map[base.CommandKey]bool
|
||||
}
|
||||
|
||||
type RemoteRuntimeState struct {
|
||||
@ -106,6 +105,9 @@ type RemoteRuntimeState struct {
|
||||
RemoteVars map[string]string `json:"remotevars"`
|
||||
Status string `json:"status"`
|
||||
ErrorStr string `json:"errorstr,omitempty"`
|
||||
InstallStatus string `json:"installstatus"`
|
||||
InstallErrorStr string `json:"installerrorstr,omitempty"`
|
||||
NeedsMShellUpgrade bool `json:"needsmshellupgrade,omitempty"`
|
||||
DefaultState *sstore.RemoteState `json:"defaultstate"`
|
||||
ConnectMode string `json:"connectmode"`
|
||||
AutoInstall bool `json:"autoinstall"`
|
||||
@ -380,10 +382,15 @@ func (msh *MShellProc) GetRemoteRuntimeState() RemoteRuntimeState {
|
||||
Archived: msh.Remote.Archived,
|
||||
RemoteIdx: msh.Remote.RemoteIdx,
|
||||
UName: msh.UName,
|
||||
InstallStatus: msh.InstallStatus,
|
||||
NeedsMShellUpgrade: msh.NeedsMShellUpgrade,
|
||||
}
|
||||
if msh.Err != nil {
|
||||
state.ErrorStr = msh.Err.Error()
|
||||
}
|
||||
if msh.InstallErr != nil {
|
||||
state.InstallErrorStr = msh.InstallErr.Error()
|
||||
}
|
||||
local := (msh.Remote.SSHOpts == nil || msh.Remote.SSHOpts.Local)
|
||||
vars := make(map[string]string)
|
||||
vars["user"] = msh.Remote.RemoteUser
|
||||
@ -473,8 +480,10 @@ func MakeMShell(r *sstore.RemoteType) *MShellProc {
|
||||
rtn := &MShellProc{
|
||||
Lock: &sync.Mutex{},
|
||||
Remote: r,
|
||||
Status: StatusInit,
|
||||
Status: StatusDisconnected,
|
||||
PtyBuffer: buf,
|
||||
InstallStatus: StatusDisconnected,
|
||||
RunningCmds: make(map[base.CommandKey]bool),
|
||||
}
|
||||
rtn.WriteToPtyBuffer("console for remote [%s]\n", r.GetName())
|
||||
return rtn
|
||||
@ -544,6 +553,7 @@ func (msh *MShellProc) setErrorStatus(err error) {
|
||||
}
|
||||
|
||||
func (msh *MShellProc) setInstallErrorStatus(err error) {
|
||||
msh.WriteToPtyBuffer("*error, %s\n", err.Error())
|
||||
msh.Lock.Lock()
|
||||
defer msh.Lock.Unlock()
|
||||
msh.InstallStatus = StatusError
|
||||
@ -569,7 +579,17 @@ func (msh *MShellProc) GetNumRunningCommands() int {
|
||||
return len(msh.RunningCmds)
|
||||
}
|
||||
|
||||
func (msh *MShellProc) Disconnect() {
|
||||
func (msh *MShellProc) Disconnect(force bool) {
|
||||
status := msh.GetStatus()
|
||||
if status != StatusConnected && status != StatusConnecting {
|
||||
msh.WriteToPtyBuffer("remote already disconnected (no action taken)\n")
|
||||
return
|
||||
}
|
||||
numCommands := msh.GetNumRunningCommands()
|
||||
if numCommands > 0 && !force {
|
||||
msh.WriteToPtyBuffer("remote not disconnected, has %d running commands. use force=1 to force disconnection\n", numCommands)
|
||||
return
|
||||
}
|
||||
msh.Lock.Lock()
|
||||
defer msh.Lock.Unlock()
|
||||
if msh.ServerProc != nil {
|
||||
@ -581,6 +601,15 @@ func (msh *MShellProc) Disconnect() {
|
||||
}
|
||||
}
|
||||
|
||||
func (msh *MShellProc) CancelInstall() {
|
||||
msh.Lock.Lock()
|
||||
defer msh.Lock.Unlock()
|
||||
if msh.InstallCancelFn != nil {
|
||||
msh.InstallCancelFn()
|
||||
msh.InstallCancelFn = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (msh *MShellProc) GetRemoteName() string {
|
||||
msh.Lock.Lock()
|
||||
defer msh.Lock.Unlock()
|
||||
@ -652,12 +681,17 @@ func (msh *MShellProc) RunPtyReadLoop(cmdPty *os.File) {
|
||||
func (msh *MShellProc) RunInstall() {
|
||||
remoteCopy := msh.GetRemoteCopy()
|
||||
if remoteCopy.Archived {
|
||||
msh.WriteToPtyBuffer("cannot install on archived remote\n")
|
||||
msh.WriteToPtyBuffer("*error: cannot install on archived remote\n")
|
||||
return
|
||||
}
|
||||
baseStatus := msh.GetStatus()
|
||||
if baseStatus == StatusConnecting || baseStatus == StatusConnected {
|
||||
msh.WriteToPtyBuffer("*error: cannot install on remote that is connected/connecting, disconnect to install\n")
|
||||
return
|
||||
}
|
||||
curStatus := msh.GetInstallStatus()
|
||||
if curStatus == StatusConnecting {
|
||||
msh.WriteToPtyBuffer("cannot install on remote that is already trying to install, cancel current install to try again")
|
||||
msh.WriteToPtyBuffer("*error: cannot install on remote that is already trying to install, cancel current install to try again\n")
|
||||
return
|
||||
}
|
||||
msh.WriteToPtyBuffer("installing mshell %s to %s...\n", MShellVersion, remoteCopy.RemoteCanonicalName)
|
||||
@ -668,7 +702,6 @@ func (msh *MShellProc) RunInstall() {
|
||||
cmdPty, err := msh.addControllingTty(ecmd)
|
||||
if err != nil {
|
||||
statusErr := fmt.Errorf("cannot attach controlling tty to mshell install command: %w", err)
|
||||
msh.WriteToPtyBuffer("*error, %s\n", statusErr.Error())
|
||||
msh.setInstallErrorStatus(statusErr)
|
||||
return
|
||||
}
|
||||
@ -676,11 +709,13 @@ func (msh *MShellProc) RunInstall() {
|
||||
if len(ecmd.ExtraFiles) > 0 {
|
||||
ecmd.ExtraFiles[len(ecmd.ExtraFiles)-1].Close()
|
||||
}
|
||||
cmdPty.Close()
|
||||
}()
|
||||
go msh.RunPtyReadLoop(cmdPty)
|
||||
clientCtx, clientCancelFn := context.WithCancel(context.Background())
|
||||
defer clientCancelFn()
|
||||
msh.WithLock(func() {
|
||||
msh.InstallErr = nil
|
||||
msh.InstallStatus = StatusConnecting
|
||||
msh.InstallCancelFn = clientCancelFn
|
||||
go msh.NotifyRemoteUpdate()
|
||||
@ -689,13 +724,26 @@ func (msh *MShellProc) RunInstall() {
|
||||
msh.WriteToPtyBuffer("%s", msg)
|
||||
}
|
||||
err = shexec.RunInstallFromCmd(clientCtx, ecmd, true, "", msgFn)
|
||||
if err == context.Canceled {
|
||||
msh.WriteToPtyBuffer("*install canceled\n")
|
||||
msh.WithLock(func() {
|
||||
msh.InstallStatus = StatusDisconnected
|
||||
go msh.NotifyRemoteUpdate()
|
||||
})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
statusErr := fmt.Errorf("install failed: %w", err)
|
||||
msh.WriteToPtyBuffer("*error, %s\n", statusErr.Error())
|
||||
msh.setInstallErrorStatus(statusErr)
|
||||
return
|
||||
}
|
||||
msh.WithLock(func() {
|
||||
msh.InstallStatus = StatusDisconnected
|
||||
msh.InstallCancelFn = nil
|
||||
msh.NeedsMShellUpgrade = false
|
||||
})
|
||||
msh.WriteToPtyBuffer("successfully installed mshell %s\n", MShellVersion)
|
||||
go msh.NotifyRemoteUpdate()
|
||||
return
|
||||
}
|
||||
|
||||
@ -706,10 +754,19 @@ func (msh *MShellProc) Launch() {
|
||||
return
|
||||
}
|
||||
curStatus := msh.GetStatus()
|
||||
if curStatus == StatusConnected {
|
||||
msh.WriteToPtyBuffer("remote is already connected (no action taken)\n")
|
||||
return
|
||||
}
|
||||
if curStatus == StatusConnecting {
|
||||
msh.WriteToPtyBuffer("remote is already connecting, disconnect before trying to connect again\n")
|
||||
return
|
||||
}
|
||||
istatus := msh.GetInstallStatus()
|
||||
if istatus == StatusConnecting {
|
||||
msh.WriteToPtyBuffer("remote is trying to install, cancel install before trying to connect again\n")
|
||||
return
|
||||
}
|
||||
msh.WriteToPtyBuffer("connecting to %s...\n", remoteCopy.RemoteCanonicalName)
|
||||
sshOpts := convertSSHOpts(remoteCopy.SSHOpts)
|
||||
sshOpts.SSHErrorsToTty = true
|
||||
@ -731,6 +788,7 @@ func (msh *MShellProc) Launch() {
|
||||
makeClientCtx, makeClientCancelFn := context.WithCancel(context.Background())
|
||||
defer makeClientCancelFn()
|
||||
msh.WithLock(func() {
|
||||
msh.Err = nil
|
||||
msh.Status = StatusConnecting
|
||||
msh.MakeClientCancelFn = makeClientCancelFn
|
||||
go msh.NotifyRemoteUpdate()
|
||||
@ -750,7 +808,12 @@ func (msh *MShellProc) Launch() {
|
||||
// no notify here, because we'll call notify in either case below
|
||||
})
|
||||
if err == context.Canceled {
|
||||
err = fmt.Errorf("forced disconnection")
|
||||
msh.WriteToPtyBuffer("*forced disconnection\n")
|
||||
msh.WithLock(func() {
|
||||
msh.Status = StatusDisconnected
|
||||
go msh.NotifyRemoteUpdate()
|
||||
})
|
||||
return
|
||||
}
|
||||
if err == nil && semver.MajorMinor(mshellVersion) != semver.MajorMinor(MShellVersion) {
|
||||
err = fmt.Errorf("mshell version is not compatible current=%s remote=%s", MShellVersion, mshellVersion)
|
||||
@ -826,7 +889,7 @@ func (state RemoteRuntimeState) ExpandHomeDir(pathStr string) (string, error) {
|
||||
func (msh *MShellProc) IsCmdRunning(ck base.CommandKey) bool {
|
||||
msh.Lock.Lock()
|
||||
defer msh.Lock.Unlock()
|
||||
for _, runningCk := range msh.RunningCmds {
|
||||
for runningCk, _ := range msh.RunningCmds {
|
||||
if runningCk == ck {
|
||||
return true
|
||||
}
|
||||
@ -921,7 +984,13 @@ func RunCommand(ctx context.Context, cmdId string, remotePtr sstore.RemotePtrTyp
|
||||
func (msh *MShellProc) AddRunningCmd(ck base.CommandKey) {
|
||||
msh.Lock.Lock()
|
||||
defer msh.Lock.Unlock()
|
||||
msh.RunningCmds = append(msh.RunningCmds, ck)
|
||||
msh.RunningCmds[ck] = true
|
||||
}
|
||||
|
||||
func (msh *MShellProc) RemoveRunningCmd(ck base.CommandKey) {
|
||||
msh.Lock.Lock()
|
||||
defer msh.Lock.Unlock()
|
||||
delete(msh.RunningCmds, ck)
|
||||
}
|
||||
|
||||
func (msh *MShellProc) PacketRpc(ctx context.Context, pk packet.RpcPacketType) (*packet.ResponsePacketType, error) {
|
||||
@ -966,7 +1035,7 @@ func makeDataAckPacket(ck base.CommandKey, fdNum int, ackLen int, err error) *pa
|
||||
}
|
||||
|
||||
func (msh *MShellProc) notifyHangups_nolock() {
|
||||
for _, ck := range msh.RunningCmds {
|
||||
for ck, _ := range msh.RunningCmds {
|
||||
cmd, err := sstore.GetCmdById(context.Background(), ck.GetSessionId(), ck.GetCmdId())
|
||||
if err != nil {
|
||||
continue
|
||||
@ -974,10 +1043,11 @@ func (msh *MShellProc) notifyHangups_nolock() {
|
||||
update := sstore.ModelUpdate{Cmd: cmd}
|
||||
sstore.MainBus.SendUpdate(ck.GetSessionId(), update)
|
||||
}
|
||||
msh.RunningCmds = nil
|
||||
msh.RunningCmds = make(map[base.CommandKey]bool)
|
||||
}
|
||||
|
||||
func (msh *MShellProc) handleCmdDonePacket(donePk *packet.CmdDonePacketType) {
|
||||
msh.RemoveRunningCmd(donePk.CK)
|
||||
update, err := sstore.UpdateCmdDonePk(context.Background(), donePk)
|
||||
if err != nil {
|
||||
msh.WriteToPtyBuffer("[error] updating cmddone: %v\n", err)
|
||||
|
Loading…
Reference in New Issue
Block a user