diff --git a/cli/cmd/build.go b/cli/cmd/build.go index efcf195c3..02312b06d 100644 --- a/cli/cmd/build.go +++ b/cli/cmd/build.go @@ -30,7 +30,8 @@ func NewBuildCmd() *cobra.Command { args []string, toComplete string) ([]string, cobra.ShellCompDirective) { var runningCtx running.RunningCtx - if err := running.FillCtx(cliOpts, &cmdCtx, &runningCtx, nil, false); err != nil { + err := running.FillCtx(cliOpts, &cmdCtx, &runningCtx, nil, running.ConfigLoadSkip) + if err != nil { return nil, cobra.ShellCompDirectiveNoFileComp } return running.ExtractAppNames(runningCtx.Instances), diff --git a/cli/cmd/check.go b/cli/cmd/check.go index b5aed35b5..26d0727c6 100644 --- a/cli/cmd/check.go +++ b/cli/cmd/check.go @@ -32,7 +32,8 @@ func internalCheckModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { } var runningCtx running.RunningCtx - if err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, true); err != nil { + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, running.ConfigLoadAll) + if err != nil { return err } diff --git a/cli/cmd/clean.go b/cli/cmd/clean.go index db69c186c..3327602a0 100644 --- a/cli/cmd/clean.go +++ b/cli/cmd/clean.go @@ -104,7 +104,8 @@ func internalCleanModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { } var runningCtx running.RunningCtx - if err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, false); err != nil { + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, running.ConfigLoadCluster) + if err != nil { return err } diff --git a/cli/cmd/cluster.go b/cli/cmd/cluster.go index d317c655b..62323f7bc 100644 --- a/cli/cmd/cluster.go +++ b/cli/cmd/cluster.go @@ -673,7 +673,8 @@ func parseAppStr(cmdCtx *cmdcontext.CmdCtx, appStr string) (string, string, stri // Fill context for the entire application. // publish app:inst can work even if the `inst` instance doesn't exist right now. var runningCtx running.RunningCtx - err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, []string{appName}, false) + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, []string{appName}, + running.ConfigLoadCluster) if err != nil { return "", "", "", err } diff --git a/cli/cmd/connect.go b/cli/cmd/connect.go index 65e6b819a..e91b7dc52 100644 --- a/cli/cmd/connect.go +++ b/cli/cmd/connect.go @@ -138,7 +138,8 @@ func resolveConnectOpts(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts, // FillCtx returns error if no instances found. var runningCtx running.RunningCtx - fillErr := running.FillCtx(cliOpts, cmdCtx, &runningCtx, []string{target}, false) + fillErr := running.FillCtx(cliOpts, cmdCtx, &runningCtx, []string{target}, + running.ConfigLoadCluster) if fillErr == nil { if len(runningCtx.Instances) > 1 { err = fmt.Errorf("specify instance name") diff --git a/cli/cmd/internal/completion.go b/cli/cmd/internal/completion.go index 17bfd15f5..799b76f17 100644 --- a/cli/cmd/internal/completion.go +++ b/cli/cmd/internal/completion.go @@ -26,7 +26,8 @@ func ValidArgsFunction( directive = cobra.ShellCompDirectiveNoFileComp var runningCtx running.RunningCtx - if err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, nil, false); err != nil { + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, nil, running.ConfigLoadSkip) + if err != nil { return } diff --git a/cli/cmd/kill.go b/cli/cmd/kill.go index fbee974c3..c4d3d10b4 100644 --- a/cli/cmd/kill.go +++ b/cli/cmd/kill.go @@ -78,7 +78,8 @@ func internalKillModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { if confirm { var runningCtx running.RunningCtx - if err = running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, false); err != nil { + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, running.ConfigLoadSkip) + if err != nil { return err } diff --git a/cli/cmd/log.go b/cli/cmd/log.go index bbff37ccf..eaaa2f8d2 100644 --- a/cli/cmd/log.go +++ b/cli/cmd/log.go @@ -133,7 +133,8 @@ func internalLogModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { var err error var runningCtx running.RunningCtx - if err = running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, false); err != nil { + err = running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, running.ConfigLoadCluster) + if err != nil { return err } diff --git a/cli/cmd/logrotate.go b/cli/cmd/logrotate.go index 00b70f484..cf267c42a 100644 --- a/cli/cmd/logrotate.go +++ b/cli/cmd/logrotate.go @@ -42,7 +42,8 @@ func internalLogrotateModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { } var runningCtx running.RunningCtx - if err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, false); err != nil { + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, running.ConfigLoadSkip) + if err != nil { return err } diff --git a/cli/cmd/play.go b/cli/cmd/play.go index 58f0de611..22c92220e 100644 --- a/cli/cmd/play.go +++ b/cli/cmd/play.go @@ -98,8 +98,8 @@ func internalPlayModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { // FillCtx returns error if no instances found. var runningCtx running.RunningCtx - - if err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, []string{args[0]}, false); err == nil { + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, []string{args[0]}, running.ConfigLoadAll) + if err == nil { if len(runningCtx.Instances) > 1 { return util.InternalError( "Internal error: specify instance name", diff --git a/cli/cmd/replicaset.go b/cli/cmd/replicaset.go index 0b2548256..c2f2c9177 100644 --- a/cli/cmd/replicaset.go +++ b/cli/cmd/replicaset.go @@ -475,7 +475,7 @@ type replicasetCtx struct { // replicasetFillCtx fills the replicaset command context. func replicasetFillCtx(cmdCtx *cmdcontext.CmdCtx, ctx *replicasetCtx, target string, - isRunningCtxRequired bool) error { + isRunningCtxRequired bool, loadConfig running.ConfigLoad) error { var err error ctx.Orchestrator, err = getOrchestrator() if err != nil { @@ -491,8 +491,7 @@ func replicasetFillCtx(cmdCtx *cmdcontext.CmdCtx, ctx *replicasetCtx, target str SslCiphers: replicasetSslCiphers, } var connOpts connector.ConnectOpts - - err = running.FillCtx(cliOpts, cmdCtx, &ctx.RunningCtx, []string{target}, false) + err = running.FillCtx(cliOpts, cmdCtx, &ctx.RunningCtx, []string{target}, loadConfig) if err == nil { ctx.IsApplication = true if len(ctx.RunningCtx.Instances) == 1 { @@ -514,7 +513,8 @@ func replicasetFillCtx(cmdCtx *cmdcontext.CmdCtx, ctx *replicasetCtx, target str } // Re-fill context for an application. ctx.InstName = instName - err := running.FillCtx(cliOpts, cmdCtx, &ctx.RunningCtx, []string{appName}, false) + err := running.FillCtx(cliOpts, cmdCtx, &ctx.RunningCtx, []string{appName}, + loadConfig) if err != nil { // Should not happen. return err @@ -572,7 +572,7 @@ func replicasetFillCtx(cmdCtx *cmdcontext.CmdCtx, ctx *replicasetCtx, target str // internalReplicasetUpgradeModule is a "upgrade" command for the replicaset module. func internalReplicasetUpgradeModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false, running.ConfigLoadAll); err != nil { return err } if ctx.IsInstanceConnect { @@ -607,7 +607,7 @@ func internalReplicasetDowngradeModule(cmdCtx *cmdcontext.CmdCtx, args []string) downgradeVersion := args[1] var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, target, false); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false, running.ConfigLoadAll); err != nil { return err } if ctx.IsInstanceConnect { @@ -640,7 +640,7 @@ func internalReplicasetDowngradeModule(cmdCtx *cmdcontext.CmdCtx, args []string) // internalReplicasetPromoteModule is a "promote" command for the replicaset module. func internalReplicasetPromoteModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false, running.ConfigLoadAll); err != nil { return err } if !ctx.IsInstanceConnect { @@ -670,7 +670,7 @@ func internalReplicasetPromoteModule(cmdCtx *cmdcontext.CmdCtx, args []string) e // internalReplicasetDemoteModule is a "demote" command for the replicaset module. func internalReplicasetDemoteModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], true); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], true, running.ConfigLoadAll); err != nil { return err } if !ctx.IsApplication { @@ -702,7 +702,7 @@ func internalReplicasetDemoteModule(cmdCtx *cmdcontext.CmdCtx, args []string) er // internalReplicasetStatusModule is a "status" command for the replicaset module. func internalReplicasetStatusModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false, running.ConfigLoadSkip); err != nil { return err } if ctx.IsInstanceConnect { @@ -722,7 +722,7 @@ func internalReplicasetExpelModule(cmdCtx *cmdcontext.CmdCtx, args []string) err return fmt.Errorf("the command expects argument application_name:instance_name") } var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], true); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], true, running.ConfigLoadAll); err != nil { return err } if ctx.IsInstanceConnect { @@ -749,7 +749,7 @@ func internalReplicasetExpelModule(cmdCtx *cmdcontext.CmdCtx, args []string) err // the "replicaset vshard" module. func internalReplicasetBootstrapVShardModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false, running.ConfigLoadAll); err != nil { return err } if ctx.IsInstanceConnect { @@ -776,7 +776,7 @@ func internalReplicasetBootstrapModule(cmdCtx *cmdcontext.CmdCtx, args []string) _, instName, found := strings.Cut(args[0], string(running.InstanceDelimiter)) var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], true); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], true, running.ConfigLoadAll); err != nil { return err } if ctx.IsInstanceConnect { @@ -838,7 +838,7 @@ func internalReplicasetRebootstrapModule(cmdCtx *cmdcontext.CmdCtx, args []strin // internalReplicasetRolesAddModule is a "roles add" command for the replicaset module. func internalReplicasetRolesAddModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false, running.ConfigLoadAll); err != nil { return err } defer ctx.Conn.Close() @@ -881,7 +881,7 @@ func internalReplicasetRolesAddModule(cmdCtx *cmdcontext.CmdCtx, args []string) // internalReplicasetRolesRemoveModule is a "roles remove" command for the replicaset module. func internalReplicasetRolesRemoveModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { var ctx replicasetCtx - if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false); err != nil { + if err := replicasetFillCtx(cmdCtx, &ctx, args[0], false, running.ConfigLoadAll); err != nil { return err } defer ctx.Conn.Close() diff --git a/cli/cmd/start.go b/cli/cmd/start.go index 9ef374529..2984e3d0f 100644 --- a/cli/cmd/start.go +++ b/cli/cmd/start.go @@ -127,7 +127,8 @@ func internalStartModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { } var runningCtx running.RunningCtx - if err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, true); err != nil { + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, running.ConfigLoadAll) + if err != nil { return err } diff --git a/cli/cmd/status.go b/cli/cmd/status.go index afa332a06..9257d501f 100644 --- a/cli/cmd/status.go +++ b/cli/cmd/status.go @@ -62,10 +62,11 @@ func internalStatusModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { } var runningCtx running.RunningCtx - if err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, false); err != nil { + err := running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, running.ConfigLoadSkip) + if err != nil { return err } - err := status.Status(runningCtx, opts) + err = status.Status(runningCtx, opts) return err } diff --git a/cli/cmd/stop.go b/cli/cmd/stop.go index 65a6a48b8..0c49a36be 100644 --- a/cli/cmd/stop.go +++ b/cli/cmd/stop.go @@ -2,6 +2,8 @@ package cmd import ( "fmt" + "os" + "github.com/apex/log" "github.com/spf13/cobra" "github.com/tarantool/tt/cli/cmd/internal" @@ -9,7 +11,6 @@ import ( "github.com/tarantool/tt/cli/modules" "github.com/tarantool/tt/cli/running" "github.com/tarantool/tt/cli/util" - "os" ) // NewStopCmd creates stop command. @@ -78,8 +79,8 @@ func internalStopModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { } var runningCtx running.RunningCtx - var err error - if err = running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, false); err != nil { + var err error = running.FillCtx(cliOpts, cmdCtx, &runningCtx, args, running.ConfigLoadSkip) + if err != nil { return err } diff --git a/cli/instances/list.go b/cli/instances/list.go index 3e0fe1bec..291f15ba4 100644 --- a/cli/instances/list.go +++ b/cli/instances/list.go @@ -31,7 +31,7 @@ func ListInstances(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts) error { fmt.Printf("instances enabled directory: %s\n", cliOpts.Env.InstancesEnabled) applications, err := running.CollectInstancesForApps(appList, cliOpts, cmdCtx.Cli.ConfigDir, - cmdCtx.Integrity, false) + cmdCtx.Integrity, running.ConfigLoadSkip) if err != nil { return err } diff --git a/cli/pack/opts.go b/cli/pack/opts.go index 8212e7a69..714fc5230 100644 --- a/cli/pack/opts.go +++ b/cli/pack/opts.go @@ -49,7 +49,7 @@ func initAppsInfo(cliOpts *config.CliOpts, cmdCtx *cmdcontext.CmdCtx, packCtx *P } packCtx.AppList = appList packCtx.AppsInfo, err = running.CollectInstancesForApps(packCtx.AppList, cliOpts, - cmdCtx.Cli.ConfigDir, cmdCtx.Integrity, false) + cmdCtx.Cli.ConfigDir, cmdCtx.Integrity, running.ConfigLoadScripts) if err != nil { return fmt.Errorf("failed to collect applications info: %s", err) } diff --git a/cli/replicaset/rebootstrap.go b/cli/replicaset/rebootstrap.go index a2e87b0ec..c55437150 100644 --- a/cli/replicaset/rebootstrap.go +++ b/cli/replicaset/rebootstrap.go @@ -60,7 +60,7 @@ func cleanDataFiles(instCtx running.InstanceCtx) error { // and starting it again. func Rebootstrap(cmdCtx cmdcontext.CmdCtx, cliOpts config.CliOpts, rbCtx RebootstrapCtx) error { apps, err := running.CollectInstancesForApps([]string{rbCtx.AppName}, &cliOpts, - cmdCtx.Cli.ConfigDir, cmdCtx.Integrity, true) + cmdCtx.Cli.ConfigDir, cmdCtx.Integrity, running.ConfigLoadAll) if err != nil { return fmt.Errorf("cannot collect application instances info: %s", err) } diff --git a/cli/running/running.go b/cli/running/running.go index 9348ab78b..58f1a05f6 100644 --- a/cli/running/running.go +++ b/cli/running/running.go @@ -126,6 +126,22 @@ type providerImpl struct { instanceCtx *InstanceCtx } +// ConfigLoad defines an enumeration of instance script and cluster configuration load types. +type ConfigLoad int + +const ( + // Skip loading cluster config and instances scripts. + ConfigLoadSkip ConfigLoad = iota + // Cluster configuration is required, trigger an error if not. + // Instances scripts could be omitted. + ConfigLoadCluster + // Instance script is required, trigger an error if not. + // Cluster configuration could be omitted. + ConfigLoadScripts + // Load cluster config and instances scripts, trigger an errors if not. + ConfigLoadAll +) + // GetAppPath return application path for the instance. It is a script file path in case of // single instance file-only app, or directory in case of directory-based application. func GetAppPath(instance InstanceCtx) string { @@ -152,7 +168,8 @@ func (provider *providerImpl) updateCtx() error { } var runningCtx RunningCtx - if err = FillCtx(cliOpts, provider.cmdCtx, &runningCtx, args, false); err != nil { + if err = FillCtx( + cliOpts, provider.cmdCtx, &runningCtx, args, ConfigLoadSkip); err != nil { return err } provider.instanceCtx = &runningCtx.Instances[0] @@ -348,7 +365,7 @@ func loadInstanceConfig(configPath, instName string, // collectInstancesFromAppDir collects instances information from application directory. func collectInstancesFromAppDir(appDir string, selectedInstName string, - integrityCtx integrity.IntegrityCtx, configRequired bool) ( + integrityCtx integrity.IntegrityCtx, loadConfig ConfigLoad) ( []InstanceCtx, error, ) { @@ -376,7 +393,7 @@ func collectInstancesFromAppDir(appDir string, selectedInstName string, InstName: filepath.Base(appDir), AppDir: appDir, SingleApp: true}}, nil - } else if configRequired { + } else if loadConfig == ConfigLoadAll || loadConfig == ConfigLoadScripts { return nil, fmt.Errorf("require files are missing in application directory %q: "+ "there must be instances config or the default instance script (%q)", appDir, "init.lua") @@ -409,19 +426,21 @@ func collectInstancesFromAppDir(appDir string, selectedInstName string, } log.Debugf("Instance %q", instance.InstName) - if instance.Configuration, err = loadInstanceConfig(instance.ClusterConfigPath, - instance.InstName, integrityCtx); err != nil && configRequired { + instance.Configuration, err = loadInstanceConfig(instance.ClusterConfigPath, + instance.InstName, integrityCtx) + if err != nil && (loadConfig == ConfigLoadAll || loadConfig == ConfigLoadCluster) { return instances, fmt.Errorf("error loading instance %q configuration from "+ "config %q: %w", instance.InstName, instance.ClusterConfigPath, err) } instance.SingleApp = false - if instance.InstanceScript, err = findInstanceScriptInAppDir(appDir, instance.InstName, - appDirFiles.clusterCfgPath, appDirFiles.defaultLuaPath); err != nil && - configRequired { + instance.InstanceScript, err = findInstanceScriptInAppDir(appDir, instance.InstName, + appDirFiles.clusterCfgPath, appDirFiles.defaultLuaPath) + if err != nil && (loadConfig == ConfigLoadAll || loadConfig == ConfigLoadScripts) { return instances, fmt.Errorf("cannot find instance script for %q in config %q: %w ", instance.InstName, appDirFiles.clusterCfgPath, err) } + instances = append(instances, instance) } @@ -434,7 +453,9 @@ func collectInstancesFromAppDir(appDir string, selectedInstName string, // CollectInstances searches all instances available in application. func CollectInstances(appName string, applicationsDir string, - integrityCtx integrity.IntegrityCtx, configRequired bool) ([]InstanceCtx, error) { + integrityCtx integrity.IntegrityCtx, loadConfig ConfigLoad) ( + []InstanceCtx, error, +) { // The user can select a specific instance from the application. // Example: `tt status application:server`. selectedInstName := "" @@ -462,8 +483,7 @@ func CollectInstances(appName string, applicationsDir string, appDir = applicationsDir } - return collectInstancesFromAppDir(appDir, selectedInstName, integrityCtx, - configRequired) + return collectInstancesFromAppDir(appDir, selectedInstName, integrityCtx, loadConfig) } // cleanup removes runtime artifacts. @@ -625,7 +645,7 @@ func GetClusterConfigPath(cliOpts *config.CliOpts, // CollectInstancesForApps collects instances information per application. func CollectInstancesForApps(appList []string, cliOpts *config.CliOpts, - ttConfigDir string, integrityCtx integrity.IntegrityCtx, configRequired bool) ( + ttConfigDir string, integrityCtx integrity.IntegrityCtx, loadConfig ConfigLoad) ( map[string][]InstanceCtx, error) { instEnabledPath := cliOpts.Env.InstancesEnabled if cliOpts.Env.InstancesEnabled == "." { @@ -635,7 +655,7 @@ func CollectInstancesForApps(appList []string, cliOpts *config.CliOpts, for _, appName := range appList { appName = strings.TrimSuffix(appName, ".lua") collectedInstances, err := CollectInstances(appName, instEnabledPath, integrityCtx, - configRequired) + loadConfig) if err != nil { return apps, fmt.Errorf("can't collect instance information for %s: %w", appName, err) @@ -676,7 +696,7 @@ func createInstanceDataDirectories(instance InstanceCtx) error { // FillCtx fills the RunningCtx context. func FillCtx(cliOpts *config.CliOpts, cmdCtx *cmdcontext.CmdCtx, - runningCtx *RunningCtx, args []string, configRequired bool) error { + runningCtx *RunningCtx, args []string, loadConfig ConfigLoad) error { var err error if len(args) > 1 && cmdCtx.CommandName != "run" && cmdCtx.CommandName != "connect" && @@ -702,8 +722,8 @@ func FillCtx(cliOpts *config.CliOpts, cmdCtx *cmdcontext.CmdCtx, appList = append(appList, args[0]) } - instances, err := CollectInstancesForApps(appList, cliOpts, - cmdCtx.Cli.ConfigDir, cmdCtx.Integrity, configRequired) + instances, err := CollectInstancesForApps(appList, cliOpts, cmdCtx.Cli.ConfigDir, + cmdCtx.Integrity, loadConfig) if err != nil { return err } diff --git a/cli/running/running_test.go b/cli/running/running_test.go index aca2f4097..4215dc8ce 100644 --- a/cli/running/running_test.go +++ b/cli/running/running_test.go @@ -35,7 +35,7 @@ func Test_CollectInstances(t *testing.T) { instances, err := CollectInstances("script", instancesEnabledPath, integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) require.NoError(t, err) require.Equal(t, 1, len(instances)) require.Equal(t, InstanceCtx{ @@ -50,7 +50,7 @@ func Test_CollectInstances(t *testing.T) { instances, err = CollectInstances("single_inst", instancesEnabledPath, integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) require.NoError(t, err) require.Equal(t, 1, len(instances)) require.Equal(t, InstanceCtx{ @@ -67,7 +67,7 @@ func Test_CollectInstances(t *testing.T) { instances, err = CollectInstances(appName, instancesEnabledPath, integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) require.NoError(t, err) require.Equal(t, 3, len(instances)) assert.True(t, slices.Contains(instances, InstanceCtx{ @@ -103,7 +103,7 @@ func Test_CollectInstances(t *testing.T) { instances, err = CollectInstances("script", instancesEnabledPath, integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) assert.ErrorContains(t, err, "script\" doesn't exist or not a directory") assert.Equal(t, 0, len(instances)) @@ -113,7 +113,7 @@ func Test_CollectInstances(t *testing.T) { instances, err = CollectInstances("script", instancesEnabledPath, integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) assert.NoError(t, err) assert.Equal(t, 1, len(instances)) @@ -121,12 +121,112 @@ func Test_CollectInstances(t *testing.T) { instances, err = CollectInstances("script", instancesEnabledPath, integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) assert.ErrorContains(t, err, "script.lua: permission denied") assert.Equal(t, 1, len(instances)) require.NoError(t, os.Chmod(instancesEnabledPath, 0755)) } +func Test_CollectInstancesInstanceScript(t *testing.T) { + if user, err := user.Current(); err == nil && user.Uid == "0" { + t.Skip("Skipping the test, it shouldn't run as root") + } + tmpDir := t.TempDir() + instancesEnabledPath := filepath.Join(tmpDir, "instances.enabled") + require.NoError(t, os.Mkdir(instancesEnabledPath, 0755)) + + err := os.WriteFile(filepath.Join(instancesEnabledPath, "script.lua"), + []byte("print(42)"), 0644) + require.NoError(t, err) + + cases := []struct { + access os.FileMode + mode ConfigLoad + err string + }{ + { + access: 0666, + mode: ConfigLoadAll, + err: "script.lua: permission denied", + }, + { + access: 0666, + mode: ConfigLoadScripts, + err: "script.lua: permission denied", + }, + { + access: 0755, + mode: ConfigLoadSkip, + }, + { + access: 0755, + mode: ConfigLoadCluster, + }, + { + access: 0755, + mode: ConfigLoadAll, + }, + } + + for _, tc := range cases { + t.Run("test", func(t *testing.T) { + require.NoError(t, os.Chmod(instancesEnabledPath, tc.access)) + instances, err := CollectInstances("script", instancesEnabledPath, + integrity.IntegrityCtx{ + Repository: &mockRepository{}, + }, tc.mode) + if tc.err != "" { + assert.ErrorContains(t, err, tc.err) + } else { + assert.NoError(t, err) + assert.Equal(t, 1, len(instances)) + } + require.NoError(t, os.Chmod(instancesEnabledPath, 0755)) + }) + } +} + +func Test_CollectInstancesEtcdNotAvailable(t *testing.T) { + if user, err := user.Current(); err == nil && user.Uid == "0" { + t.Skip("Skipping the test, it shouldn't run as root") + } + instancesEnabledPath := filepath.Join("testdata", "instances_enabled") + + cases := []struct { + mode ConfigLoad + err string + }{ + { + mode: ConfigLoadAll, + err: "unable to connect to etcd", + }, + { + mode: ConfigLoadCluster, + err: "unable to connect to etcd", + }, + { + mode: ConfigLoadScripts, + }, + { + mode: ConfigLoadSkip, + }, + } + + for _, tc := range cases { + t.Run(tc.err, func(t *testing.T) { + _, err := CollectInstances("config_load", instancesEnabledPath, + integrity.IntegrityCtx{ + Repository: &mockRepository{}, + }, tc.mode) + if tc.err != "" { + assert.ErrorContains(t, err, tc.err) + } else { + assert.NoError(t, err) + } + }) + } +} + func Test_collectAppDirFiles(t *testing.T) { tmpdir := t.TempDir() @@ -189,7 +289,7 @@ func Test_collectInstancesForApps(t *testing.T) { instances, err := CollectInstancesForApps(apps, cliOpts, "/etc/tarantool/", integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) require.NoError(t, err) require.Contains(t, instances, appName) @@ -316,7 +416,7 @@ func Test_collectInstancesForSingleInstApp(t *testing.T) { instances, err := CollectInstancesForApps(apps, cliOpts, "/etc/tarantool/", integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) require.NoError(t, err) require.Equal(t, 1, len(instances)) require.Contains(t, instances, appName) @@ -347,7 +447,7 @@ func Test_collectInstancesSingleInstanceTntCtlLayout(t *testing.T) { instances, err := CollectInstancesForApps(apps, cliOpts, cfgDir, integrity.IntegrityCtx{ Repository: &mockRepository{}, - }, true) + }, ConfigLoadAll) require.NoError(t, err) require.Len(t, instances, 1) require.Contains(t, instances, appName) diff --git a/cli/running/testdata/instances_enabled/config_load/config.yml b/cli/running/testdata/instances_enabled/config_load/config.yml new file mode 100644 index 000000000..32de03818 --- /dev/null +++ b/cli/running/testdata/instances_enabled/config_load/config.yml @@ -0,0 +1,46 @@ +credentials: + users: + guest: + roles: [super] + +iproto: + listen: + - uri: 'unix/:./{{ instance_name }}.iproto' + +groups: + group-001: + replicasets: + replicaset-001: + instances: + instance-001: + database: + mode: rw + replicaset-002: + instances: + instance-002: + console: + socket: ./{{instance_name}}.control + wal: + dir: ./{{instance_name}}_wal_dir + database: + mode: rw + replicaset-003: + instances: + instance-003: + snapshot: + dir: ./{{ instance_name }}_snap_dir + vinyl: + dir: ./{{ instance_name }}_vinyl_dir + database: + mode: rw + +config: + etcd: + endpoints: + - http://localhost:2379 + prefix: /test_app + username: client + password: secret + http: + request: + timeout: 3 diff --git a/cli/running/testdata/instances_enabled/config_load/instances.yml b/cli/running/testdata/instances_enabled/config_load/instances.yml new file mode 100644 index 000000000..c9e5954a9 --- /dev/null +++ b/cli/running/testdata/instances_enabled/config_load/instances.yml @@ -0,0 +1,3 @@ +instance-001: +instance-002: +instance-003: