|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "log" |
| 6 | + "net/http" |
| 7 | + "os" |
| 8 | + "path/filepath" |
| 9 | + "strings" |
| 10 | +) |
| 11 | + |
| 12 | +const ( |
| 13 | + archiveDir = "/archives" |
| 14 | + port = "8080" |
| 15 | +) |
| 16 | + |
| 17 | +func main() { |
| 18 | + // Verify archives exist |
| 19 | + files, err := filepath.Glob(filepath.Join(archiveDir, "*.tar.gz")) |
| 20 | + if err != nil || len(files) == 0 { |
| 21 | + log.Fatal("No archives found in ", archiveDir) |
| 22 | + } |
| 23 | + log.Printf("Found %d archives", len(files)) |
| 24 | + |
| 25 | + http.HandleFunc("/", listBinaries) |
| 26 | + http.HandleFunc("/download/", downloadBinary) |
| 27 | + |
| 28 | + log.Printf("Starting server on port %s", port) |
| 29 | + log.Printf("Serving archives from %s", archiveDir) |
| 30 | + |
| 31 | + if err := http.ListenAndServe(":"+port, nil); err != nil { |
| 32 | + log.Fatal(err) |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +func listBinaries(w http.ResponseWriter, r *http.Request) { |
| 37 | + files, err := filepath.Glob(filepath.Join(archiveDir, "*.tar.gz")) |
| 38 | + if err != nil { |
| 39 | + http.Error(w, "Error listing archives", http.StatusInternalServerError) |
| 40 | + return |
| 41 | + } |
| 42 | + |
| 43 | + w.Header().Set("Content-Type", "text/html") |
| 44 | + fmt.Fprintf(w, "<html><head><title>kubectl-oadp Downloads</title></head><body>") |
| 45 | + fmt.Fprintf(w, "<h1>kubectl-oadp Binary Downloads</h1>") |
| 46 | + fmt.Fprintf(w, "<p>Download pre-built binaries for your platform:</p><ul>") |
| 47 | + |
| 48 | + for _, file := range files { |
| 49 | + name := filepath.Base(file) |
| 50 | + info, err := os.Stat(file) |
| 51 | + if err != nil { |
| 52 | + continue |
| 53 | + } |
| 54 | + size := float64(info.Size()) / (1024 * 1024) // MB |
| 55 | + fmt.Fprintf(w, `<li><a href="/download/%s">%s</a> (%.2f MB)</li>`, name, name, size) |
| 56 | + } |
| 57 | + |
| 58 | + fmt.Fprintf(w, "</ul>") |
| 59 | + fmt.Fprintf(w, "<h3>Installation:</h3>") |
| 60 | + fmt.Fprintf(w, "<pre>tar -xzf kubectl-oadp-<platform>.tar.gz\n") |
| 61 | + fmt.Fprintf(w, "chmod +x kubectl-oadp\n") |
| 62 | + fmt.Fprintf(w, "sudo mv kubectl-oadp /usr/local/bin/</pre>") |
| 63 | + fmt.Fprintf(w, "</body></html>") |
| 64 | +} |
| 65 | + |
| 66 | +func downloadBinary(w http.ResponseWriter, r *http.Request) { |
| 67 | + filename := filepath.Base(r.URL.Path[len("/download/"):]) |
| 68 | + |
| 69 | + // Security: ensure filename is just the archive name |
| 70 | + if filepath.Dir(filename) != "." || !strings.HasSuffix(filename, ".tar.gz") { |
| 71 | + http.Error(w, "Invalid filename", http.StatusBadRequest) |
| 72 | + return |
| 73 | + } |
| 74 | + |
| 75 | + filePath := filepath.Join(archiveDir, filename) |
| 76 | + |
| 77 | + // Verify file exists |
| 78 | + if _, err := os.Stat(filePath); os.IsNotExist(err) { |
| 79 | + http.Error(w, "Archive not found", http.StatusNotFound) |
| 80 | + return |
| 81 | + } |
| 82 | + |
| 83 | + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename)) |
| 84 | + w.Header().Set("Content-Type", "application/gzip") |
| 85 | + |
| 86 | + http.ServeFile(w, r, filePath) |
| 87 | + log.Printf("Downloaded: %s from %s", filename, r.RemoteAddr) |
| 88 | +} |
0 commit comments