Compare commits
2 Commits
c40ae04496
...
97d8a4541f
| Author | SHA1 | Date | |
|---|---|---|---|
| 97d8a4541f | |||
| b8c43e0758 |
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import "context"
|
||||
import "flag"
|
||||
import "fmt"
|
||||
import "os"
|
||||
import "os/signal"
|
||||
import "syscall"
|
||||
@@ -48,26 +49,34 @@ func run() int {
|
||||
var cfg codit.Config
|
||||
var logger codit.Logger
|
||||
var server *codit.Server
|
||||
var logFile string
|
||||
var err error
|
||||
|
||||
flag.Var(&configPaths, "config", "path or wildcard pattern to YAML configuration file; repeatable")
|
||||
flag.Var(&configPaths, "config-file", "path to YAML configuration file; repeatable")
|
||||
flag.Var(&configPaths, "config-file-pattern", "wildcard pattern for YAML configuration files; repeatable")
|
||||
flag.StringVar(&logFile, "log-file", "", "path to log file")
|
||||
flag.Parse()
|
||||
|
||||
logger = codit.NewAsyncLogger(PROGRAM_NAME, os.Stderr, codit.LOG_ALL)
|
||||
cfg, err = codit.LoadConfigFilesWithEnvPrefix(configPaths, codit.EnvPrefixFromServerIdentifier(PROGRAM_NAME))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "load config: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
if logFile != "" {
|
||||
cfg.LogFile = logFile
|
||||
}
|
||||
logger, err = newLoggerFromConfig(PROGRAM_NAME, cfg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "init logger: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
defer logger.Close()
|
||||
ctx, stop = signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt)
|
||||
defer stop()
|
||||
logger.Write("", codit.LOG_INFO, "starting %s %s", PROGRAM_NAME, PROGRAM_VERSION)
|
||||
defer logger.Write("", codit.LOG_INFO, "stopped %s %s", PROGRAM_NAME, PROGRAM_VERSION)
|
||||
|
||||
cfg, err = codit.LoadConfigFilesWithEnvPrefix(configPaths, codit.EnvPrefixFromServerIdentifier(PROGRAM_NAME))
|
||||
if err != nil {
|
||||
logger.Write("", codit.LOG_ERROR, "load config: %v", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
server, err = codit.NewServerWithIdentifier(&cfg, logger, PROGRAM_NAME)
|
||||
if err != nil {
|
||||
logger.Write("", codit.LOG_ERROR, "init app: %v", err)
|
||||
@@ -83,3 +92,19 @@ func run() int {
|
||||
logger.Write("", codit.LOG_INFO, "shutdown complete - %s %s", PROGRAM_NAME, PROGRAM_VERSION)
|
||||
return 0
|
||||
}
|
||||
|
||||
func newLoggerFromConfig(id string, cfg codit.Config) (codit.Logger, error) {
|
||||
var mask codit.LogMask
|
||||
var logger *codit.AsyncLogger
|
||||
var err error
|
||||
|
||||
mask = codit.LogStrsToMask(cfg.LogMask)
|
||||
if cfg.LogFile == "" {
|
||||
return codit.NewAsyncLogger(id, os.Stderr, mask), nil
|
||||
}
|
||||
logger, err = codit.NewAsyncLoggerToFile(id, cfg.LogFile, cfg.LogMaxSize, cfg.LogRotate, mask)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return logger, nil
|
||||
}
|
||||
|
||||
@@ -47,6 +47,18 @@ type Config struct {
|
||||
DockerHTTPPrefix string `yaml:"docker_http_prefix"`
|
||||
GitHTTPPrefix string `yaml:"git_http_prefix"`
|
||||
RPMHTTPPrefix string `yaml:"rpm_http_prefix"`
|
||||
App LogConfig `yaml:"app"`
|
||||
LogMask []string `yaml:"log-mask"`
|
||||
LogFile string `yaml:"log-file"`
|
||||
LogMaxSize int64 `yaml:"log-max-size"`
|
||||
LogRotate int `yaml:"log-rotate"`
|
||||
}
|
||||
|
||||
type LogConfig struct {
|
||||
LogMask []string `yaml:"log-mask"`
|
||||
LogFile string `yaml:"log-file"`
|
||||
LogMaxSize int64 `yaml:"log-max-size"`
|
||||
LogRotate int `yaml:"log-rotate"`
|
||||
}
|
||||
|
||||
const DefaultEnvPrefix string = "CODIT_"
|
||||
@@ -89,11 +101,13 @@ func LoadFilesWithEnvPrefix(paths []string, envPrefix string) (Config, error) {
|
||||
DockerHTTPPrefix: "/v2",
|
||||
GitHTTPPrefix: "/git",
|
||||
RPMHTTPPrefix: "/rpm",
|
||||
LogMask: []string{},
|
||||
}
|
||||
err = loadConfigFiles(&cfg, paths)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
applyAppLogConfig(&cfg)
|
||||
override(&cfg, envPrefix)
|
||||
cfg.AuthMode = strings.ToLower(strings.TrimSpace(cfg.AuthMode))
|
||||
cfg.TLSServerCertSource = strings.ToLower(strings.TrimSpace(cfg.TLSServerCertSource))
|
||||
@@ -112,6 +126,21 @@ func LoadFilesWithEnvPrefix(paths []string, envPrefix string) (Config, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func applyAppLogConfig(cfg *Config) {
|
||||
if len(cfg.App.LogMask) > 0 {
|
||||
cfg.LogMask = cfg.App.LogMask
|
||||
}
|
||||
if cfg.App.LogFile != "" {
|
||||
cfg.LogFile = cfg.App.LogFile
|
||||
}
|
||||
if cfg.App.LogMaxSize != 0 {
|
||||
cfg.LogMaxSize = cfg.App.LogMaxSize
|
||||
}
|
||||
if cfg.App.LogRotate != 0 {
|
||||
cfg.LogRotate = cfg.App.LogRotate
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func loadConfigFiles(cfg *Config, paths []string) error {
|
||||
var expanded []string
|
||||
@@ -321,6 +350,22 @@ func override(cfg *Config, envPrefix string) {
|
||||
if v != "" {
|
||||
cfg.RPMHTTPPrefix = v
|
||||
}
|
||||
v = getEnv(envPrefix, "LOG_MASK")
|
||||
if v != "" {
|
||||
cfg.LogMask = splitCSV(v)
|
||||
}
|
||||
v = getEnv(envPrefix, "LOG_FILE")
|
||||
if v != "" {
|
||||
cfg.LogFile = v
|
||||
}
|
||||
v = getEnv(envPrefix, "LOG_MAX_SIZE")
|
||||
if v != "" {
|
||||
cfg.LogMaxSize, _ = strconv.ParseInt(v, 10, 64)
|
||||
}
|
||||
v = getEnv(envPrefix, "LOG_ROTATE")
|
||||
if v != "" {
|
||||
cfg.LogRotate, _ = strconv.Atoi(v)
|
||||
}
|
||||
}
|
||||
|
||||
func getEnv(prefix string, name string) string {
|
||||
|
||||
@@ -58,7 +58,7 @@ func TestLoadFromYAMLAndEnvOverride(t *testing.T) {
|
||||
var cfg Config
|
||||
dir = t.TempDir()
|
||||
path = filepath.Join(dir, "config.yaml")
|
||||
data = "db_driver: sqlite\ndb_dsn: file:test.db\nauth_mode: HyBrId\ngit_http_prefix: /g\ndocker_http_prefix: registry\n"
|
||||
data = "db_driver: sqlite\ndb_dsn: file:test.db\nauth_mode: HyBrId\ngit_http_prefix: /g\ndocker_http_prefix: registry\napp:\n log-mask: [error, warn]\n log-file: /tmp/codit.log\n log-max-size: 1234\n log-rotate: 3\n"
|
||||
err = os.WriteFile(path, []byte(data), 0o644)
|
||||
if err != nil {
|
||||
t.Fatalf("write config file: %v", err)
|
||||
@@ -81,6 +81,12 @@ func TestLoadFromYAMLAndEnvOverride(t *testing.T) {
|
||||
if cfg.DockerHTTPPrefix != "/registry" {
|
||||
t.Fatalf("docker_http_prefix normalization failed: %s", cfg.DockerHTTPPrefix)
|
||||
}
|
||||
if len(cfg.LogMask) != 2 || cfg.LogMask[0] != "error" || cfg.LogMask[1] != "warn" {
|
||||
t.Fatalf("log-mask load failed: %#v", cfg.LogMask)
|
||||
}
|
||||
if cfg.LogFile != "/tmp/codit.log" || cfg.LogMaxSize != 1234 || cfg.LogRotate != 3 {
|
||||
t.Fatalf("log config load failed: file=%q max=%d rotate=%d", cfg.LogFile, cfg.LogMaxSize, cfg.LogRotate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFilesLaterWinsAndGlob(t *testing.T) {
|
||||
|
||||
+40
-5
@@ -14,6 +14,7 @@ import "io"
|
||||
import "log"
|
||||
import "net"
|
||||
import "net/http"
|
||||
import "net/netip"
|
||||
import "os"
|
||||
import "path/filepath"
|
||||
import "sync"
|
||||
@@ -1221,14 +1222,22 @@ func (m *additionalListenerManager) startEndpoint(endpoint listenerEndpoint) run
|
||||
m.wg.Add(1)
|
||||
go func(ep listenerEndpoint, srv *http.Server) {
|
||||
var err error
|
||||
var listener net.Listener
|
||||
var network string
|
||||
defer m.wg.Done()
|
||||
network = tcpAddrStrClass(ep.Addr)
|
||||
listener, err = net.Listen(network, ep.Addr)
|
||||
if err != nil {
|
||||
m.Logger.Write(ep.Name, LOG_ERROR, "additional listener failed network=%s addr=%s err=%v", network, ep.Addr, err)
|
||||
return
|
||||
}
|
||||
if ep.IsHTTPS {
|
||||
err = srv.ListenAndServeTLS("", "")
|
||||
err = srv.ServeTLS(listener, "", "")
|
||||
} else {
|
||||
err = srv.ListenAndServe()
|
||||
err = srv.Serve(listener)
|
||||
}
|
||||
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
m.Logger.Write(ep.Name, LOG_ERROR, "additional listener failed addr=%s err=%v", ep.Addr, err)
|
||||
m.Logger.Write(ep.Name, LOG_ERROR, "additional listener failed network=%s addr=%s err=%v", network, ep.Addr, err)
|
||||
}
|
||||
}(endpoint, server)
|
||||
return running
|
||||
@@ -1935,6 +1944,24 @@ func TitleFromServerIdentifier(value string) string {
|
||||
return codit_config.TitleFromServerIdentifier(value)
|
||||
}
|
||||
|
||||
func tcpAddrStrClass(addr string) string {
|
||||
var ap netip.AddrPort
|
||||
var err error
|
||||
|
||||
if len(addr) > 0 {
|
||||
ap, err = netip.ParseAddrPort(addr)
|
||||
if err == nil {
|
||||
if ap.Addr().Is6() {
|
||||
return "tcp6"
|
||||
}
|
||||
if ap.Addr().Is4() || ap.Addr().Is4In6() {
|
||||
return "tcp4"
|
||||
}
|
||||
}
|
||||
}
|
||||
return "tcp"
|
||||
}
|
||||
|
||||
func serveListeners(ctx context.Context, endpoints []listenerEndpoint, handler http.Handler, logger Logger, serverIdentifier string) error {
|
||||
var listenCtx context.Context
|
||||
var cancel context.CancelFunc
|
||||
@@ -1980,9 +2007,12 @@ func serveListeners(ctx context.Context, endpoints []listenerEndpoint, handler h
|
||||
var err error
|
||||
var server *http.Server
|
||||
var l *log.Logger
|
||||
var listener net.Listener
|
||||
var network string
|
||||
defer wg.Done()
|
||||
|
||||
l = log.New(&server_http_log_writer{l: logger, id: "", depth: +2}, "", 0)
|
||||
network = tcpAddrStrClass(endpoint.Addr)
|
||||
if endpoint.IsHTTPS {
|
||||
server = &http.Server{
|
||||
Addr: endpoint.Addr,
|
||||
@@ -2002,10 +2032,15 @@ func serveListeners(ctx context.Context, endpoints []listenerEndpoint, handler h
|
||||
serversMu.Lock()
|
||||
servers = append(servers, server)
|
||||
serversMu.Unlock()
|
||||
listener, err = net.Listen(network, endpoint.Addr)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("listen %s %s: %w", network, endpoint.Addr, err)
|
||||
return
|
||||
}
|
||||
if endpoint.IsHTTPS {
|
||||
err = server.ListenAndServeTLS("", "")
|
||||
err = server.ServeTLS(listener, "", "")
|
||||
} else {
|
||||
err = server.ListenAndServe()
|
||||
err = server.Serve(listener)
|
||||
}
|
||||
errs <- err
|
||||
}(ep)
|
||||
|
||||
Reference in New Issue
Block a user