Skip to content

Commit b05002d

Browse files
committed
Add endpoint that returns the EC binary from the EC data directory
1 parent ed37d64 commit b05002d

File tree

8 files changed

+105
-8
lines changed

8 files changed

+105
-8
lines changed

.github/actions/copy-assets/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.24 as builder
1+
FROM golang:1.24.2 as builder
22
WORKDIR /action
33
COPY . /action
44

dev/dockerfiles/kotsadm/Dockerfile.local

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
FROM golang:1.24-alpine AS dlv-builder
1+
FROM golang:1.24.2-alpine AS dlv-builder
22

33
RUN go install github.com/go-delve/delve/cmd/[email protected]
44

5-
FROM golang:1.24-alpine
5+
FROM golang:1.24.2-alpine
66

77
RUN apk add --no-cache ca-certificates s3cmd curl git make bash
88

dev/dockerfiles/kurl-proxy/Dockerfile.local

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.24-alpine
1+
FROM golang:1.24.2-alpine
22

33
RUN apk add --no-cache ca-certificates curl git make bash
44

dev/scripts/common.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function populate() {
2727
-e GOCACHE=/replicatedhq/kots/dev/.gocache \
2828
-e GOMODCACHE=/replicatedhq/kots/dev/.gomodcache \
2929
-w /replicatedhq/kots \
30-
golang:1.24-alpine \
30+
golang:1.24.2-alpine \
3131
/bin/sh -c "apk add make bash git && make kots build"
3232
;;
3333
"kotsadm-web")
@@ -44,7 +44,7 @@ function populate() {
4444
-e GOCACHE=/replicatedhq/kots/dev/.gocache \
4545
-e GOMODCACHE=/replicatedhq/kots/dev/.gomodcache \
4646
-w /replicatedhq/kots/kurl_proxy \
47-
golang:1.24-alpine \
47+
golang:1.24.2-alpine \
4848
/bin/sh -c "apk add make bash git && make build"
4949
;;
5050
esac

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/replicatedhq/kots
22

3-
go 1.24.1
3+
go 1.24.2
44

55
require (
66
cloud.google.com/go/storage v1.45.0

kurl_proxy/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/replicatedhq/kots/kurl_proxy
22

3-
go 1.24.0
3+
go 1.24.2
44

55
require (
66
github.com/gin-gonic/gin v1.10.0
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package handlers
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
"os"
8+
"path/filepath"
9+
10+
"github.com/pkg/errors"
11+
"github.com/replicatedhq/kots/pkg/embeddedcluster"
12+
"github.com/replicatedhq/kots/pkg/logger"
13+
"github.com/replicatedhq/kots/pkg/util"
14+
)
15+
16+
// GetEmbeddedClusterBinary returns the embedded cluster binary as a .tgz file
17+
// This endpoint is unauthenticated to allow node joining without credentials
18+
func (h *Handler) GetEmbeddedClusterBinary(w http.ResponseWriter, r *http.Request) {
19+
if !util.IsEmbeddedCluster() {
20+
logger.Error(errors.New("not an embedded cluster"))
21+
w.WriteHeader(http.StatusBadRequest)
22+
return
23+
}
24+
25+
// Get kubeclient
26+
kbClient, err := h.GetKubeClient(r.Context())
27+
if err != nil {
28+
logger.Error(errors.Wrap(err, "failed to get kubeclient"))
29+
w.WriteHeader(http.StatusInternalServerError)
30+
return
31+
}
32+
33+
// Get current installation
34+
installation, err := embeddedcluster.GetCurrentInstallation(r.Context(), kbClient)
35+
if err != nil {
36+
logger.Error(errors.Wrap(err, "failed to get current installation"))
37+
w.WriteHeader(http.StatusInternalServerError)
38+
return
39+
}
40+
41+
// Get data directory path from runtime config
42+
dataDir := ""
43+
if installation.Spec.RuntimeConfig != nil {
44+
dataDir = installation.Spec.RuntimeConfig.DataDir
45+
}
46+
if dataDir == "" {
47+
logger.Error(errors.New("data directory not found in runtime config"))
48+
w.WriteHeader(http.StatusInternalServerError)
49+
return
50+
}
51+
52+
// Get binary name from installation
53+
binaryName := installation.Spec.BinaryName
54+
if binaryName == "" {
55+
logger.Error(errors.New("binary name not found in installation"))
56+
w.WriteHeader(http.StatusInternalServerError)
57+
return
58+
}
59+
60+
// Path to EC binary
61+
binaryPath := filepath.Join(dataDir, "bin", binaryName)
62+
63+
// Check if binary exists
64+
binaryStat, err := os.Stat(binaryPath)
65+
if os.IsNotExist(err) {
66+
logger.Error(errors.Wrap(err, "binary file not found"))
67+
w.WriteHeader(http.StatusNotFound)
68+
return
69+
} else if err != nil {
70+
logger.Error(errors.Wrap(err, "failed to stat binary file"))
71+
w.WriteHeader(http.StatusInternalServerError)
72+
return
73+
}
74+
75+
// Set response headers for binary file
76+
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", binaryName))
77+
w.Header().Set("Content-Type", "application/octet-stream")
78+
w.Header().Set("Content-Length", fmt.Sprintf("%d", binaryStat.Size()))
79+
80+
// Open binary file
81+
binaryFile, err := os.Open(binaryPath)
82+
if err != nil {
83+
logger.Error(errors.Wrap(err, "failed to open binary file"))
84+
w.WriteHeader(http.StatusInternalServerError)
85+
return
86+
}
87+
defer binaryFile.Close()
88+
89+
// Stream the binary directly to the response
90+
if _, err := io.Copy(w, binaryFile); err != nil {
91+
logger.Error(errors.Wrap(err, "failed to write binary to response"))
92+
return
93+
}
94+
}

pkg/handlers/handlers.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,9 @@ func RegisterUnauthenticatedRoutes(handler *Handler, kotsStore store.Store, debu
387387

388388
// This handler requires a valid token in the query
389389
loggingRouter.Path("/api/v1/embedded-cluster/join").Methods("GET").HandlerFunc(handler.GetEmbeddedClusterNodeJoinCommand)
390+
391+
// This endpoint returns the embedded cluster binary as a .tgz file
392+
loggingRouter.Path("/api/v1/embedded-cluster/binary").Methods("GET").HandlerFunc(handler.GetEmbeddedClusterBinary)
390393
}
391394

392395
func StreamJSON(c *gwebsocket.Conn, payload interface{}) {

0 commit comments

Comments
 (0)