From daee2df389d761aaf0e6a6815210ec471f294a99 Mon Sep 17 00:00:00 2001 From: Michael Freeman Date: Mon, 24 Feb 2025 11:35:30 -0600 Subject: [PATCH] server updates for ko build stuff --- .github/workflows/container-build.yml | 70 +++++++++++++++++++++++++++ .github/workflows/release.yml | 55 ++++++++++++++++++++- Makefile | 58 ++++++++++++++++++++++ pkg/cloud/api/server.go | 51 +++++++++++-------- pkg/cloud/api/web/non-container.go | 11 +++++ 5 files changed, 224 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/container-build.yml create mode 100644 pkg/cloud/api/web/non-container.go diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml new file mode 100644 index 0000000..d057eca --- /dev/null +++ b/.github/workflows/container-build.yml @@ -0,0 +1,70 @@ +# .github/workflows/container-build.yml +name: Build and Push Containers +on: + push: + branches: + - main + paths-ignore: + - '*.md' + - 'docs/**' + - '.github/**' + - '!.github/workflows/container-build.yml' + +permissions: + contents: read + packages: write + +jobs: + build-containers: + runs-on: ubuntu-latest + env: + VERSION: latest + KO_DOCKER_REPO: ghcr.io/carverauto/serviceradar + steps: + - uses: actions/checkout@v4 + - name: Extract short SHA + id: vars + run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.24' + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: 'web/package-lock.json' + - name: Setup ko + uses: ko-build/setup-ko@v0.6 + - name: Build web UI + run: ./scripts/build-web.sh + - name: Move web artifacts + run: | + mkdir -p pkg/cloud/api/web/ + cp -r web/dist pkg/cloud/api/web/ + mkdir -p cmd/cloud/.kodata + cp -r web/dist cmd/cloud/.kodata/web + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push container images + run: | + # Set up ko repository + export KO_DOCKER_REPO=ghcr.io/carverauto/serviceradar + + # Build and push container images for all components + GOFLAGS="-tags=containers" ko build \ + --platform=linux/amd64,linux/arm64 \ + --base-import-paths \ + --tags=sha-${{ steps.vars.outputs.sha_short }},latest \ + --bare \ + --image-refs=image-refs.txt \ + ./cmd/agent \ + ./cmd/poller \ + ./cmd/cloud \ + ./cmd/checkers/dusk \ + ./cmd/checkers/snmp \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 30e99b5..2e8199d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,8 +5,9 @@ on: types: [created] permissions: contents: write + packages: write jobs: - build: + build-packages: runs-on: ubuntu-latest env: VERSION: ${{ github.ref_name }} @@ -35,3 +36,55 @@ jobs: files: ./release-artifacts/*.deb env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build-containers: + runs-on: ubuntu-latest + needs: build-packages + env: + VERSION: ${{ github.ref_name }} + KO_DOCKER_REPO: ghcr.io/carverauto/serviceradar + steps: + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.24' + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: 'web/package-lock.json' + - name: Setup ko + uses: ko-build/setup-ko@v0.6 + - name: Build web UI + run: ./scripts/build-web.sh + - name: Move web artifacts + run: | + mkdir -p pkg/cloud/api/web/ + cp -r web/dist pkg/cloud/api/web/ + mkdir -p cmd/cloud/.kodata + cp -r web/dist cmd/cloud/.kodata/web + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build and push container images + run: | + # Set up ko repository + export KO_DOCKER_REPO=ghcr.io/carverauto/serviceradar + + # Build and push container images for all components + GOFLAGS="-tags=containers" ko build \ + --platform=linux/amd64,linux/arm64 \ + --base-import-paths \ + --tags=${VERSION},latest \ + --bare \ + --image-refs=image-refs.txt \ + ./cmd/agent \ + ./cmd/poller \ + ./cmd/cloud \ + ./cmd/checkers/dusk \ + ./cmd/checkers/snmp \ No newline at end of file diff --git a/Makefile b/Makefile index 8cfc83b..82dd1d0 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,11 @@ GOLANGCI_LINT_VERSION ?= v1.64.5 VERSION ?= $(shell git describe --tags --always) NEXT_VERSION ?= $(shell git describe --tags --abbrev=0 | awk -F. '{$$NF = $$NF + 1;} 1' | sed 's/ /./g') +# Container configuration +REGISTRY ?= ghcr.io/carverauto/serviceradar +KO_DOCKER_REPO ?= $(REGISTRY) +PLATFORMS ?= linux/amd64,linux/arm64 + # Colors for pretty printing COLOR_RESET = \033[0m COLOR_BOLD = \033[1m @@ -75,6 +80,59 @@ version: ## Show current and next version clean: ## Clean up build artifacts @echo "$(COLOR_BOLD)Cleaning up build artifacts$(COLOR_RESET)" @rm -f cover.*.profile cover.html + @rm -rf bin/ + +.PHONY: build +build: ## Build all binaries + @echo "$(COLOR_BOLD)Building all binaries$(COLOR_RESET)" + @$(GO) build -ldflags "-X main.version=$(VERSION)" -o bin/serviceradar-agent cmd/agent/main.go + @$(GO) build -ldflags "-X main.version=$(VERSION)" -o bin/serviceradar-poller cmd/poller/main.go + @$(GO) build -ldflags "-X main.version=$(VERSION)" -o bin/serviceradar-dusk-checker cmd/checkers/dusk/main.go + @$(GO) build -ldflags "-X main.version=$(VERSION)" -o bin/serviceradar-cloud cmd/cloud/main.go + @$(GO) build -ldflags "-X main.version=$(VERSION)" -o bin/serviceradar-snmp-checker cmd/checkers/snmp/main.go + +.PHONY: build-web +build-web: ## Build web UI + @echo "$(COLOR_BOLD)Building web UI$(COLOR_RESET)" + @./scripts/build-web.sh + @mkdir -p pkg/cloud/api/web/ + @cp -r web/dist pkg/cloud/api/web/ + +.PHONY: kodata-prep +kodata-prep: build-web ## Prepare kodata directories + @echo "$(COLOR_BOLD)Preparing kodata directories$(COLOR_RESET)" + @mkdir -p cmd/cloud/.kodata + @cp -r pkg/cloud/api/web/dist cmd/cloud/.kodata/web + +.PHONY: container-build +container-build: kodata-prep ## Build container images with ko + @echo "$(COLOR_BOLD)Building container images with ko$(COLOR_RESET)" + @GOFLAGS="-tags=containers" KO_DOCKER_REPO=$(KO_DOCKER_REPO) ko build \ + --platform=$(PLATFORMS) \ + --base-import-paths \ + --tags=$(VERSION) \ + --bare \ + --image-refs=image-refs.txt \ + ./cmd/agent \ + ./cmd/poller \ + ./cmd/cloud \ + ./cmd/checkers/dusk \ + ./cmd/checkers/snmp + +.PHONY: container-push +container-push: kodata-prep ## Build and push container images with ko + @echo "$(COLOR_BOLD)Building and pushing container images with ko$(COLOR_RESET)" + @GOFLAGS="-tags=containers" KO_DOCKER_REPO=$(KO_DOCKER_REPO) ko build \ + --platform=$(PLATFORMS) \ + --base-import-paths \ + --tags=$(VERSION),latest \ + --bare \ + --image-refs=image-refs.txt \ + ./cmd/agent \ + ./cmd/poller \ + ./cmd/cloud \ + ./cmd/checkers/dusk \ + ./cmd/checkers/snmp # Docusaurus commands .PHONY: docs-start diff --git a/pkg/cloud/api/server.go b/pkg/cloud/api/server.go index 1c3c3bc..f26a041 100644 --- a/pkg/cloud/api/server.go +++ b/pkg/cloud/api/server.go @@ -3,16 +3,18 @@ package api import ( - "embed" "encoding/json" - "io/fs" "log" "net/http" + "os" + "path/filepath" + "strings" "sync" "time" "github.com/gorilla/mux" "github.com/mfreeman451/serviceradar/pkg/checker/snmp" + "github.com/mfreeman451/serviceradar/pkg/cloud/api/web" "github.com/mfreeman451/serviceradar/pkg/db" srHttp "github.com/mfreeman451/serviceradar/pkg/http" "github.com/mfreeman451/serviceradar/pkg/metrics" @@ -99,19 +101,6 @@ func WithDB(db db.Service) func(server *APIServer) { } } -func (s *APIServer) setupStaticFileServing() { - fsys, err := fs.Sub(webContent, "web/dist") - if err != nil { - log.Printf("Error setting up static file serving: %v", err) - return - } - - s.router.PathPrefix("/").Handler(http.FileServer(http.FS(fsys))) -} - -//go:embed web/dist/* -var webContent embed.FS - func (s *APIServer) setupRoutes() { // Add CORS middleware s.router.Use(srHttp.CommonMiddleware) @@ -134,8 +123,24 @@ func (s *APIServer) setupRoutes() { // SNMP endpoints s.router.HandleFunc("/api/nodes/{id}/snmp", s.getSNMPData).Methods("GET") - // Serve static files - s.setupStaticFileServing() + // Configure static file serving + staticFilesPath := web.GetStaticFilesPath() + fileServer := http.FileServer(http.Dir(staticFilesPath)) + + s.router.PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check if file exists + path := filepath.Join(staticFilesPath, r.URL.Path) + _, err := os.Stat(path) + + // If file doesn't exist or is a directory (and not root), serve index.html + if os.IsNotExist(err) || (r.URL.Path != "/" && strings.HasSuffix(r.URL.Path, "/")) { + http.ServeFile(w, r, filepath.Join(staticFilesPath, "index.html")) + return + } + + // Otherwise serve the requested file + fileServer.ServeHTTP(w, r) + }) } // getSNMPData retrieves SNMP data for a specific node. @@ -408,13 +413,19 @@ func (s *APIServer) getServiceDetails(w http.ResponseWriter, r *http.Request) { http.Error(w, "Service not found", http.StatusNotFound) } +const ( + defaultReadTimeout = 10 * time.Second + defaultWriteTimeout = 10 * time.Second + defaultIdleTimeout = 60 * time.Second +) + func (s *APIServer) Start(addr string) error { srv := &http.Server{ Addr: addr, Handler: s.router, - ReadTimeout: 10 * time.Second, // Timeout for reading the entire request, including the body. - WriteTimeout: 10 * time.Second, // Timeout for writing the response. - IdleTimeout: 60 * time.Second, // Timeout for idle connections waiting in the Keep-Alive state. + ReadTimeout: defaultReadTimeout, // Timeout for reading the entire request, including the body. + WriteTimeout: defaultWriteTimeout, // Timeout for writing the response. + IdleTimeout: defaultIdleTimeout, // Timeout for idle connections waiting in the Keep-Alive state. // Optional: You can also set ReadHeaderTimeout to limit the time for reading request headers // ReadHeaderTimeout: 5 * time.Second, } diff --git a/pkg/cloud/api/web/non-container.go b/pkg/cloud/api/web/non-container.go new file mode 100644 index 0000000..74e1f6a --- /dev/null +++ b/pkg/cloud/api/web/non-container.go @@ -0,0 +1,11 @@ +//go:build !containers +// +build !containers + +// Package web pkg/cloud/api/web/noncontainer.go +package web + +// GetStaticFilesPath returns the path to static files in non-container mode. +func GetStaticFilesPath() string { + // Default path for deb package installation + return "/usr/local/share/serviceradar-cloud/web/dist" +}