From deae4275ff334261aca7e27b759a5bad8684ad3e Mon Sep 17 00:00:00 2001 From: Angel Marin Date: Wed, 17 Dec 2025 11:42:13 +0100 Subject: [PATCH] Make easy 1 command api experience for development --- Makefile | 11 ++++ .../environments/e_embedded_development.go | 53 +++++++++++++++++++ cmd/hyperfleet-api/environments/framework.go | 9 ++-- cmd/hyperfleet-api/environments/types.go | 9 ++-- cmd/hyperfleet-api/servecmd/cmd.go | 13 ++++- docs/development.md | 11 ++++ docs/testcontainers.md | 9 ++++ 7 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 cmd/hyperfleet-api/environments/e_embedded_development.go diff --git a/Makefile b/Makefile index 2cbf533..82b43b3 100755 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ help: @echo "make binary compile binaries" @echo "make install compile binaries and install in GOPATH bin" @echo "make secrets initialize secrets directory with default values" + @echo "make dev run with embedded PostgreSQL (testcontainers), no jwt/authz" @echo "make run run the application" @echo "make run/docs run swagger and host the api spec" @echo "make test run unit tests" @@ -258,6 +259,16 @@ run-no-auth: binary ./hyperfleet-api migrate ./hyperfleet-api serve --enable-authz=false --enable-jwt=false +# Run the API with an embedded PostgreSQL using testcontainers. +# - Starts PostgreSQL (testcontainers) +# - Runs migrations automatically (inside the testcontainer factory) +# - Disables JWT + authz +# Notes: +# - For podman, you may need: TESTCONTAINERS_RYUK_DISABLED=true +dev: binary secrets + TESTCONTAINERS_RYUK_DISABLED=true OCM_ENV=embedded_development ./hyperfleet-api serve +.PHONY: dev + # Run Swagger nd host the api docs run/docs: @echo "Please open http://localhost/" diff --git a/cmd/hyperfleet-api/environments/e_embedded_development.go b/cmd/hyperfleet-api/environments/e_embedded_development.go new file mode 100644 index 0000000..abfc46e --- /dev/null +++ b/cmd/hyperfleet-api/environments/e_embedded_development.go @@ -0,0 +1,53 @@ +package environments + +import ( + "github.com/openshift-hyperfleet/hyperfleet-api/pkg/config" + "github.com/openshift-hyperfleet/hyperfleet-api/pkg/db/db_session" +) + +// embeddedDevelopmentEnvImpl runs the API with an embedded PostgreSQL instance (testcontainers). +// Intended for local/dev usage by dependent projects that want a fully autonomous API. +type embeddedDevelopmentEnvImpl struct { + env *Env +} + +var _ EnvironmentImpl = &embeddedDevelopmentEnvImpl{} + +func (e *embeddedDevelopmentEnvImpl) OverrideDatabase(c *Database) error { + c.SessionFactory = db_session.NewTestcontainerFactory(e.env.Config.Database) + return nil +} + +func (e *embeddedDevelopmentEnvImpl) OverrideConfig(c *config.ApplicationConfig) error { + c.Server.EnableJWT = false + c.Server.EnableAuthz = false + c.Server.EnableHTTPS = false + return nil +} + +func (e *embeddedDevelopmentEnvImpl) OverrideServices(_ *Services) error { + return nil +} + +func (e *embeddedDevelopmentEnvImpl) OverrideHandlers(_ *Handlers) error { + return nil +} + +func (e *embeddedDevelopmentEnvImpl) OverrideClients(_ *Clients) error { + return nil +} + +func (e *embeddedDevelopmentEnvImpl) Flags() map[string]string { + return map[string]string{ + "v": "10", + "logtostderr": "true", + "enable-authz": "false", + "enable-jwt": "false", + "ocm-debug": "false", + "enable-ocm-mock": "true", + "enable-https": "false", + "enable-metrics-https": "false", + "api-server-hostname": "localhost", + "api-server-bindaddress": "localhost:8000", + } +} diff --git a/cmd/hyperfleet-api/environments/framework.go b/cmd/hyperfleet-api/environments/framework.go index deaf8f7..0c71f1c 100755 --- a/cmd/hyperfleet-api/environments/framework.go +++ b/cmd/hyperfleet-api/environments/framework.go @@ -22,10 +22,11 @@ func init() { environment.Name = GetEnvironmentStrFromEnv() environments = map[string]EnvironmentImpl{ - DevelopmentEnv: &devEnvImpl{environment}, - UnitTestingEnv: &unitTestingEnvImpl{environment}, - IntegrationTestingEnv: &integrationTestingEnvImpl{environment}, - ProductionEnv: &productionEnvImpl{environment}, + DevelopmentEnv: &devEnvImpl{environment}, + EmbeddedDevelopmentEnv: &embeddedDevelopmentEnvImpl{environment}, + UnitTestingEnv: &unitTestingEnvImpl{environment}, + IntegrationTestingEnv: &integrationTestingEnvImpl{environment}, + ProductionEnv: &productionEnvImpl{environment}, } }) } diff --git a/cmd/hyperfleet-api/environments/types.go b/cmd/hyperfleet-api/environments/types.go index d1d0c93..60530f1 100755 --- a/cmd/hyperfleet-api/environments/types.go +++ b/cmd/hyperfleet-api/environments/types.go @@ -10,10 +10,11 @@ import ( ) const ( - UnitTestingEnv string = "unit_testing" - IntegrationTestingEnv string = "integration_testing" - DevelopmentEnv string = "development" - ProductionEnv string = "production" + UnitTestingEnv string = "unit_testing" + IntegrationTestingEnv string = "integration_testing" + DevelopmentEnv string = "development" + EmbeddedDevelopmentEnv string = "embedded_development" + ProductionEnv string = "production" EnvironmentStringKey string = "OCM_ENV" EnvironmentDefault = DevelopmentEnv diff --git a/cmd/hyperfleet-api/servecmd/cmd.go b/cmd/hyperfleet-api/servecmd/cmd.go index dce3fd3..2ebaa33 100755 --- a/cmd/hyperfleet-api/servecmd/cmd.go +++ b/cmd/hyperfleet-api/servecmd/cmd.go @@ -1,6 +1,10 @@ package servecmd import ( + "os" + "os/signal" + "syscall" + "github.com/golang/glog" "github.com/spf13/cobra" @@ -48,5 +52,12 @@ func runServe(cmd *cobra.Command, args []string) { // REMOVED: ControllersServer - Sentinel handles orchestration // Controllers are no longer run inside the API service - select {} + // Ensure we cleanup resources (including testcontainers) on shutdown signals. + signals := make(chan os.Signal, 2) + signal.Notify(signals, os.Interrupt, syscall.SIGTERM) + <-signals + + glog.Infof("Shutdown signal received, tearing down environment resources") + environments.Environment().Teardown() + os.Exit(0) } diff --git a/docs/development.md b/docs/development.md index 3e75734..cf11515 100644 --- a/docs/development.md +++ b/docs/development.md @@ -91,6 +91,16 @@ pre-commit run --all-files make run-no-auth ``` +### Local Development (Embedded PostgreSQL via testcontainers) + +If you want a fully autonomous local API (no external database required), run: + +```bash +make dev +``` + +This will start an embedded PostgreSQL (testcontainers), run migrations, and start the API with **JWT + authz disabled**. + The service starts on `localhost:8000`: - REST API: `http://localhost:8000/api/hyperfleet/v1/` - OpenAPI spec: `http://localhost:8000/api/hyperfleet/v1/openapi` @@ -180,6 +190,7 @@ make db/login # Connect to database shell | `make binary` | Build hyperfleet-api executable | | `make test` | Run unit tests | | `make test-integration` | Run integration tests | +| `make dev` | Start server with embedded PostgreSQL (testcontainers), no jwt/authz | | `make run-no-auth` | Start server without authentication | | `make run` | Start server with OCM authentication | | `make db/setup` | Create PostgreSQL container | diff --git a/docs/testcontainers.md b/docs/testcontainers.md index 40c89a1..a1141ea 100755 --- a/docs/testcontainers.md +++ b/docs/testcontainers.md @@ -4,6 +4,15 @@ hyperfleet uses https://github.com/testcontainers/testcontainers-go/ for integra The containers used by the tests are initialized/destroyed in the `integration_testing` environment. +## Embedded PostgreSQL for local development + +The `embedded_development` environment also uses testcontainers to start an embedded PostgreSQL instance at runtime. +You can run it via: + +```bash +make dev +``` + ## Compatibility with podman