mirror of
https://github.com/netbirdio/netbird.git
synced 2025-08-09 23:27:58 +02:00
[client] Feature/upload bundle (#3734)
Add an upload bundle option with the flag --upload-bundle; by default, the upload will use a NetBird address, which can be replaced using the flag --upload-bundle-url. The upload server is available under the /upload-server path. The release change will push a docker image to netbirdio/upload image repository. The server supports using s3 with pre-signed URL for direct upload and local file for storing bundles.
This commit is contained in:
109
upload-server/server/server.go
Normal file
109
upload-server/server/server.go
Normal file
@ -0,0 +1,109 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/upload-server/types"
|
||||
)
|
||||
|
||||
const (
|
||||
putURLPath = "/upload"
|
||||
bucketVar = "BUCKET"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
srv *http.Server
|
||||
}
|
||||
|
||||
func NewServer() *Server {
|
||||
address := os.Getenv("SERVER_ADDRESS")
|
||||
if address == "" {
|
||||
log.Infof("SERVER_ADDRESS environment variable was not set, using 0.0.0.0:8080")
|
||||
address = "0.0.0.0:8080"
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
err := configureMux(mux)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to configure server: %v", err)
|
||||
}
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
})
|
||||
|
||||
return &Server{
|
||||
srv: &http.Server{Addr: address, Handler: mux},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
log.Infof("Starting upload server on %s", s.srv.Addr)
|
||||
return s.srv.ListenAndServe()
|
||||
}
|
||||
|
||||
func (s *Server) Stop() error {
|
||||
if s.srv != nil {
|
||||
log.Infof("Stopping upload server on %s", s.srv.Addr)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
return s.srv.Shutdown(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func configureMux(mux *http.ServeMux) error {
|
||||
_, ok := os.LookupEnv(bucketVar)
|
||||
if ok {
|
||||
return configureS3Handlers(mux)
|
||||
} else {
|
||||
return configureLocalHandlers(mux)
|
||||
}
|
||||
}
|
||||
|
||||
func getObjectKey(w http.ResponseWriter, r *http.Request) string {
|
||||
id := r.URL.Query().Get("id")
|
||||
if id == "" {
|
||||
http.Error(w, "id query param required", http.StatusBadRequest)
|
||||
return ""
|
||||
}
|
||||
|
||||
return id + "/" + uuid.New().String()
|
||||
}
|
||||
|
||||
func isValidRequest(w http.ResponseWriter, r *http.Request) bool {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return false
|
||||
}
|
||||
|
||||
if r.Header.Get(types.ClientHeader) != types.ClientHeaderValue {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
func respondGetRequest(w http.ResponseWriter, uploadURL string, objectKey string) {
|
||||
response := types.GetURLResponse{
|
||||
URL: uploadURL,
|
||||
Key: objectKey,
|
||||
}
|
||||
|
||||
rdata, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
http.Error(w, "failed to marshal response", http.StatusInternalServerError)
|
||||
log.Errorf("Marshal error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err = w.Write(rdata)
|
||||
if err != nil {
|
||||
log.Errorf("Write error: %v", err)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user