forked from TrueCloudLab/xk6-frostfs
[#90] Support config folder together with config file
Signed-off-by: Anton Nikiforov <an.nikiforov@yadro.com>
This commit is contained in:
parent
95ce6f1162
commit
26f5262b3d
7 changed files with 33 additions and 22 deletions
|
@ -74,12 +74,13 @@ const frostfs_cli = native.connect("s01.frostfs.devenv:8080", "", 0, 0, false)
|
||||||
|
|
||||||
Create a local client with `connect` method. Arguments:
|
Create a local client with `connect` method. Arguments:
|
||||||
- local path to frostfs storage node configuration file
|
- 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)
|
- hex encoded private key (empty value produces random key)
|
||||||
- whether to use the debug logger (warning: very verbose)
|
- whether to use the debug logger (warning: very verbose)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import local from 'k6/x/frostfs/local';
|
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
|
### 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:
|
Create local s3 client with `connect` method. Arguments:
|
||||||
- local path to frostfs storage node configuration file
|
- local path to frostfs storage node configuration file
|
||||||
|
- local path to frostfs storage node configuration directory
|
||||||
- parameter map with the following options:
|
- 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.
|
* `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).
|
* `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';
|
import local from 'k6/x/frostfs/local';
|
||||||
const params = {'node_position': 1, 'node_count': 3}
|
const params = {'node_position': 1, 'node_count': 3}
|
||||||
const bucketMapping = {'mytestbucket': 'GBQDDUM1hdodXmiRHV57EUkFWJzuntsG8BG15wFSwam6'}
|
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
|
### Methods
|
||||||
|
|
|
@ -2,7 +2,7 @@ import local from 'k6/x/frostfs/local';
|
||||||
import { uuidv4 } from '../scenarios/libs/k6-utils-1.4.0.js';
|
import { uuidv4 } from '../scenarios/libs/k6-utils-1.4.0.js';
|
||||||
|
|
||||||
const payload = open('../go.sum', 'b');
|
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 = {
|
export const options = {
|
||||||
stages: [
|
stages: [
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { uuidv4 } from '../scenarios/libs/k6-utils-1.4.0.js';
|
||||||
|
|
||||||
const bucket = "testbucket"
|
const bucket = "testbucket"
|
||||||
const payload = open('../go.sum', 'b');
|
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',
|
'testbucket': 'GBQDDUM1hdodXmiRHV57EUkFWJzuntsG8BG15wFSwam6',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ type RootModule struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
// configFile is the name of the configuration file used during one test.
|
// configFile is the name of the configuration file used during one test.
|
||||||
configFile string
|
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
|
// ng is the engine instance used during one test, corresponding to the configFile. Each VU
|
||||||
// gets the same engine instance.
|
// gets the same engine instance.
|
||||||
ng *engine.StorageEngine
|
ng *engine.StorageEngine
|
||||||
|
@ -48,7 +50,7 @@ type RootModule struct {
|
||||||
// Local represents an instance of the module for every VU.
|
// Local represents an instance of the module for every VU.
|
||||||
type Local struct {
|
type Local struct {
|
||||||
vu modules.VU
|
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.
|
// Ensure the interfaces are implemented correctly.
|
||||||
|
@ -71,7 +73,7 @@ func (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {
|
||||||
return NewLocalModuleInstance(vu, r.GetOrCreateEngine)
|
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{
|
return &Local{
|
||||||
vu: vu,
|
vu: vu,
|
||||||
ResolveEngine: resolveEngine,
|
ResolveEngine: resolveEngine,
|
||||||
|
@ -100,21 +102,22 @@ func checkResourceLimits() error {
|
||||||
return nil
|
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
|
// creating a new one if none exists. Note that the identity of configuration files is their
|
||||||
// file name for the purposes of test runs.
|
// 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()
|
r.mu.Lock()
|
||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
|
|
||||||
if len(configFile) == 0 {
|
if len(configFile) == 0 && len(configDir) == 0 {
|
||||||
return nil, errors.New("configFile cannot be empty")
|
return nil, errors.New("provide configFile or configDir")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and initialize engine for the given configFile if it doesn't exist already
|
// Create and initialize engine for the given configFile if it doesn't exist already
|
||||||
if r.ng == nil {
|
if r.ng == nil {
|
||||||
r.configFile = configFile
|
r.configFile = configFile
|
||||||
appCfg := config.New(configFile, "", "")
|
r.configDir = configDir
|
||||||
|
appCfg := config.New(configFile, configDir, "")
|
||||||
ngOpts, shardOpts, err := storageEngineOptionsFromConfig(appCfg, debug)
|
ngOpts, shardOpts, err := storageEngineOptionsFromConfig(appCfg, debug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("creating engine options from config: %v", err)
|
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)
|
return nil, fmt.Errorf("initializing engine: %v", err)
|
||||||
}
|
}
|
||||||
} else if configFile != r.configFile {
|
} 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
|
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) VU() modules.VU { return s.vu }
|
||||||
|
|
||||||
func (s *Local) Connect(configFile, hexKey string, debug bool) (*Client, error) {
|
func (s *Local) Connect(configFile, configDir, hexKey string, debug bool) (*Client, error) {
|
||||||
ng, err := s.ResolveEngine(s.VU().Context(), configFile, debug)
|
ng, err := s.ResolveEngine(s.VU().Context(), configFile, configDir, debug)
|
||||||
if err != nil {
|
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)
|
key, err := ParseOrCreateKey(hexKey)
|
||||||
|
|
|
@ -56,7 +56,7 @@ func (s *Local) Exports() modules.Exports {
|
||||||
return modules.Exports{Default: s}
|
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.
|
// Parse configuration flags.
|
||||||
fs := flag.NewFlagSet("s3local", flag.ContinueOnError)
|
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)
|
objGetDuration, _ = registry.NewMetric("s3local_obj_get_duration", metrics.Trend, metrics.Time)
|
||||||
|
|
||||||
// Create S3 layer backed by local storage engine and tree service.
|
// 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 {
|
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{
|
treeSvc := tree.NewTree(treeServiceEngineWrapper{
|
||||||
|
|
|
@ -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 summary_json = __ENV.SUMMARY_JSON || "/tmp/summary.json";
|
||||||
|
|
||||||
const config_file = __ENV.CONFIG_FILE;
|
const config_file = __ENV.CONFIG_FILE;
|
||||||
|
const config_dir = __ENV.CONFIG_DIR;
|
||||||
const debug_logger = (__ENV.DEBUG_LOGGER || 'false') == 'true';
|
const debug_logger = (__ENV.DEBUG_LOGGER || 'false') == 'true';
|
||||||
const local_client = local.connect(config_file, '', debug_logger);
|
const local_client = local.connect(config_file, config_dir, '', debug_logger);
|
||||||
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 registry_enabled = !!__ENV.REGISTRY_FILE;
|
||||||
const obj_registry = registry_enabled ? registry.open(__ENV.REGISTRY_FILE) : undefined;
|
const obj_registry = registry_enabled ? registry.open(__ENV.REGISTRY_FILE) : undefined;
|
||||||
|
|
|
@ -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 summary_json = __ENV.SUMMARY_JSON || "/tmp/summary.json";
|
||||||
|
|
||||||
const config_file = __ENV.CONFIG_FILE;
|
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',
|
'debug_logger': __ENV.DEBUG_LOGGER || 'false',
|
||||||
}, bucket_mapping());
|
}, 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 registry_enabled = !!__ENV.REGISTRY_FILE;
|
||||||
const obj_registry = registry_enabled ? registry.open(__ENV.REGISTRY_FILE) : undefined;
|
const obj_registry = registry_enabled ? registry.open(__ENV.REGISTRY_FILE) : undefined;
|
||||||
|
|
Loading…
Reference in a new issue