mirror of
https://github.com/veops/oneterm.git
synced 2025-09-27 03:36:02 +08:00
fix(backend): Fix error logs for normal exits of SSH/database connections
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/creack/pty"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/veops/oneterm/internal/connector/protocols"
|
||||
"github.com/veops/oneterm/internal/model"
|
||||
gsession "github.com/veops/oneterm/internal/session"
|
||||
"github.com/veops/oneterm/internal/tunneling"
|
||||
@@ -55,12 +56,6 @@ func connectDB(sess *gsession.Session, asset *model.Asset, account *model.Accoun
|
||||
return fmt.Errorf("unsupported protocol: %s", sess.Protocol)
|
||||
}
|
||||
|
||||
logger.L().Info("Starting database client",
|
||||
zap.String("command", clientConfig.Command),
|
||||
zap.Strings("args", clientConfig.Args),
|
||||
zap.String("host", ip),
|
||||
zap.Int("port", port))
|
||||
|
||||
// Create command and pseudo-terminal
|
||||
cmd := exec.CommandContext(sess.Gctx, clientConfig.Command, clientConfig.Args...)
|
||||
cmd.Env = append(os.Environ(), "TERM=xterm-256color")
|
||||
@@ -88,7 +83,13 @@ func connectDB(sess *gsession.Session, asset *model.Asset, account *model.Accoun
|
||||
// Monitor process exit
|
||||
sess.G.Go(func() error {
|
||||
err := cmd.Wait()
|
||||
logger.L().Info("Database client process exited", zap.Error(err), zap.String("protocol", protocol))
|
||||
|
||||
// Log process exit - only log as error if there was an actual error
|
||||
if err != nil {
|
||||
logger.L().Error("Database client process exited with error", zap.Error(err), zap.String("protocol", protocol))
|
||||
} else {
|
||||
logger.L().Info("Database client process exited normally", zap.String("protocol", protocol))
|
||||
}
|
||||
|
||||
// Only send termination message if not already sent
|
||||
if atomic.CompareAndSwapInt32(&exitMessageSent, 0, 1) {
|
||||
@@ -98,10 +99,16 @@ func connectDB(sess *gsession.Session, asset *model.Asset, account *model.Accoun
|
||||
}
|
||||
|
||||
sess.Once.Do(func() {
|
||||
logger.L().Info("Closing AwayChan from database client monitor")
|
||||
logger.L().Debug("Closing AwayChan from database client monitor")
|
||||
close(chs.AwayChan)
|
||||
})
|
||||
return fmt.Errorf("database client process terminated: %w", err)
|
||||
|
||||
// Return appropriate error
|
||||
if err != nil {
|
||||
return fmt.Errorf("database client process terminated with error: %w", err)
|
||||
}
|
||||
// Return nil for normal exit - this is not an error condition
|
||||
return nil
|
||||
})
|
||||
|
||||
// Goroutine 1: Process input, detect exit command
|
||||
@@ -213,7 +220,8 @@ func connectDB(sess *gsession.Session, asset *model.Asset, account *model.Accoun
|
||||
case <-sess.Gctx.Done():
|
||||
return nil
|
||||
case <-chs.AwayChan:
|
||||
return fmt.Errorf("away")
|
||||
// Normal termination - return sentinel error
|
||||
return protocols.ErrSessionClosed
|
||||
case window := <-chs.WindowChan:
|
||||
// Adjust terminal size
|
||||
_ = pty.Setsize(ptmx, &pty.Winsize{
|
||||
|
@@ -93,7 +93,8 @@ func ConnectGuacd(ctx *gin.Context, sess *gsession.Session, asset *model.Asset,
|
||||
case <-sess.Gctx.Done():
|
||||
return nil
|
||||
case <-chs.AwayChan:
|
||||
return fmt.Errorf("away")
|
||||
// Normal termination - return sentinel error
|
||||
return ErrSessionClosed
|
||||
case in := <-chs.InChan:
|
||||
t.Write(in)
|
||||
}
|
||||
|
@@ -80,7 +80,12 @@ func ConnectSsh(ctx *gin.Context, sess *gsession.Session, asset *model.Asset, ac
|
||||
|
||||
sess.G.Go(func() error {
|
||||
err = sshSess.Wait()
|
||||
return fmt.Errorf("ssh session wait end %w", err)
|
||||
// Always close AwayChan when SSH session ends
|
||||
sess.Once.Do(func() { close(chs.AwayChan) })
|
||||
if err != nil {
|
||||
return fmt.Errorf("ssh session wait end with error: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
chs.ErrChan <- err
|
||||
@@ -114,7 +119,8 @@ func ConnectSsh(ctx *gin.Context, sess *gsession.Session, asset *model.Asset, ac
|
||||
case <-sess.Gctx.Done():
|
||||
return nil
|
||||
case <-chs.AwayChan:
|
||||
return fmt.Errorf("away")
|
||||
// Normal termination - return sentinel error
|
||||
return ErrSessionClosed
|
||||
case window := <-chs.WindowChan:
|
||||
if err := sshSess.WindowChange(window.Height, window.Width); err != nil {
|
||||
logger.L().Warn("reset window size failed", zap.Error(err))
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package protocols
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -23,6 +24,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrSessionClosed is a sentinel error for normal session termination
|
||||
// This is returned when a session is closed normally (e.g., user exits)
|
||||
ErrSessionClosed = errors.New("session closed normally")
|
||||
|
||||
Upgrader = websocket.Upgrader{
|
||||
HandshakeTimeout: time.Minute,
|
||||
ReadBufferSize: 4096,
|
||||
|
@@ -335,6 +335,10 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
// Let the table handle all navigation keys
|
||||
m.table, cmd = m.table.Update(msg)
|
||||
return m, cmd
|
||||
default:
|
||||
// For any other key messages, let the table handle them
|
||||
m.table, cmd = m.table.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
@@ -358,8 +362,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
newHeight = maxHeight
|
||||
}
|
||||
m.table.SetHeight(newHeight)
|
||||
default:
|
||||
// Update table for other messages
|
||||
// Let table also handle the window size message
|
||||
m.table, cmd = m.table.Update(msg)
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -543,18 +545,32 @@ func (m *view) handleConnectionCommand(cmd string) tea.Cmd {
|
||||
|
||||
// Setup connection parameters
|
||||
pty, _, _ := m.Sess.Pty()
|
||||
m.Ctx.Request.URL.RawQuery = fmt.Sprintf("w=%d&h=%d", pty.Window.Width, pty.Window.Height)
|
||||
m.Ctx.Params = nil
|
||||
m.Ctx.Params = append(m.Ctx.Params, gin.Param{Key: "account_id", Value: cast.ToString(m.combines[cmd][0])})
|
||||
m.Ctx.Params = append(m.Ctx.Params, gin.Param{Key: "asset_id", Value: cast.ToString(m.combines[cmd][1])})
|
||||
m.Ctx.Params = append(m.Ctx.Params, gin.Param{Key: "protocol", Value: fmt.Sprintf("%s:%d", p, m.combines[cmd][2])})
|
||||
m.Ctx = m.Ctx.Copy()
|
||||
m.Ctx.Set("sessionType", model.SESSIONTYPE_CLIENT)
|
||||
|
||||
// Create a copy of the context first to avoid modifying the original
|
||||
newCtx := m.Ctx.Copy()
|
||||
|
||||
// Ensure Request and URL are properly initialized
|
||||
if newCtx.Request == nil {
|
||||
newCtx.Request = &http.Request{
|
||||
RemoteAddr: m.Sess.RemoteAddr().String(),
|
||||
URL: &url.URL{},
|
||||
}
|
||||
}
|
||||
if newCtx.Request.URL == nil {
|
||||
newCtx.Request.URL = &url.URL{}
|
||||
}
|
||||
|
||||
newCtx.Request.URL.RawQuery = fmt.Sprintf("w=%d&h=%d", pty.Window.Width, pty.Window.Height)
|
||||
newCtx.Params = nil
|
||||
newCtx.Params = append(newCtx.Params, gin.Param{Key: "account_id", Value: cast.ToString(m.combines[cmd][0])})
|
||||
newCtx.Params = append(newCtx.Params, gin.Param{Key: "asset_id", Value: cast.ToString(m.combines[cmd][1])})
|
||||
newCtx.Params = append(newCtx.Params, gin.Param{Key: "protocol", Value: fmt.Sprintf("%s:%d", p, m.combines[cmd][2])})
|
||||
newCtx.Set("sessionType", model.SESSIONTYPE_CLIENT)
|
||||
m.connecting = true
|
||||
|
||||
return tea.Sequence(
|
||||
tea.Printf("🔌 Establishing connection to %s...\n", cmd),
|
||||
tea.Exec(&connector{Ctx: m.Ctx, Sess: m.Sess, Vw: m, gctx: m.gctx}, func(err error) tea.Msg {
|
||||
tea.Exec(&connector{Ctx: newCtx, Sess: m.Sess, Vw: m, gctx: m.gctx}, func(err error) tea.Msg {
|
||||
m.connecting = false
|
||||
if err != nil {
|
||||
return errMsg(fmt.Errorf("❌ Connection failed: %v", err))
|
||||
@@ -864,7 +880,12 @@ func (conn *connector) Run() error {
|
||||
myConnector.HandleTerm(gsess, nil)
|
||||
|
||||
if err = gsess.G.Wait(); err != nil {
|
||||
logger.L().Error("sshsrv run stopped", zap.String("sessionId", gsess.SessionId), zap.Error(err))
|
||||
// Check if this is the normal termination sentinel error
|
||||
if err.Error() == "session closed normally" {
|
||||
logger.L().Debug("sshsrv session ended normally", zap.String("sessionId", gsess.SessionId))
|
||||
} else {
|
||||
logger.L().Debug("sshsrv run stopped", zap.String("sessionId", gsess.SessionId), zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
conn.stdout.Write([]byte("\n\n"))
|
||||
|
Reference in New Issue
Block a user