From 26f5262b3d7fc072256d05db50d3b4f7889a975b Mon Sep 17 00:00:00 2001 From: Anton Nikiforov Date: Mon, 23 Oct 2023 18:55:07 +0300 Subject: [PATCH] [#90] Support config folder together with config file Signed-off-by: Anton Nikiforov --- README.md | 6 ++++-- examples/local.js | 2 +- examples/s3local.js | 2 +- internal/local/local.go | 29 ++++++++++++++++++----------- internal/s3local/local.go | 6 +++--- scenarios/local.js | 5 +++-- scenarios/s3local.js | 5 +++-- 7 files changed, 33 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 6e1174b..4d9a679 100644 --- a/README.md +++ b/README.md @@ -74,12 +74,13 @@ const frostfs_cli = native.connect("s01.frostfs.devenv:8080", "", 0, 0, false) Create a local client with `connect` method. Arguments: - local path to frostfs storage node configuration file +- local path to frostfs storage node configuration directory - hex encoded private key (empty value produces random key) - whether to use the debug logger (warning: very verbose) ```js import local from 'k6/x/frostfs/local'; -const local_client = local.connect("/path/to/config.yaml", "", false) +const local_client = local.connect("/path/to/config.yaml", "/path/to/config/dir", "", false) ``` ### Methods @@ -123,6 +124,7 @@ const s3_cli = s3.connect("https://s3.frostfs.devenv:8080", {'no_verify_ssl': 't Create local s3 client with `connect` method. Arguments: - local path to frostfs storage node configuration file +- local path to frostfs storage node configuration directory - parameter map with the following options: * `hex_key`: private key to use as a hexadecimal string. A random one is created if none is provided. * `node_position`: position of this node in the node array if loading multiple nodes independently (default: 0). @@ -135,7 +137,7 @@ Create local s3 client with `connect` method. Arguments: import local from 'k6/x/frostfs/local'; const params = {'node_position': 1, 'node_count': 3} const bucketMapping = {'mytestbucket': 'GBQDDUM1hdodXmiRHV57EUkFWJzuntsG8BG15wFSwam6'} -const local_client = local.connect("/path/to/config.yaml", params, bucketMapping) +const local_client = local.connect("/path/to/config.yaml", "/path/to/config/dir", params, bucketMapping) ``` ### Methods diff --git a/examples/local.js b/examples/local.js index 7e3b49a..79161b9 100644 --- a/examples/local.js +++ b/examples/local.js @@ -2,7 +2,7 @@ import local from 'k6/x/frostfs/local'; import { uuidv4 } from '../scenarios/libs/k6-utils-1.4.0.js'; const payload = open('../go.sum', 'b'); -const local_cli = local.connect("/path/to/config.yaml", "", false) +const local_cli = local.connect("/path/to/config.yaml", "/path/to/config/dir", "", false) export const options = { stages: [ diff --git a/examples/s3local.js b/examples/s3local.js index c4d3ac8..a88cb55 100644 --- a/examples/s3local.js +++ b/examples/s3local.js @@ -3,7 +3,7 @@ import { uuidv4 } from '../scenarios/libs/k6-utils-1.4.0.js'; const bucket = "testbucket" const payload = open('../go.sum', 'b'); -const s3local_cli = s3local.connect("path/to/storage/config.yml", {}, { +const s3local_cli = s3local.connect("path/to/storage/config.yml", "path/to/storage/config/dir", {}, { 'testbucket': 'GBQDDUM1hdodXmiRHV57EUkFWJzuntsG8BG15wFSwam6', }); diff --git a/internal/local/local.go b/internal/local/local.go index 0f04317..22d3f6e 100644 --- a/internal/local/local.go +++ b/internal/local/local.go @@ -40,6 +40,8 @@ type RootModule struct { mu sync.Mutex // configFile is the name of the configuration file used during one test. configFile string + // configDir is the name of the configuration directory used during one test. + configDir string // ng is the engine instance used during one test, corresponding to the configFile. Each VU // gets the same engine instance. ng *engine.StorageEngine @@ -48,7 +50,7 @@ type RootModule struct { // Local represents an instance of the module for every VU. type Local struct { vu modules.VU - ResolveEngine func(context.Context, string, bool) (*engine.StorageEngine, error) + ResolveEngine func(context.Context, string, string, bool) (*engine.StorageEngine, error) } // Ensure the interfaces are implemented correctly. @@ -71,7 +73,7 @@ func (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance { return NewLocalModuleInstance(vu, r.GetOrCreateEngine) } -func NewLocalModuleInstance(vu modules.VU, resolveEngine func(context.Context, string, bool) (*engine.StorageEngine, error)) *Local { +func NewLocalModuleInstance(vu modules.VU, resolveEngine func(context.Context, string, string, bool) (*engine.StorageEngine, error)) *Local { return &Local{ vu: vu, ResolveEngine: resolveEngine, @@ -100,21 +102,22 @@ func checkResourceLimits() error { return nil } -// GetOrCreateEngine returns the current engine instance for the given configuration file, +// GetOrCreateEngine returns the current engine instance for the given configuration file or directory, // creating a new one if none exists. Note that the identity of configuration files is their // file name for the purposes of test runs. -func (r *RootModule) GetOrCreateEngine(ctx context.Context, configFile string, debug bool) (*engine.StorageEngine, error) { +func (r *RootModule) GetOrCreateEngine(ctx context.Context, configFile string, configDir string, debug bool) (*engine.StorageEngine, error) { r.mu.Lock() defer r.mu.Unlock() - if len(configFile) == 0 { - return nil, errors.New("configFile cannot be empty") + if len(configFile) == 0 && len(configDir) == 0 { + return nil, errors.New("provide configFile or configDir") } // Create and initialize engine for the given configFile if it doesn't exist already if r.ng == nil { r.configFile = configFile - appCfg := config.New(configFile, "", "") + r.configDir = configDir + appCfg := config.New(configFile, configDir, "") ngOpts, shardOpts, err := storageEngineOptionsFromConfig(appCfg, debug) if err != nil { return nil, fmt.Errorf("creating engine options from config: %v", err) @@ -135,7 +138,11 @@ func (r *RootModule) GetOrCreateEngine(ctx context.Context, configFile string, d return nil, fmt.Errorf("initializing engine: %v", err) } } else if configFile != r.configFile { - return nil, fmt.Errorf("GetOrCreateEngine called with mismatching configFile after engine was initialized: got %q, want %q", configFile, r.configFile) + return nil, fmt.Errorf("GetOrCreateEngine called with mismatching configFile after engine was "+ + "initialized: got %q, want %q", configFile, r.configFile) + } else if configDir != r.configDir { + return nil, fmt.Errorf("GetOrCreateEngine called with mismatching configDir after engine was "+ + "initialized: got %q, want %q", configDir, r.configDir) } return r.ng, nil @@ -149,10 +156,10 @@ func (s *Local) Exports() modules.Exports { func (s *Local) VU() modules.VU { return s.vu } -func (s *Local) Connect(configFile, hexKey string, debug bool) (*Client, error) { - ng, err := s.ResolveEngine(s.VU().Context(), configFile, debug) +func (s *Local) Connect(configFile, configDir, hexKey string, debug bool) (*Client, error) { + ng, err := s.ResolveEngine(s.VU().Context(), configFile, configDir, debug) if err != nil { - return nil, fmt.Errorf("connecting to engine for config %q: %v", configFile, err) + return nil, fmt.Errorf("connecting to engine for config - file %q dir %q: %v", configFile, configDir, err) } key, err := ParseOrCreateKey(hexKey) diff --git a/internal/s3local/local.go b/internal/s3local/local.go index 2d8b8c3..531ac15 100644 --- a/internal/s3local/local.go +++ b/internal/s3local/local.go @@ -56,7 +56,7 @@ func (s *Local) Exports() modules.Exports { return modules.Exports{Default: s} } -func (s *Local) Connect(configFile string, params map[string]string, bucketMapping map[string]string) (*Client, error) { +func (s *Local) Connect(configFile string, configDir string, params map[string]string, bucketMapping map[string]string) (*Client, error) { // Parse configuration flags. fs := flag.NewFlagSet("s3local", flag.ContinueOnError) @@ -107,9 +107,9 @@ func (s *Local) Connect(configFile string, params map[string]string, bucketMappi objGetDuration, _ = registry.NewMetric("s3local_obj_get_duration", metrics.Trend, metrics.Time) // Create S3 layer backed by local storage engine and tree service. - ng, err := s.l.ResolveEngine(s.l.VU().Context(), configFile, *debugLogger) + ng, err := s.l.ResolveEngine(s.l.VU().Context(), configFile, configDir, *debugLogger) if err != nil { - return nil, fmt.Errorf("connecting to engine for config %q: %v", configFile, err) + return nil, fmt.Errorf("connecting to engine for config - file %q dir %q: %v", configFile, configDir, err) } treeSvc := tree.NewTree(treeServiceEngineWrapper{ diff --git a/scenarios/local.js b/scenarios/local.js index 0deb231..d706ee3 100644 --- a/scenarios/local.js +++ b/scenarios/local.js @@ -21,9 +21,10 @@ const read_size = JSON.parse(open(__ENV.PREGEN_JSON)).obj_size; const summary_json = __ENV.SUMMARY_JSON || "/tmp/summary.json"; const config_file = __ENV.CONFIG_FILE; +const config_dir = __ENV.CONFIG_DIR; const debug_logger = (__ENV.DEBUG_LOGGER || 'false') == 'true'; -const local_client = local.connect(config_file, '', debug_logger); -const log = logging.new().withField("config", config_file); +const local_client = local.connect(config_file, config_dir, '', debug_logger); +const log = logging.new().withFields({"config_file": config_file,"config_dir": config_dir}); const registry_enabled = !!__ENV.REGISTRY_FILE; const obj_registry = registry_enabled ? registry.open(__ENV.REGISTRY_FILE) : undefined; diff --git a/scenarios/s3local.js b/scenarios/s3local.js index aa9b54d..d058b33 100644 --- a/scenarios/s3local.js +++ b/scenarios/s3local.js @@ -36,10 +36,11 @@ const read_size = JSON.parse(open(__ENV.PREGEN_JSON)).obj_size; const summary_json = __ENV.SUMMARY_JSON || "/tmp/summary.json"; const config_file = __ENV.CONFIG_FILE; -const s3_client = s3local.connect(config_file, { +const config_dir = __ENV.CONFIG_DIR; +const s3_client = s3local.connect(config_file, config_dir, { 'debug_logger': __ENV.DEBUG_LOGGER || 'false', }, bucket_mapping()); -const log = logging.new().withField("config", config_file); +const log = logging.new().withFields({"config_file": config_file,"config_dir": config_dir}); const registry_enabled = !!__ENV.REGISTRY_FILE; const obj_registry = registry_enabled ? registry.open(__ENV.REGISTRY_FILE) : undefined;