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