fix(config): fix configuration management
This commit is contained in:
17
Taskfile.yml
17
Taskfile.yml
@@ -1,7 +1,8 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
API_IMAGE_NAME: realz
|
REGISTRY: reg.cadoles.com/lacanne
|
||||||
|
API_IMAGE_NAME: realzapi
|
||||||
API_IMAGE_VERSION: v1.0.0
|
API_IMAGE_VERSION: v1.0.0
|
||||||
DB_IMAGE_NAME: realzdb
|
DB_IMAGE_NAME: realzdb
|
||||||
DB_IMAGE_VERSION: v1.0.0
|
DB_IMAGE_VERSION: v1.0.0
|
||||||
@@ -14,15 +15,25 @@ tasks:
|
|||||||
build-api:
|
build-api:
|
||||||
desc: Construction de l'image Docker realz API
|
desc: Construction de l'image Docker realz API
|
||||||
cmds:
|
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
|
silent: true
|
||||||
|
|
||||||
build-db:
|
build-db:
|
||||||
desc: Construction de l'image Docker realz DB
|
desc: Construction de l'image Docker realz DB
|
||||||
cmds:
|
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
|
silent: true
|
||||||
|
|
||||||
build:
|
build:
|
||||||
desc: Construction des images Docker realz
|
desc: Construction des images Docker realz
|
||||||
deps: [ build-api, build-db ]
|
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
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
package api
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@@ -99,11 +100,13 @@ func getCorrectedAltitude(db *database.Service) gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfg, err := config.Load()
|
cfg, err := config.LoadConfig(".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error loading configuration: %v", err)
|
log.Fatalf("Error loading configuration: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Config: %+v\n", cfg)
|
||||||
|
|
||||||
db, err := database.NewService(&cfg.Database)
|
db, err := database.NewService(&cfg.Database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Could not initialize database: %v", err)
|
log.Fatalf("Could not initialize database: %v", err)
|
||||||
@@ -113,8 +116,14 @@ func main() {
|
|||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
|
|
||||||
// Servir les fichiers statiques (index.html, etc.) depuis le répertoire courant.
|
// Configure les proxies de confiance pour Gin
|
||||||
router.StaticFS("/", http.Dir("."))
|
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.
|
// La route est maintenant un POST pour recevoir un corps de requête JSON.
|
||||||
router.POST("/getorthocorrec", getOrthometricCorrection(db))
|
router.POST("/getorthocorrec", getOrthometricCorrection(db))
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
server:
|
server:
|
||||||
address: "0.0.0.0:8088"
|
address: "0.0.0.0:8088"
|
||||||
|
trustes_proxies:
|
||||||
|
- "127.0.0.1"
|
||||||
|
- "::1"
|
||||||
|
|
||||||
database:
|
database:
|
||||||
user: "realz"
|
user: "realz"
|
||||||
|
@@ -6,8 +6,9 @@ COPY go.mod go.sum ./
|
|||||||
RUN go mod download
|
RUN go mod download
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN go build
|
RUN go build cmd/api/realz.go
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=builder /app/realz /realz
|
COPY --from=builder /app/realz /realz
|
||||||
|
COPY --from=builder /app/index.html /index.html
|
||||||
ENTRYPOINT ["/realz"]
|
ENTRYPOINT ["/realz"]
|
@@ -1,17 +1,47 @@
|
|||||||
services:
|
services:
|
||||||
|
api:
|
||||||
|
image: reg.cadoles.com/lacanne/realzapi:latest
|
||||||
|
env_file: .env
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
postgis:
|
postgis:
|
||||||
image: realz
|
condition: service_healthy
|
||||||
container_name: postgis_initialized
|
ports:
|
||||||
|
- "8088:8080" # Expose API port (host:container)
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=${POSTGRES_USER}
|
APP_SERVER_ADDRESS: 0.0.0.0:8080
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
APP_DATABASE_HOST: postgis
|
||||||
- POSTGRES_DB=${POSTGRES_DB} # Base de données pour l'administration, pas celle de l'app
|
APP_DATABASE_PORT: 5432
|
||||||
- PGRST_AUTHUSER=${PGRST_AUTHUSER}
|
APP_DATABASE_USER: ${POSTGRES_USER}
|
||||||
- PGRST_PASSWORD=${PGRST_PASSWORD}
|
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:
|
ports:
|
||||||
- "5433:5432"
|
- "5433:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- postgis_data:/var/lib/postgresql/data
|
- 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:
|
volumes:
|
||||||
postgis_data:
|
postgis_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
realz-net:
|
@@ -2,66 +2,67 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"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 {
|
type Config struct {
|
||||||
Database DatabaseConfig `mapstructure:"database"`
|
Server ServerConfig
|
||||||
Server ServerConfig `mapstructure:"server"`
|
Database DatabaseConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// DatabaseConfig holds database connection configuration.
|
// ServerConfig contient les paramètres de configuration du serveur HTTP.
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerConfig holds server-specific configuration.
|
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
Address string `mapstructure:"address"`
|
Address string `mapstructure:"address"`
|
||||||
|
TrustedProxies []string `mapstructure:"trusted_proxies"` // Liste des IPs de proxies de confiance
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load reads configuration from file and environment variables.
|
// DatabaseConfig contient les paramètres de configuration de la base de données.
|
||||||
func Load() (*Config, error) {
|
type DatabaseConfig struct {
|
||||||
// 0. Configuration for environment variables
|
Host string `mapstructure:"host"`
|
||||||
viper.SetEnvPrefix("APP") // Variables must start with "APP_" (e.g., APP_SERVER_ADDRESS)
|
Port int `mapstructure:"port"`
|
||||||
|
User string `mapstructure:"user"`
|
||||||
|
Password string `mapstructure:"password"`
|
||||||
|
DBName string `mapstructure:"dbname"`
|
||||||
|
SSLMode string `mapstructure:"sslmode"`
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Base configuration file
|
// LoadConfig charge la configuration depuis un fichier et les variables d'environnement.
|
||||||
viper.SetConfigName("config") // config.yaml
|
func LoadConfig(path string) (config Config, err error) {
|
||||||
|
viper.AddConfigPath(path)
|
||||||
|
viper.SetConfigName("config")
|
||||||
viper.SetConfigType("yaml")
|
viper.SetConfigType("yaml")
|
||||||
viper.AddConfigPath(".")
|
|
||||||
|
|
||||||
// Read the base file. Don't stop if it's not found.
|
viper.SetDefault("server.address", ":8080")
|
||||||
if err := viper.ReadInConfig(); err != nil {
|
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 {
|
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||||||
return nil, fmt.Errorf("error reading base config file config.yaml: %w", err)
|
return
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Ensuite, on prépare Viper à lire les variables d'environnement
|
||||||
|
viper.SetEnvPrefix("APP")
|
||||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||||
viper.AutomaticEnv()
|
viper.AutomaticEnv() // Dit à Viper de chercher les variables d'environnement
|
||||||
|
|
||||||
var cfg Config
|
// 3. Enfin, on déverse le résultat final dans la struct.
|
||||||
if err := viper.Unmarshal(&cfg); err != nil {
|
// C'est à ce moment que la surcharge a lieu.
|
||||||
return nil, fmt.Errorf("unable to decode config into struct: %w", err)
|
fmt.Printf("[%v]\n", config.Database.DBName)
|
||||||
}
|
|
||||||
|
|
||||||
return &cfg, nil
|
err = viper.Unmarshal(&config)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
@@ -16,8 +16,8 @@ type Service struct {
|
|||||||
// NewService initializes and returns a new database service.
|
// NewService initializes and returns a new database service.
|
||||||
func NewService(cfg *config.DatabaseConfig) (*Service, error) {
|
func NewService(cfg *config.DatabaseConfig) (*Service, error) {
|
||||||
connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=%s",
|
connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=%s",
|
||||||
cfg.User, cfg.Password, cfg.Dbname,
|
cfg.User, cfg.Password, cfg.DBName,
|
||||||
cfg.Host, cfg.Port, cfg.Sslmode,
|
cfg.Host, cfg.Port, cfg.SSLMode,
|
||||||
)
|
)
|
||||||
|
|
||||||
db, err := sql.Open("postgres", connStr)
|
db, err := sql.Open("postgres", connStr)
|
||||||
|
Reference in New Issue
Block a user