diff --git a/internal/benchrunner/runners/common/scenario.go b/internal/benchrunner/runners/common/scenario.go new file mode 100644 index 0000000000..05c95d4493 --- /dev/null +++ b/internal/benchrunner/runners/common/scenario.go @@ -0,0 +1,119 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package common + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/elastic/go-ucfg/yaml" +) + +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +const DevPath = "_dev/benchmark/rally" + +type Scenario struct { + Package string `config:"package" json:"package"` + Description string `config:"description" json:"description"` + Version string `config:"version" json:"version"` + DataStream DataStream `config:"data_stream" json:"data_stream"` + Corpora Corpora `config:"corpora" json:"corpora"` +} + +type DataStream struct { + Name string `config:"name" json:"name"` +} + +type Corpora struct { + Generator *Generator `config:"generator" json:"generator"` +} + +type Generator struct { + TotalEvents uint64 `config:"total_events" json:"total_events"` + Template CorporaTemplate `config:"template" json:"template"` + Config CorporaAsset `config:"config" json:"config"` + Fields CorporaAsset `config:"fields" json:"fields"` +} + +type CorporaAsset struct { + Raw map[string]interface{} `config:"raw" json:"raw"` + Path string `config:"path" json:"path"` +} +type CorporaTemplate struct { + Raw string `config:"raw" json:"raw"` + Path string `config:"path" json:"path"` + Type string `config:"type" json:"type"` +} + +func DefaultConfig() *Scenario { + return &Scenario{} +} + +func ReadConfig(path, scenario, packageName, packageVersion string) (*Scenario, error) { + configPath := filepath.Join(path, DevPath, fmt.Sprintf("%s.yml", scenario)) + c := DefaultConfig() + cfg, err := yaml.NewConfigWithFile(configPath) + if err != nil { + return nil, fmt.Errorf("can't load benchmark configuration: %s: %w", configPath, err) + } + + if err == nil { + if err := cfg.Unpack(c); err != nil { + return nil, fmt.Errorf("can't unpack benchmark configuration: %s: %w", configPath, err) + } + } + + c.Package = packageName + c.Version = packageVersion + + if c.DataStream.Name == "" { + return nil, errors.New("can't read data stream name from benchmark configuration: empty") + } + + return c, nil +} + +func ReadScenarios(path, scenarioName, packageName, packageVersion string) (map[string]*Scenario, error) { + scenarios := make(map[string]*Scenario) + if len(scenarioName) > 0 { + scenario, err := ReadConfig(path, scenarioName, packageName, packageVersion) + if err != nil { + return nil, fmt.Errorf("error loading scenario: %w", err) + } + scenarios[scenarioName] = scenario + } else { + err := filepath.Walk(filepath.Join(path, DevPath), func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + if strings.HasSuffix(info.Name(), "-benchmark.yml") { + scenarioName = strings.TrimSuffix(info.Name(), ".yml") + scenario, err := ReadConfig(path, scenarioName, packageName, packageVersion) + if err != nil { + return err + } + scenarios[scenarioName] = scenario + } + + return nil + }) + if err != nil { + return nil, fmt.Errorf("error loading scenario: %w", err) + } + } + + return scenarios, nil +} diff --git a/internal/benchrunner/runners/rally/metrics.go b/internal/benchrunner/runners/rally/metrics.go index b5fa905c7c..a6a965e320 100644 --- a/internal/benchrunner/runners/rally/metrics.go +++ b/internal/benchrunner/runners/rally/metrics.go @@ -14,6 +14,8 @@ import ( "sync/atomic" "time" + "github.com/elastic/elastic-package/internal/benchrunner/runners/common" + "github.com/elastic/elastic-package/internal/elasticsearch" "github.com/elastic/elastic-package/internal/elasticsearch/ingest" "github.com/elastic/elastic-package/internal/logger" @@ -23,7 +25,7 @@ import ( type collector struct { ctxt servicedeployer.ServiceContext metadata benchMeta - scenario scenario + scenario common.Scenario interval time.Duration esAPI *elasticsearch.API @@ -66,7 +68,7 @@ type metricsSummary struct { func newCollector( ctxt servicedeployer.ServiceContext, benchName string, - scenario scenario, + scenario common.Scenario, esAPI, metricsAPI *elasticsearch.API, interval time.Duration, datastream, pipelinePrefix string, diff --git a/internal/benchrunner/runners/rally/report.go b/internal/benchrunner/runners/rally/report.go index 3f6e46e23a..728e73f21e 100644 --- a/internal/benchrunner/runners/rally/report.go +++ b/internal/benchrunner/runners/rally/report.go @@ -10,6 +10,8 @@ import ( "strings" "time" + "github.com/elastic/elastic-package/internal/benchrunner/runners/common" + "github.com/dustin/go-humanize" "github.com/jedib0t/go-pretty/table" "github.com/jedib0t/go-pretty/text" @@ -31,8 +33,8 @@ type report struct { } Parameters struct { PackageVersion string - DataStream dataStream - Corpora corpora + DataStream common.DataStream + Corpora common.Corpora } ClusterName string Nodes int @@ -43,7 +45,7 @@ type report struct { RallyStats []rallyStat } -func createReport(benchName, corporaFile string, s *scenario, sum *metricsSummary, stats []rallyStat) (reporters.Reportable, error) { +func createReport(benchName, corporaFile string, s *common.Scenario, sum *metricsSummary, stats []rallyStat) (reporters.Reportable, error) { r := newReport(benchName, corporaFile, s, sum, stats) human := reporters.NewReport(s.Package, reportHumanFormat(r)) @@ -59,7 +61,7 @@ func createReport(benchName, corporaFile string, s *scenario, sum *metricsSummar return mr, nil } -func newReport(benchName, corporaFile string, s *scenario, sum *metricsSummary, stats []rallyStat) *report { +func newReport(benchName, corporaFile string, s *common.Scenario, sum *metricsSummary, stats []rallyStat) *report { var report report report.Info.Benchmark = benchName report.Info.Description = s.Description diff --git a/internal/benchrunner/runners/rally/runner.go b/internal/benchrunner/runners/rally/runner.go index 3b9cbb506c..34a2f3b5a8 100644 --- a/internal/benchrunner/runners/rally/runner.go +++ b/internal/benchrunner/runners/rally/runner.go @@ -21,6 +21,8 @@ import ( "text/template" "time" + "github.com/elastic/elastic-package/internal/benchrunner/runners/common" + "github.com/elastic/elastic-package/internal/packages/installer" "github.com/magefile/mage/sh" @@ -150,7 +152,7 @@ type rallyStat struct { type runner struct { options Options - scenario *scenario + scenario *common.Scenario ctxt servicedeployer.ServiceContext runtimeDataStream string @@ -262,7 +264,7 @@ func (r *runner) setUp() error { return fmt.Errorf("reading package manifest failed: %w", err) } - scenario, err := readConfig(r.options.PackageRootPath, r.options.BenchName, pkgManifest.Name, pkgManifest.Version) + scenario, err := common.ReadConfig(r.options.PackageRootPath, r.options.BenchName, pkgManifest.Name, pkgManifest.Version) if err != nil { return err } @@ -596,7 +598,7 @@ func (r *runner) getGeneratorConfig() (*config.Config, error) { ) if r.scenario.Corpora.Generator.Config.Path != "" { - configPath := filepath.Clean(filepath.Join(devPath, r.scenario.Corpora.Generator.Config.Path)) + configPath := filepath.Clean(filepath.Join(common.DevPath, r.scenario.Corpora.Generator.Config.Path)) configPath = os.ExpandEnv(configPath) if _, err := os.Stat(configPath); err != nil { return nil, fmt.Errorf("can't find config file %s: %w", configPath, err) @@ -627,7 +629,7 @@ func (r *runner) getGeneratorFields() (fields.Fields, error) { ) if r.scenario.Corpora.Generator.Fields.Path != "" { - fieldsPath := filepath.Clean(filepath.Join(devPath, r.scenario.Corpora.Generator.Fields.Path)) + fieldsPath := filepath.Clean(filepath.Join(common.DevPath, r.scenario.Corpora.Generator.Fields.Path)) fieldsPath = os.ExpandEnv(fieldsPath) if _, err := os.Stat(fieldsPath); err != nil { return nil, fmt.Errorf("can't find fields file %s: %w", fieldsPath, err) @@ -659,7 +661,7 @@ func (r *runner) getGeneratorTemplate() ([]byte, error) { ) if r.scenario.Corpora.Generator.Template.Path != "" { - tplPath := filepath.Clean(filepath.Join(devPath, r.scenario.Corpora.Generator.Template.Path)) + tplPath := filepath.Clean(filepath.Join(common.DevPath, r.scenario.Corpora.Generator.Template.Path)) tplPath = os.ExpandEnv(tplPath) if _, err := os.Stat(tplPath); err != nil { return nil, fmt.Errorf("can't find template file %s: %w", tplPath, err) @@ -1113,7 +1115,7 @@ type benchMeta struct { Benchmark string `json:"benchmark"` RunID string `json:"run_id"` } `json:"info"` - Parameters scenario `json:"parameter"` + Parameters common.Scenario `json:"parameter"` } func (r *runner) enrichEventWithBenchmarkMetadata(e map[string]interface{}) map[string]interface{} { diff --git a/internal/benchrunner/runners/rally/scenario.go b/internal/benchrunner/runners/rally/scenario.go index 27982bf618..7c788993a3 100644 --- a/internal/benchrunner/runners/rally/scenario.go +++ b/internal/benchrunner/runners/rally/scenario.go @@ -3,74 +3,3 @@ // you may not use this file except in compliance with the Elastic License. package rally - -import ( - "errors" - "fmt" - "path/filepath" - - "github.com/elastic/go-ucfg/yaml" -) - -const devPath = "_dev/benchmark/rally" - -type scenario struct { - Package string `config:"package" json:"package"` - Description string `config:"description" json:"description"` - Version string `config:"version" json:"version"` - DataStream dataStream `config:"data_stream" json:"data_stream"` - Corpora corpora `config:"corpora" json:"corpora"` -} - -type dataStream struct { - Name string `config:"name" json:"name"` -} - -type corpora struct { - Generator *generator `config:"generator" json:"generator"` -} - -type generator struct { - TotalEvents uint64 `config:"total_events" json:"total_events"` - Template corporaTemplate `config:"template" json:"template"` - Config corporaAsset `config:"config" json:"config"` - Fields corporaAsset `config:"fields" json:"fields"` -} - -type corporaAsset struct { - Raw map[string]interface{} `config:"raw" json:"raw"` - Path string `config:"path" json:"path"` -} -type corporaTemplate struct { - Raw string `config:"raw" json:"raw"` - Path string `config:"path" json:"path"` - Type string `config:"type" json:"type"` -} - -func defaultConfig() *scenario { - return &scenario{} -} - -func readConfig(path, scenario, packageName, packageVersion string) (*scenario, error) { - configPath := filepath.Join(path, devPath, fmt.Sprintf("%s.yml", scenario)) - c := defaultConfig() - cfg, err := yaml.NewConfigWithFile(configPath) - if err != nil { - return nil, fmt.Errorf("can't load benchmark configuration: %s: %w", configPath, err) - } - - if err == nil { - if err := cfg.Unpack(c); err != nil { - return nil, fmt.Errorf("can't unpack benchmark configuration: %s: %w", configPath, err) - } - } - - c.Package = packageName - c.Version = packageVersion - - if c.DataStream.Name == "" { - return nil, errors.New("can't read data stream name from benchmark configuration: empty") - } - - return c, nil -} diff --git a/internal/benchrunner/runners/stream/runner.go b/internal/benchrunner/runners/stream/runner.go index 490a68e777..bcec433331 100644 --- a/internal/benchrunner/runners/stream/runner.go +++ b/internal/benchrunner/runners/stream/runner.go @@ -18,6 +18,8 @@ import ( "sync" "time" + "github.com/elastic/elastic-package/internal/benchrunner/runners/common" + "github.com/elastic/elastic-package/internal/packages/installer" "github.com/google/uuid" @@ -39,7 +41,7 @@ import ( type runner struct { options Options - scenarios map[string]*scenario + scenarios map[string]*common.Scenario ctxt servicedeployer.ServiceContext runtimeDataStreams map[string]string @@ -114,7 +116,7 @@ func (r *runner) setUp() error { return fmt.Errorf("reading package manifest failed: %w", err) } - scenarios, err := readScenarios(r.options.PackageRootPath, r.options.BenchName, pkgManifest.Name, pkgManifest.Version) + scenarios, err := common.ReadScenarios(r.options.PackageRootPath, r.options.BenchName, pkgManifest.Name, pkgManifest.Version) if err != nil { return err } @@ -271,7 +273,7 @@ func (r *runner) deleteDataStreamDocs(dataStream string) error { return nil } -func (r *runner) initializeGenerator(tpl []byte, config genlib.Config, fields genlib.Fields, scenario *scenario, backFill time.Duration, totEvents uint64) (genlib.Generator, error) { +func (r *runner) initializeGenerator(tpl []byte, config genlib.Config, fields genlib.Fields, scenario *common.Scenario, backFill time.Duration, totEvents uint64) (genlib.Generator, error) { timestampConfig := genlib.ConfigField{Name: r.options.TimestampField} if backFill < 0 { timestampConfig.Period = backFill @@ -334,14 +336,14 @@ func (r *runner) collectGenerators() error { return nil } -func (r *runner) getGeneratorConfig(scenario *scenario) (*config.Config, error) { +func (r *runner) getGeneratorConfig(scenario *common.Scenario) (*config.Config, error) { var ( data []byte err error ) if scenario.Corpora.Generator.Config.Path != "" { - configPath := filepath.Clean(filepath.Join(devPath, scenario.Corpora.Generator.Config.Path)) + configPath := filepath.Clean(filepath.Join(common.DevPath, scenario.Corpora.Generator.Config.Path)) configPath = os.ExpandEnv(configPath) if _, err := os.Stat(configPath); err != nil { return nil, fmt.Errorf("can't find config file %s: %w", configPath, err) @@ -365,14 +367,14 @@ func (r *runner) getGeneratorConfig(scenario *scenario) (*config.Config, error) return &cfg, nil } -func (r *runner) getGeneratorFields(scenario *scenario) (fields.Fields, error) { +func (r *runner) getGeneratorFields(scenario *common.Scenario) (fields.Fields, error) { var ( data []byte err error ) if scenario.Corpora.Generator.Fields.Path != "" { - fieldsPath := filepath.Clean(filepath.Join(devPath, scenario.Corpora.Generator.Fields.Path)) + fieldsPath := filepath.Clean(filepath.Join(common.DevPath, scenario.Corpora.Generator.Fields.Path)) fieldsPath = os.ExpandEnv(fieldsPath) if _, err := os.Stat(fieldsPath); err != nil { return nil, fmt.Errorf("can't find fields file %s: %w", fieldsPath, err) @@ -397,14 +399,14 @@ func (r *runner) getGeneratorFields(scenario *scenario) (fields.Fields, error) { return fields, nil } -func (r *runner) getGeneratorTemplate(scenario *scenario) ([]byte, error) { +func (r *runner) getGeneratorTemplate(scenario *common.Scenario) ([]byte, error) { var ( data []byte err error ) if scenario.Corpora.Generator.Template.Path != "" { - tplPath := filepath.Clean(filepath.Join(devPath, scenario.Corpora.Generator.Template.Path)) + tplPath := filepath.Clean(filepath.Join(common.DevPath, scenario.Corpora.Generator.Template.Path)) tplPath = os.ExpandEnv(tplPath) if _, err := os.Stat(tplPath); err != nil { return nil, fmt.Errorf("can't find template file %s: %w", tplPath, err) diff --git a/internal/benchrunner/runners/stream/scenario.go b/internal/benchrunner/runners/stream/scenario.go index 36abf5f840..745c478185 100644 --- a/internal/benchrunner/runners/stream/scenario.go +++ b/internal/benchrunner/runners/stream/scenario.go @@ -3,112 +3,3 @@ // you may not use this file except in compliance with the Elastic License. package stream - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/elastic/go-ucfg/yaml" -) - -const devPath = "_dev/benchmark/rally" - -type scenario struct { - Package string `config:"package" json:"package"` - Description string `config:"description" json:"description"` - Version string `config:"version" json:"version"` - DataStream dataStream `config:"data_stream" json:"data_stream"` - Corpora corpora `config:"corpora" json:"corpora"` -} - -type dataStream struct { - Name string `config:"name" json:"name"` -} - -type corpora struct { - Generator *generator `config:"generator" json:"generator"` -} - -type generator struct { - TotalEvents uint64 `config:"total_events" json:"total_events"` - Template corporaTemplate `config:"template" json:"template"` - Config corporaAsset `config:"config" json:"config"` - Fields corporaAsset `config:"fields" json:"fields"` -} - -type corporaAsset struct { - Raw map[string]interface{} `config:"raw" json:"raw"` - Path string `config:"path" json:"path"` -} -type corporaTemplate struct { - Raw string `config:"raw" json:"raw"` - Path string `config:"path" json:"path"` - Type string `config:"type" json:"type"` -} - -func defaultConfig() *scenario { - return &scenario{} -} - -func readConfig(path, scenarioName, packageName, packageVersion string) (*scenario, error) { - configPath := filepath.Join(path, devPath, fmt.Sprintf("%s.yml", scenarioName)) - c := defaultConfig() - cfg, err := yaml.NewConfigWithFile(configPath) - if err != nil { - return nil, fmt.Errorf("can't load benchmark configuration: %s: %w", configPath, err) - } - - if err == nil { - if err := cfg.Unpack(c); err != nil { - return nil, fmt.Errorf("can't unpack benchmark configuration: %s: %w", configPath, err) - } - } - - c.Package = packageName - c.Version = packageVersion - - if c.DataStream.Name == "" { - return nil, errors.New("can't read data stream name from benchmark configuration: empty") - } - - return c, nil -} -func readScenarios(path, scenarioName, packageName, packageVersion string) (map[string]*scenario, error) { - scenarios := make(map[string]*scenario) - if len(scenarioName) > 0 { - scenario, err := readConfig(path, scenarioName, packageName, packageVersion) - if err != nil { - return nil, fmt.Errorf("error loading scenario: %w", err) - } - scenarios[scenarioName] = scenario - } else { - err := filepath.Walk(filepath.Join(path, devPath), func(_ string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - if info.IsDir() { - return nil - } - - if strings.HasSuffix(info.Name(), "-benchmark.yml") { - scenarioName = strings.TrimSuffix(info.Name(), ".yml") - scenario, err := readConfig(path, scenarioName, packageName, packageVersion) - if err != nil { - return err - } - scenarios[scenarioName] = scenario - } - - return nil - }) - if err != nil { - return nil, fmt.Errorf("error loading scenario: %w", err) - } - } - - return scenarios, nil -} diff --git a/internal/benchrunner/runners/system/scenario.go b/internal/benchrunner/runners/system/scenario.go index 00a7909f0a..d775e47788 100644 --- a/internal/benchrunner/runners/system/scenario.go +++ b/internal/benchrunner/runners/system/scenario.go @@ -11,6 +11,8 @@ import ( "path/filepath" "time" + "github.com/elastic/elastic-package/internal/benchrunner/runners/common" + "github.com/aymerick/raymond" "github.com/elastic/go-ucfg" "github.com/elastic/go-ucfg/yaml" @@ -38,8 +40,8 @@ type dataStream struct { } type corpora struct { - Generator *generator `config:"generator" json:"generator"` - InputService *inputService `config:"input_service" json:"input_service"` + Generator *common.Generator `config:"generator" json:"generator"` + InputService *inputService `config:"input_service" json:"input_service"` } type inputService struct { @@ -47,29 +49,6 @@ type inputService struct { Signal string `config:"signal" json:"signal"` } -type generator struct { - TotalEvents uint64 `config:"total_events" json:"total_events"` - Template corporaTemplate `config:"template" json:"template"` - Config corporaConfig `config:"config" json:"config"` - Fields corporaFields `config:"fields" json:"fields"` -} - -type corporaTemplate struct { - Raw string `config:"raw" json:"raw"` - Path string `config:"path" json:"path"` - Type string `config:"type" json:"type"` -} - -type corporaConfig struct { - Raw map[string]interface{} `config:"raw" json:"raw"` - Path string `config:"path" json:"path"` -} - -type corporaFields struct { - Raw map[string]interface{} `config:"raw" json:"raw"` - Path string `config:"path" json:"path"` -} - func defaultConfig() *scenario { timeout := 10 * time.Minute return &scenario{