fix(config): fix configuration management

This commit is contained in:
2025-10-13 16:47:09 +02:00
parent 3d85723de9
commit fac5eb8a66
7 changed files with 113 additions and 58 deletions

View File

@@ -1,7 +1,8 @@
version: '3'
vars:
API_IMAGE_NAME: realz
REGISTRY: reg.cadoles.com/lacanne
API_IMAGE_NAME: realzapi
API_IMAGE_VERSION: v1.0.0
DB_IMAGE_NAME: realzdb
DB_IMAGE_VERSION: v1.0.0
@@ -14,15 +15,25 @@ tasks:
build-api:
desc: Construction de l'image Docker realz API
cmds:
- docker build -t {{.API_IMAGE_NAME}}:{{.API_IMAGE_VERSION}} -t {{.API_IMAGE_NAME}}:latest -f docker/Dockerfile.api .
- docker build -t {{.REGISTRY}}/{{.API_IMAGE_NAME}}:{{.API_IMAGE_VERSION}} -t {{.REGISTRY}}/{{.API_IMAGE_NAME}}:latest -f docker/Dockerfile.api .
silent: true
build-db:
desc: Construction de l'image Docker realz DB
cmds:
- docker build -t {{.DB_IMAGE_NAME}}:{{.DB_IMAGE_VERSION}} -t {{.DB_IMAGE_NAME}}:latest -f docker/Dockerfile.db .
- docker build -t {{.REGISTRY}}/{{.DB_IMAGE_NAME}}:{{.DB_IMAGE_VERSION}} -t {{.REGISTRY}}/{{.DB_IMAGE_NAME}}:latest -f docker/Dockerfile.db .
silent: true
build:
desc: Construction des images Docker realz
deps: [ build-api, build-db ]
publish:
deps: [ build-api, build-db ]
cmds:
- docker login {{.REGISTRY}}
- docker push {{.REGISTRY}}/{{.API_IMAGE_NAME}}:{{.API_IMAGE_VERSION}}
- docker push {{.REGISTRY}}/{{.API_IMAGE_NAME}}:latest
- docker push {{.REGISTRY}}/{{.DB_IMAGE_NAME}}:{{.DB_IMAGE_VERSION}}
- docker push {{.REGISTRY}}/{{.DB_IMAGE_NAME}}:latest
silent: true

View File

@@ -1,7 +1,8 @@
package api
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
@@ -99,11 +100,13 @@ func getCorrectedAltitude(db *database.Service) gin.HandlerFunc {
}
func main() {
cfg, err := config.Load()
cfg, err := config.LoadConfig(".")
if err != nil {
log.Fatalf("Error loading configuration: %v", err)
}
fmt.Printf("Config: %+v\n", cfg)
db, err := database.NewService(&cfg.Database)
if err != nil {
log.Fatalf("Could not initialize database: %v", err)
@@ -113,8 +116,14 @@ func main() {
router := gin.Default()
// Servir les fichiers statiques (index.html, etc.) depuis le répertoire courant.
router.StaticFS("/", http.Dir("."))
// Configure les proxies de confiance pour Gin
if len(cfg.Server.TrustedProxies) > 0 {
router.SetTrustedProxies(cfg.Server.TrustedProxies)
log.Printf("Trusted proxies set to: %v", cfg.Server.TrustedProxies)
}
// Servir les fichiers statiques de l'UI go-app
router.Static("/web", "./ui/web")
// La route est maintenant un POST pour recevoir un corps de requête JSON.
router.POST("/getorthocorrec", getOrthometricCorrection(db))

View File

@@ -1,5 +1,8 @@
server:
address: "0.0.0.0:8088"
trustes_proxies:
- "127.0.0.1"
- "::1"
database:
user: "realz"

View File

@@ -6,8 +6,9 @@ COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build
RUN go build cmd/api/realz.go
FROM scratch
COPY --from=builder /app/realz /realz
COPY --from=builder /app/index.html /index.html
ENTRYPOINT ["/realz"]

View File

@@ -1,17 +1,47 @@
services:
postgis:
image: realz
container_name: postgis_initialized
api:
image: reg.cadoles.com/lacanne/realzapi:latest
env_file: .env
restart: unless-stopped
depends_on:
postgis:
condition: service_healthy
ports:
- "8088:8080" # Expose API port (host:container)
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB} # Base de données pour l'administration, pas celle de l'app
- PGRST_AUTHUSER=${PGRST_AUTHUSER}
- PGRST_PASSWORD=${PGRST_PASSWORD}
APP_SERVER_ADDRESS: 0.0.0.0:8080
APP_DATABASE_HOST: postgis
APP_DATABASE_PORT: 5432
APP_DATABASE_USER: ${POSTGRES_USER}
APP_DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
APP_DATABASE_DBNAME: ${POSTGRES_DB}
APP_DATABASE_SSLMODE: disable
networks:
- realz-net
postgis:
image: reg.cadoles.com/lacanne/realzdb:latest
container_name: postgis_initialized
restart: unless-stopped
env_file: .env
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
ports:
- "5433:5432"
volumes:
- postgis_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- realz-net
volumes:
postgis_data:
networks:
realz-net:

View File

@@ -2,66 +2,67 @@ package config
import (
"fmt"
"log"
"os"
"strings"
"github.com/spf13/viper"
)
// Config holds all configuration for the application.
// Config représente la structure globale de la configuration de l'application.
type Config struct {
Database DatabaseConfig `mapstructure:"database"`
Server ServerConfig `mapstructure:"server"`
Server ServerConfig
Database DatabaseConfig
}
// DatabaseConfig holds database connection configuration.
// ServerConfig contient les paramètres de configuration du serveur HTTP.
type ServerConfig struct {
Address string `mapstructure:"address"`
TrustedProxies []string `mapstructure:"trusted_proxies"` // Liste des IPs de proxies de confiance
}
// DatabaseConfig contient les paramètres de configuration de la base de données.
type DatabaseConfig struct {
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
Dbname string `mapstructure:"dbname"`
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Sslmode string `mapstructure:"sslmode"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
DBName string `mapstructure:"dbname"`
SSLMode string `mapstructure:"sslmode"`
}
// ServerConfig holds server-specific configuration.
type ServerConfig struct {
Address string `mapstructure:"address"`
}
// Load reads configuration from file and environment variables.
func Load() (*Config, error) {
// 0. Configuration for environment variables
viper.SetEnvPrefix("APP") // Variables must start with "APP_" (e.g., APP_SERVER_ADDRESS)
// 1. Base configuration file
viper.SetConfigName("config") // config.yaml
// LoadConfig charge la configuration depuis un fichier et les variables d'environnement.
func LoadConfig(path string) (config Config, err error) {
viper.AddConfigPath(path)
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
// Read the base file. Don't stop if it's not found.
if err := viper.ReadInConfig(); err != nil {
viper.SetDefault("server.address", ":8080")
viper.SetDefault("server.trusted_proxies", "127.0.0.1, ::1")
viper.SetDefault("database.host", "localhost")
viper.SetDefault("database.port", 5432)
viper.SetDefault("database.user", "default_user")
viper.SetDefault("database.password", "")
viper.SetDefault("database.dbname", "default_db")
viper.SetDefault("database.sslmode", "disable")
// L'ordre ici est important
// 1. D'abord, on lit le fichier
err = viper.ReadInConfig()
if err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return nil, fmt.Errorf("error reading base config file config.yaml: %w", err)
}
}
// 2. Override with environment-specific file (via APP_ENV)
if env := os.Getenv("APP_ENV"); env != "" {
viper.SetConfigName("config." + env) // e.g., config.prod.yaml
if err := viper.MergeInConfig(); err != nil {
log.Printf("Warning: could not load config file for environment '%s': %v", env, err)
return
}
}
// 2. Ensuite, on prépare Viper à lire les variables d'environnement
viper.SetEnvPrefix("APP")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv()
viper.AutomaticEnv() // Dit à Viper de chercher les variables d'environnement
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("unable to decode config into struct: %w", err)
}
// 3. Enfin, on déverse le résultat final dans la struct.
// C'est à ce moment que la surcharge a lieu.
fmt.Printf("[%v]\n", config.Database.DBName)
return &cfg, nil
err = viper.Unmarshal(&config)
return
}

View File

@@ -16,8 +16,8 @@ type Service struct {
// NewService initializes and returns a new database service.
func NewService(cfg *config.DatabaseConfig) (*Service, error) {
connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=%s",
cfg.User, cfg.Password, cfg.Dbname,
cfg.Host, cfg.Port, cfg.Sslmode,
cfg.User, cfg.Password, cfg.DBName,
cfg.Host, cfg.Port, cfg.SSLMode,
)
db, err := sql.Open("postgres", connStr)