From 7e6b4d9272495ec794daa9079a02f8ea00d4d712 Mon Sep 17 00:00:00 2001 From: Erik Brakkee Date: Sun, 21 Jul 2024 22:36:17 +0200 Subject: [PATCH] lots of work to make it actually work. Icluding the server keep alive interval. Fix where expiry duration was added twice. --- cmd/agent/agent.go | 25 +++++++++++++++++------ cmd/converge/server.go | 1 - kubernetes/deployment.yaml | 25 +++++++++++++++++++++++ kubernetes/service.yaml | 13 ++++++++++++ pkg/agent/help.txt | 6 +++++- pkg/agent/session.go | 2 +- static/index.html | 42 ++++++++++++++++++++++---------------- 7 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 kubernetes/deployment.yaml create mode 100644 kubernetes/service.yaml diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go index 6cb5c2d..a02b9a0 100755 --- a/cmd/agent/agent.go +++ b/cmd/agent/agent.go @@ -58,10 +58,10 @@ func setWinsize(f *os.File, w, h int) { uintptr(unsafe.Pointer(&struct{ h, w, x, y uint16 }{uint16(h), uint16(w), 0, 0}))) } -func sshServer(hostKeyFile string) *ssh.Server { +func sshServer(hostKeyFile string, shellCommand string) *ssh.Server { ssh.Handle(func(s ssh.Session) { - // TODO shell should be made configurable - cmd := exec.Command("bash") + + cmd := exec.Command(shellCommand) ptyReq, winCh, isPty := s.Pty() if isPty { workingDirectory, _ := os.Getwd() @@ -154,8 +154,8 @@ func (f ReaderFunc) Read(p []byte) (n int, err error) { func main() { wsURL := os.Args[1] - advanceWarningTime := 10 * time.Minute - agentExpriryTime := 30 * time.Minute + advanceWarningTime := 5 * time.Minute + agentExpriryTime := 10 * time.Minute tickerInterval := 60 * time.Second agent.ConfigureAgent(advanceWarningTime, agentExpriryTime, tickerInterval) @@ -176,8 +176,21 @@ func main() { // Need to create listener implementation that aactually listens for websocket connections. var service AgentService + shells := []string{"bash", "sh", "ash", "ksh", "zsh", "fish", "tcsh", "csh"} + shell := "" + for _, candidate := range shells { + shell, err = exec.LookPath(candidate) + if err == nil { + break + } + } + if shell == "" { + log.Printf("Cannot find a shell in %v", shells) + os.Exit(1) + } + log.Printf("Using shell %s for remote sessions", shell) service = ListenerServer(func() *ssh.Server { - return sshServer("hostkey.pem") + return sshServer("hostkey.pem", shell) }) //service = ConnectionServer(netCatServer) //service = ConnectionServer(echoServer) diff --git a/cmd/converge/server.go b/cmd/converge/server.go index fc34ae7..7dd3cb0 100644 --- a/cmd/converge/server.go +++ b/cmd/converge/server.go @@ -69,7 +69,6 @@ type FilteredFileSystem struct { } func (ffs FilteredFileSystem) Open(name string) (http.File, error) { - log.Println("Name : " + name) f, err := ffs.fs.Open(name) if err != nil { return nil, err diff --git a/kubernetes/deployment.yaml b/kubernetes/deployment.yaml new file mode 100644 index 0000000..aa6d050 --- /dev/null +++ b/kubernetes/deployment.yaml @@ -0,0 +1,25 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: converge + name: converge + namespace: wamblee-org +spec: + replicas: 1 + selector: + matchLabels: + app: converge + template: + metadata: + labels: + app: converge + spec: + containers: + - image: your.repo.com/converge:1.0 + imagePullPolicy: Always + name: converge + ports: + - containerPort: 8000 + + diff --git a/kubernetes/service.yaml b/kubernetes/service.yaml new file mode 100644 index 0000000..c9f09d5 --- /dev/null +++ b/kubernetes/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: converge + name: converge +spec: + ports: + - port: 8000 + protocol: TCP + targetPort: 8000 + selector: + app: converge diff --git a/pkg/agent/help.txt b/pkg/agent/help.txt index 0fed91e..dcb960e 100644 --- a/pkg/agent/help.txt +++ b/pkg/agent/help.txt @@ -1,6 +1,6 @@ Session is set to expire at %v -The session expires automatically after %d time. +The session expires automatically after %v. If there are no more sessions after logging out, the agent terminates. @@ -8,6 +8,10 @@ You can extend this time using touch $agentdir/.hold +The expiry time is equal to the modification time of the .hold +file with the expiry duration added. + To prevent the agent from exiting after the last session is gone, also use the above command in any shell. + diff --git a/pkg/agent/session.go b/pkg/agent/session.go index 2c8016d..f1ac5c0 100644 --- a/pkg/agent/session.go +++ b/pkg/agent/session.go @@ -161,7 +161,7 @@ func (state *AgentState) expiryTime(filename string) time.Time { func check() { now := time.Now() - expiryTime := state.expiryTime(".hold").Add(state.agentExpriryTime) + expiryTime := state.expiryTime(".hold") if now.After(expiryTime) { messageUsers("Expiry time was reached logging out") diff --git a/static/index.html b/static/index.html index 1b178ba..2684c8c 100644 --- a/static/index.html +++ b/static/index.html @@ -17,34 +17,40 @@

About

- Converge is a utility for troubleshooting builds on continuous integration serves. - It solves a common problem where the cause of job failure is difficult to determine. - This is complicated furhter by the fact that build jobs are usually run on a build - farm where there is no access to the build agents or in more modern envrionments when - jobs are run in ephemeral containers. + Converge is a utility for troubleshooting builds on continuous integration serves. + It solves a common problem where the cause of job failure is difficult to determine. + This is complicated further by the fact that build jobs are usually run on a build + farm where there is no access to the build agents or in more modern envrionments when + jobs are run in ephemeral containers.

- With Converge it is possible to get remote shell access to such jobs. This works - by configuring the build job to connect to a Converge server using an agent program. - The agent program can be downloaded from within the CI job using curl or wget. - Next, an end-use can connect to the Converge server, a rendez-vous server, that connects - the client and server together. + With Converge it is possible to get remote shell access to such jobs. This works + by configuring the build job to connect to a Converge server using an agent program. + The agent program can be downloaded from within the CI job using curl or wget. + Next, an end-use can connect to the Converge server, a rendez-vous server, that connects + the client and server together.

- The setup is such that the connection from client (end-user) to server (agent on CI job) - is end-to-end encrypted. The Converge server itself is no more than a bitpipe which pumps - data between client and agent. + The setup is such that the connection from client (end-user) to server (agent on CI job) + is end-to-end encrypted. The Converge server itself is no more than a bitpipe which pumps + data between client and agent.

- Both ssh and sftp are supported. Multiple shells are also allowed. + Both ssh and sftp are supported. Multiple shells are also allowed.

- There is a timeout mechanism in the agent such that jobs do not hang indefinetely waiting - for a connection. + There is a timeout mechanism in the agent such that jobs do not hang indefinitely waiting + for a connection. This mechanism is useful to make sure build agents do not wait + indefinitely for a user session. By default, the agent exits with status 0 when + the first client exits after logging in. This behavior as well as general expiry can be + controlled from within a shell session by touching a .hold file. After logging in, the + user can control expiry of the session as instructed by messages in the ssh session. + Then the timeout of a session is near the user is informed about this with messages + in the shell.

Usage

@@ -75,7 +81,7 @@

This is a command that can be used as a proxy command for SSH which performs the connection to the remote - server.

+ server.

Next step is to run a local SSH of SFTP client: @@ -118,7 +124,7 @@

     ssh -oServerAliveInterval=10 -p 10000 abc@localhost
-    sftp -oServerAliveInterval=10 -oPort 10000 abc@localhost
+    sftp -oServerAliveInterval=10 -oPort=10000 abc@localhost