Skip to content

Commit 493d00c

Browse files
committed
fix: properly support --config-path argument
Changes: - Change the flow how the config is merged: first read the config from the file if it is set, merge it with the defaults, then init the rest of command line flags using the merged defaults + config file as the base. - Make some config fields pointers to change how it's merged. Signed-off-by: Artem Chernyshev <[email protected]>
1 parent 742faec commit 493d00c

File tree

17 files changed

+391
-281
lines changed

17 files changed

+391
-281
lines changed

cmd/omni/cmd/cmd.go

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,27 @@ import (
1111
"fmt"
1212
"os"
1313
"os/signal"
14-
"sync"
1514
"syscall"
1615

1716
"github.com/siderolabs/gen/ensure"
18-
"github.com/siderolabs/go-debug"
17+
"github.com/siderolabs/talos/pkg/machinery/config/merge"
1918
"github.com/spf13/cobra"
2019
"go.uber.org/zap"
2120
"go.uber.org/zap/zapcore"
2221

2322
"github.com/siderolabs/omni/client/pkg/constants"
2423
"github.com/siderolabs/omni/client/pkg/panichandler"
24+
"github.com/siderolabs/omni/cmd/omni/pkg/app"
25+
"github.com/siderolabs/omni/internal/pkg/auth/actor"
2526
"github.com/siderolabs/omni/internal/pkg/config"
2627
"github.com/siderolabs/omni/internal/version"
2728
)
2829

29-
func runDebugServer(ctx context.Context, logger *zap.Logger, bindEndpoint string) {
30-
debugLogFunc := func(msg string) {
31-
logger.Info(msg)
32-
}
33-
34-
if err := debug.ListenAndServe(ctx, bindEndpoint, debugLogFunc); err != nil {
35-
logger.Panic("failed to start debug server", zap.Error(err))
36-
}
37-
}
38-
3930
// rootCmd represents the base command when called without any subcommands.
4031
var rootCmd = &cobra.Command{
4132
Use: "omni",
4233
Short: "Omni Kubernetes management platform service",
43-
Long: "This executable runs both frontend and backend",
34+
Long: "This executable runs both Omni frontend and Omni backend",
4435
SilenceUsage: true,
4536
Version: version.Tag,
4637
RunE: func(*cobra.Command, []string) error {
@@ -82,20 +73,14 @@ var rootCmd = &cobra.Command{
8273
cancel()
8374
}, logger)
8475

85-
var configs []*config.Params
86-
87-
if rootCmdArgs.configPath != "" {
88-
var cfg *config.Params
89-
90-
cfg, err = config.LoadFromFile(rootCmdArgs.configPath)
91-
if err != nil {
92-
return err
93-
}
94-
95-
configs = append(configs, cfg)
76+
config, err := app.PrepareConfig(logger, cmdConfig)
77+
if err != nil {
78+
return err
9679
}
9780

98-
return RunService(ctx, logger, append(configs, cmdConfig)...)
81+
ctx = actor.MarkContextAsInternalActor(ctx)
82+
83+
return app.Run(ctx, config, logger)
9984
},
10085
}
10186

@@ -104,13 +89,35 @@ var rootCmdArgs struct {
10489
debug bool
10590
}
10691

107-
// RootCmd returns the root command.
108-
func RootCmd() *cobra.Command { return initOnce() }
92+
// Execute the command.
93+
func Execute() error {
94+
rootCmd.Flags().StringVar(&rootCmdArgs.configPath, "config-path", "", "load the config from the file, flags have bigger priority")
95+
96+
// Parsing the config path flag early to let it populate the initial configuration
97+
// ignore all errors, they will be handled in the Execute
98+
rootCmd.Flags().Parse(os.Args[1:]) //nolint:errcheck
99+
100+
if rootCmdArgs.configPath == "" {
101+
return newCommand().Execute()
102+
}
103+
104+
cfg, err := config.LoadFromFile(rootCmdArgs.configPath)
105+
if err != nil {
106+
return err
107+
}
108+
109+
// override the cmdConfig with the config loaded from the file
110+
if err := merge.Merge(cmdConfig, cfg); err != nil {
111+
return err
112+
}
113+
114+
return newCommand().Execute()
115+
}
109116

110-
var cmdConfig = config.InitDefault()
117+
var cmdConfig = config.Default()
111118

112-
var initOnce = sync.OnceValue(func() *cobra.Command {
113-
rootCmd.Flags().BoolVar(&rootCmdArgs.debug, "debug", false, "enable debug logs.")
119+
func newCommand() *cobra.Command {
120+
rootCmd.Flags().BoolVar(&rootCmdArgs.debug, "debug", constants.IsDebugBuild, "enable debug logs.")
114121

115122
rootCmd.Flags().StringVar(&cmdConfig.Account.ID, "account-id", cmdConfig.Account.ID, "instance account ID, should never be changed.")
116123
rootCmd.Flags().StringVar(&cmdConfig.Account.Name, "name", cmdConfig.Account.Name, "instance user-facing name.")
@@ -124,10 +131,8 @@ var initOnce = sync.OnceValue(func() *cobra.Command {
124131
defineDebugFlags()
125132
defineEtcdBackupsFlags()
126133

127-
rootCmd.Flags().StringVar(&rootCmdArgs.configPath, "config-path", "", "load the config from the file, flags have bigger priority")
128-
129134
return rootCmd
130-
})
135+
}
131136

132137
func defineServiceFlags() {
133138
// API
@@ -146,13 +151,13 @@ func defineServiceFlags() {
146151
rootCmd.Flags().StringVar(
147152
&cmdConfig.Services.API.KeyFile,
148153
"key",
149-
"",
154+
cmdConfig.Services.API.KeyFile,
150155
"TLS key file",
151156
)
152157
rootCmd.Flags().StringVar(
153158
&cmdConfig.Services.API.CertFile,
154159
"cert",
155-
"",
160+
cmdConfig.Services.API.CertFile,
156161
"TLS cert file",
157162
)
158163

@@ -194,13 +199,13 @@ func defineServiceFlags() {
194199
rootCmd.Flags().BoolVar(
195200
&cmdConfig.Services.Siderolink.DisableLastEndpoint,
196201
"siderolink-disable-last-endpoint",
197-
false,
202+
cmdConfig.Services.Siderolink.DisableLastEndpoint,
198203
"do not populate last known peer endpoint for the WireGuard peers",
199204
)
200205
rootCmd.Flags().BoolVar(
201206
&cmdConfig.Services.Siderolink.UseGRPCTunnel,
202207
"siderolink-use-grpc-tunnel",
203-
false,
208+
cmdConfig.Services.Siderolink.UseGRPCTunnel,
204209
"use gRPC tunnel to wrap WireGuard traffic instead of UDP. When enabled, "+
205210
"the SideroLink connections from Talos machines will be configured to use the tunnel mode, regardless of their individual configuration. ",
206211
)
@@ -216,9 +221,10 @@ func defineServiceFlags() {
216221
cmdConfig.Services.Siderolink.LogServerPort,
217222
"port for TCP log server",
218223
)
219-
rootCmd.Flags().Var(
224+
rootCmd.Flags().StringVar(
220225
&cmdConfig.Services.Siderolink.JoinTokensMode,
221226
"join-tokens-mode",
227+
cmdConfig.Services.Siderolink.JoinTokensMode,
222228
"configures Talos machine join flow to use secure node tokens",
223229
)
224230

@@ -331,10 +337,14 @@ func defineServiceFlags() {
331337

332338
// DevServerProxy
333339
rootCmd.Flags().StringVar(
334-
&cmdConfig.Services.DevServerProxy.ProxyTo, "frontend-dst", "",
340+
&cmdConfig.Services.DevServerProxy.ProxyTo,
341+
"frontend-dst",
342+
cmdConfig.Services.DevServerProxy.ProxyTo,
335343
"destination address non API requests from proxy server.")
336344
rootCmd.Flags().StringVar(
337-
&cmdConfig.Services.DevServerProxy.BindEndpoint, "frontend-bind", "",
345+
&cmdConfig.Services.DevServerProxy.BindEndpoint,
346+
"frontend-bind",
347+
cmdConfig.Services.DevServerProxy.BindEndpoint,
338348
"proxy server which will redirect all non API requests to the definied frontend server.")
339349
}
340350

@@ -540,8 +550,6 @@ func defineStorageFlags() {
540550
"file containing private key to use for decrypting master key slot.",
541551
)
542552

543-
ensure.NoError(rootCmd.MarkFlagRequired("private-key-source"))
544-
545553
rootCmd.Flags().StringSliceVar(
546554
&cmdConfig.Storage.Default.Etcd.PublicKeyFiles,
547555
"public-key-files",
@@ -585,7 +593,7 @@ func defineRegistriesFlags() {
585593
rootCmd.Flags().StringSliceVar(
586594
&cmdConfig.Registries.Mirrors,
587595
"registry-mirror",
588-
[]string{},
596+
cmdConfig.Registries.Mirrors,
589597
"list of registry mirrors to use in format: <registry host>=<mirror URL>",
590598
)
591599
}

cmd/omni/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
package main
88

99
import (
10-
"os"
10+
"log"
1111

1212
_ "github.com/siderolabs/omni/cmd/acompat" // this package should always be imported first for init->set env to work
1313
"github.com/siderolabs/omni/cmd/omni/cmd"
1414
)
1515

1616
func main() {
17-
if err := cmd.RootCmd().Execute(); err != nil {
18-
os.Exit(1)
17+
if err := cmd.Execute(); err != nil {
18+
log.Fatalf("failed to run Omni: %s", err)
1919
}
2020
}

cmd/omni/cmd/run.go renamed to cmd/omni/pkg/app/app.go

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,20 @@
33
// Use of this software is governed by the Business Source License
44
// included in the LICENSE file.
55

6-
package cmd
6+
// Package app contains the Omni startup methods.
7+
package app
78

89
import (
910
"context"
1011
"fmt"
1112

1213
"github.com/cosi-project/runtime/pkg/resource"
1314
"github.com/cosi-project/runtime/pkg/state"
14-
"github.com/go-logr/zapr"
1515
"github.com/prometheus/client_golang/prometheus"
16-
"github.com/siderolabs/talos/pkg/machinery/config/merge"
16+
"github.com/siderolabs/go-debug"
1717
"go.uber.org/zap"
1818
"go.uber.org/zap/zapcore"
19-
"k8s.io/klog/v2"
2019

21-
"github.com/siderolabs/omni/client/pkg/compression"
22-
"github.com/siderolabs/omni/client/pkg/constants"
2320
authres "github.com/siderolabs/omni/client/pkg/omni/resources/auth"
2421
omnires "github.com/siderolabs/omni/client/pkg/omni/resources/omni"
2522
"github.com/siderolabs/omni/client/pkg/panichandler"
@@ -40,44 +37,32 @@ import (
4037
"github.com/siderolabs/omni/internal/pkg/ctxstore"
4138
"github.com/siderolabs/omni/internal/pkg/features"
4239
"github.com/siderolabs/omni/internal/pkg/siderolink"
43-
"github.com/siderolabs/omni/internal/version"
4440
)
4541

46-
// RunService starts the main Omni server.
47-
func RunService(ctx context.Context, logger *zap.Logger, paramsList ...*config.Params) error {
48-
cfg := config.InitDefault()
42+
// PrepareConfig prepare the Omni configuration.
43+
func PrepareConfig(logger *zap.Logger, params ...*config.Params) (*config.Params, error) {
44+
var err error
4945

50-
for _, params := range paramsList {
51-
if err := merge.Merge(cfg, params); err != nil {
52-
return err
53-
}
46+
config.Config, err = config.Init(logger, params...)
47+
if err != nil {
48+
return nil, err
5449
}
5550

56-
cfg.PopulateFallbacks()
51+
return config.Config, nil
52+
}
5753

58-
if err := cfg.Validate(); err != nil {
59-
return err
54+
func runDebugServer(ctx context.Context, logger *zap.Logger, bindEndpoint string) {
55+
debugLogFunc := func(msg string) {
56+
logger.Info(msg)
6057
}
6158

62-
config.Config = cfg
63-
64-
if err := compression.InitConfig(config.Config.Features.EnableConfigDataCompression); err != nil {
65-
return err
59+
if err := debug.ListenAndServe(ctx, bindEndpoint, debugLogFunc); err != nil {
60+
logger.Panic("failed to start debug server", zap.Error(err))
6661
}
62+
}
6763

68-
logger.Info("initialized resource compression config", zap.Bool("enabled", config.Config.Features.EnableConfigDataCompression))
69-
70-
// set kubernetes logger to use warn log level and use zap
71-
klog.SetLogger(zapr.NewLogger(logger.WithOptions(zap.IncreaseLevel(zapcore.WarnLevel)).With(logging.Component("kubernetes"))))
72-
73-
if constants.IsDebugBuild {
74-
logger.Warn("running debug build")
75-
}
76-
77-
logger.Info("starting Omni", zap.String("version", version.Tag))
78-
79-
logger.Debug("using config", zap.Any("config", config.Config))
80-
64+
// Run the Omni service.
65+
func Run(ctx context.Context, cfg *config.Params, logger *zap.Logger) error {
8166
if cfg.Debug.Server.Endpoint != "" {
8267
panichandler.Go(func() {
8368
runDebugServer(ctx, logger, cfg.Debug.Server.Endpoint)

internal/backend/runtime/omni/export_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func EtcdElections(ctx context.Context, client *clientv3.Client, electionKey str
3030
return etcdElections(ctx, client, electionKey, logger, f)
3131
}
3232

33-
func ClusterValidationOptions(st state.State, etcdBackupConfig config.EtcdBackup, embeddedDiscoveryServiceConfig config.EmbeddedDiscoveryService) []validated.StateOption {
33+
func ClusterValidationOptions(st state.State, etcdBackupConfig config.EtcdBackup, embeddedDiscoveryServiceConfig *config.EmbeddedDiscoveryService) []validated.StateOption {
3434
return clusterValidationOptions(st, etcdBackupConfig, embeddedDiscoveryServiceConfig)
3535
}
3636

internal/backend/runtime/omni/state_validation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import (
4242
// Validation is only syntactic - they are checked whether they are valid semver strings.
4343
//
4444
//nolint:gocognit,gocyclo,cyclop
45-
func clusterValidationOptions(st state.State, etcdBackupConfig config.EtcdBackup, embeddedDiscoveryServiceConfig config.EmbeddedDiscoveryService) []validated.StateOption {
45+
func clusterValidationOptions(st state.State, etcdBackupConfig config.EtcdBackup, embeddedDiscoveryServiceConfig *config.EmbeddedDiscoveryService) []validated.StateOption {
4646
validateVersions := func(ctx context.Context, existingRes *omni.Cluster, res *omni.Cluster, skipTalosVersion, skipKubernetesVersion bool) error {
4747
if skipTalosVersion && skipKubernetesVersion {
4848
return nil

internal/backend/runtime/omni/state_validation_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func TestClusterValidation(t *testing.T) {
5858
}
5959

6060
innerSt := state.WrapCore(namespaced.NewState(inmem.Build))
61-
st := validated.NewState(innerSt, omni.ClusterValidationOptions(state.WrapCore(innerSt), etcdBackupConfig, config.EmbeddedDiscoveryService{})...)
61+
st := validated.NewState(innerSt, omni.ClusterValidationOptions(state.WrapCore(innerSt), etcdBackupConfig, &config.EmbeddedDiscoveryService{})...)
6262

6363
talosVersion1 := omnires.NewTalosVersion(resources.DefaultNamespace, "1.4.0")
6464
talosVersion1.TypedSpec().Value.CompatibleKubernetesVersions = []string{"1.27.0", "1.27.1"}
@@ -172,7 +172,7 @@ func TestClusterUseEmbeddedDiscoveryServiceValidation(t *testing.T) {
172172
ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second)
173173
t.Cleanup(cancel)
174174

175-
buildState := func(conf config.EmbeddedDiscoveryService) (inner, outer state.State) {
175+
buildState := func(conf *config.EmbeddedDiscoveryService) (inner, outer state.State) {
176176
innerSt := state.WrapCore(namespaced.NewState(inmem.Build))
177177
st := validated.NewState(innerSt, omni.ClusterValidationOptions(state.WrapCore(innerSt), config.EtcdBackup{}, conf)...)
178178

@@ -182,7 +182,7 @@ func TestClusterUseEmbeddedDiscoveryServiceValidation(t *testing.T) {
182182
t.Run("disabled instance-wide - create", func(t *testing.T) {
183183
t.Parallel()
184184

185-
_, st := buildState(config.EmbeddedDiscoveryService{
185+
_, st := buildState(&config.EmbeddedDiscoveryService{
186186
Enabled: false,
187187
})
188188

@@ -202,7 +202,7 @@ func TestClusterUseEmbeddedDiscoveryServiceValidation(t *testing.T) {
202202
t.Parallel()
203203

204204
// prepare a cluster which has the feature enabled, while it is disabled instance-wide
205-
innerSt, st := buildState(config.EmbeddedDiscoveryService{
205+
innerSt, st := buildState(&config.EmbeddedDiscoveryService{
206206
Enabled: false,
207207
})
208208

@@ -231,7 +231,7 @@ func TestClusterUseEmbeddedDiscoveryServiceValidation(t *testing.T) {
231231
t.Run("enabled instance-wide", func(t *testing.T) {
232232
t.Parallel()
233233

234-
_, st := buildState(config.EmbeddedDiscoveryService{
234+
_, st := buildState(&config.EmbeddedDiscoveryService{
235235
Enabled: true,
236236
})
237237

0 commit comments

Comments
 (0)