Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Dockerfile.download
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This Dockerfile is used to cross-build the kubectl-oadp binaries for all platforms
# It also builds a Go server that serves the binaries for download

FROM golang:1.24 AS builder

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .

# Build everything, create tarballs, and clean up in one layer to reduce size
RUN make release-build && \
CGO_ENABLED=0 go build -o download-server ./cmd/downloads/server.go && \
mkdir -p /archives && \
for binary in kubectl-oadp-*; do \
archive_name=$(echo "$binary" | sed 's/\.exe$//' ).tar.gz; \
tar -czf "/archives/$archive_name" "$binary"; \
echo "Created /archives/$archive_name"; \
done && \
go clean -cache -modcache -testcache && \
rm -rf /root/.cache/go-build && \
rm -rf /go/pkg

FROM registry.access.redhat.com/ubi8/ubi-minimal:latest
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FROM registry.access.redhat.com/ubi8/ubi-minimal:latest
FROM registry.access.redhat.com/ubi9/ubi-minimal:latest


# Only copy compressed tarballs (much smaller than raw binaries)
COPY --from=builder /archives /archives

# Copy the download server
COPY --from=builder /app/download-server /usr/local/bin/download-server

EXPOSE 8080

CMD ["/usr/local/bin/download-server"]
88 changes: 88 additions & 0 deletions cmd/downloads/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"strings"
)

const (
archiveDir = "/archives"
port = "8080"
)

func main() {
// Verify archives exist
files, err := filepath.Glob(filepath.Join(archiveDir, "*.tar.gz"))
if err != nil || len(files) == 0 {
log.Fatal("No archives found in ", archiveDir)
}
log.Printf("Found %d archives", len(files))

http.HandleFunc("/", listBinaries)
http.HandleFunc("/download/", downloadBinary)

log.Printf("Starting server on port %s", port)
log.Printf("Serving archives from %s", archiveDir)

if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}

func listBinaries(w http.ResponseWriter, r *http.Request) {
files, err := filepath.Glob(filepath.Join(archiveDir, "*.tar.gz"))
if err != nil {
http.Error(w, "Error listing archives", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "text/html")
fmt.Fprintf(w, "<html><head><title>kubectl-oadp Downloads</title></head><body>")
fmt.Fprintf(w, "<h1>kubectl-oadp Binary Downloads</h1>")
fmt.Fprintf(w, "<p>Download pre-built binaries for your platform:</p><ul>")

for _, file := range files {
name := filepath.Base(file)
info, err := os.Stat(file)
if err != nil {
continue
}
size := float64(info.Size()) / (1024 * 1024) // MB
fmt.Fprintf(w, `<li><a href="/download/%s">%s</a> (%.2f MB)</li>`, name, name, size)
}

fmt.Fprintf(w, "</ul>")
fmt.Fprintf(w, "<h3>Installation:</h3>")
fmt.Fprintf(w, "<pre>tar -xzf kubectl-oadp-&lt;platform&gt;.tar.gz\n")
fmt.Fprintf(w, "chmod +x kubectl-oadp\n")
fmt.Fprintf(w, "sudo mv kubectl-oadp /usr/local/bin/</pre>")
fmt.Fprintf(w, "</body></html>")
}

func downloadBinary(w http.ResponseWriter, r *http.Request) {
filename := filepath.Base(r.URL.Path[len("/download/"):])

// Security: ensure filename is just the archive name
if filepath.Dir(filename) != "." || !strings.HasSuffix(filename, ".tar.gz") {
http.Error(w, "Invalid filename", http.StatusBadRequest)
return
}

filePath := filepath.Join(archiveDir, filename)

// Verify file exists
if _, err := os.Stat(filePath); os.IsNotExist(err) {
http.Error(w, "Archive not found", http.StatusNotFound)
return
}

w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
w.Header().Set("Content-Type", "application/gzip")

http.ServeFile(w, r, filePath)
log.Printf("Downloaded: %s from %s", filename, r.RemoteAddr)
}
Loading