diff --git a/cmd/poller/collector/helpers.go b/cmd/poller/collector/helpers.go index 74a515535..b8b7f4b2f 100644 --- a/cmd/poller/collector/helpers.go +++ b/cmd/poller/collector/helpers.go @@ -55,64 +55,86 @@ func (c *AbstractCollector) ImportSubTemplate(model, filename string, ver [3]int var ( selectedVersion, pathPrefix, subTemplateFp string availableVersions []string + err error + finalTemplate *node.Node + tempTemplate *node.Node ) - pathPrefix = path.Join(c.Options.HomePath, "conf/", strings.ToLower(c.Name), model) - c.Logger.Debug().Msgf("Looking for best-fitting template in [%s]", pathPrefix) - verWithDots := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(ver)), "."), "[]") - - // check for available versions, those are the subdirectories that include filename - if files, err := ioutil.ReadDir(pathPrefix); err == nil { - for _, file := range files { - if match, _ := regexp.MatchString(`\d+\.\d+\.\d+`, file.Name()); match == true && file.IsDir() { - if templates, err := ioutil.ReadDir(path.Join(pathPrefix, file.Name())); err == nil { - for _, t := range templates { - if t.Name() == filename { - c.Logger.Trace().Msgf("available version dir: [%s]", file.Name()) - availableVersions = append(availableVersions, file.Name()) - break + //split filename by comma + // in case of custom.yaml having same key, file names will be concatenated by comma + filenames := strings.Split(filename, ",") + + for _, f := range filenames { + pathPrefix = path.Join(c.Options.HomePath, "conf/", strings.ToLower(c.Name), model) + c.Logger.Debug().Msgf("Looking for best-fitting template in [%s]", pathPrefix) + verWithDots := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(ver)), "."), "[]") + + // check for available versions, those are the subdirectories that include filename + if files, err := ioutil.ReadDir(pathPrefix); err == nil { + for _, file := range files { + if match, _ := regexp.MatchString(`\d+\.\d+\.\d+`, file.Name()); match == true && file.IsDir() { + if templates, err := ioutil.ReadDir(path.Join(pathPrefix, file.Name())); err == nil { + for _, t := range templates { + if t.Name() == f { + c.Logger.Trace().Msgf("available version dir: [%s]", file.Name()) + availableVersions = append(availableVersions, file.Name()) + break + } } } } } + } else { + return nil, err } - } else { - return nil, err - } - c.Logger.Trace().Msgf("checking for %d available versions: %v", len(availableVersions), availableVersions) + c.Logger.Trace().Msgf("checking for %d available versions: %v", len(availableVersions), availableVersions) + + if len(availableVersions) > 0 { + versions := make([]*version.Version, len(availableVersions)) + for i, raw := range availableVersions { + v, err := version.NewVersion(raw) + if err != nil { + c.Logger.Trace().Msgf("error parsing version: %s err: %s", raw, err) + continue + } + versions[i] = v + } - if len(availableVersions) > 0 { - versions := make([]*version.Version, len(availableVersions)) - for i, raw := range availableVersions { - v, err := version.NewVersion(raw) + sort.Sort(version.Collection(versions)) + + verS, err := version.NewVersion(verWithDots) if err != nil { - c.Logger.Trace().Msgf("error parsing version: %s err: %s", raw, err) - continue + c.Logger.Trace().Msgf("error parsing ONTAP version: %s err: %s", verWithDots, err) + return nil, errors.New("No best-fitting subtemplate version found") + } + // get closest index + idx := getClosestIndex(versions, verS) + if idx >= 0 && idx < len(versions) { + selectedVersion = versions[idx].String() } - versions[i] = v } - sort.Sort(version.Collection(versions)) - - verS, err := version.NewVersion(verWithDots) - if err != nil { - c.Logger.Trace().Msgf("error parsing ONTAP version: %s err: %s", verWithDots, err) - return nil, errors.New("No best-fitting subtemplate version found") + if selectedVersion == "" { + return nil, errors.New("No best-fit template found") } - // get closest index - idx := getClosestIndex(versions, verS) - if idx >= 0 && idx < len(versions) { - selectedVersion = versions[idx].String() - } - } - if selectedVersion == "" { - return nil, errors.New("No best-fit template found") + subTemplateFp = path.Join(pathPrefix, selectedVersion, f) + c.Logger.Info().Msgf("best-fit template [%s] for [%s]", subTemplateFp, verWithDots) + if finalTemplate == nil { + finalTemplate, err = tree.Import("yaml", subTemplateFp) + if err == nil { + finalTemplate.PreprocessTemplate() + } + } else { + tempTemplate, err = tree.Import("yaml", subTemplateFp) + if err == nil { + tempTemplate.PreprocessTemplate() + // merge templates + finalTemplate.Merge(tempTemplate, nil) + } + } } - - subTemplateFp = path.Join(pathPrefix, selectedVersion, filename) - c.Logger.Info().Msgf("best-fit template [%s] for [%s]", subTemplateFp, verWithDots) - return tree.Import("yaml", subTemplateFp) + return finalTemplate, err } //getClosestIndex returns the closest left match to the sorted list of input versions diff --git a/cmd/poller/plugin/label_agent/label_agent_test.go b/cmd/poller/plugin/label_agent/label_agent_test.go index 0618a613e..a5a74afee 100644 --- a/cmd/poller/plugin/label_agent/label_agent_test.go +++ b/cmd/poller/plugin/label_agent/label_agent_test.go @@ -22,35 +22,35 @@ func TestInitPlugin(t *testing.T) { // define plugin rules params := node.NewS("LabelAgent") // split value of "X" into 4 and take last 2 as new labels - params.NewChildS("split", "X `/` ,,C,D") + params.NewChildS("split", "").AddChild(params.NewChildS("", "X `/` ,,C,D")) // split value of "X" and take first 2 as new labels - params.NewChildS("split_regex", "X `.*(A\\d+)_(B\\d+)` A,B") + params.NewChildS("split_regex", "").AddChild(params.NewChildS("", "X `.*(A\\d+)_(B\\d+)` A,B")) // split value of "X" into key-value pairs - params.NewChildS("split_pairs", "X ` ` `:`") + params.NewChildS("split_pairs", "").AddChild(params.NewChildS("", "X ` ` `:`")) // join values of "A" and "B" and set as label "X" - params.NewChildS("join", "X `_` A,B") + params.NewChildS("join", "").AddChild(params.NewChildS("", "X `_` A,B")) // replace "aaa_" with "bbb_" and set as label "B" - params.NewChildS("replace", "A B `aaa_` `bbb_`") + params.NewChildS("replace", "").AddChild(params.NewChildS("", "A B `aaa_` `bbb_`")) // remove occurences of "aaa_" from value of "A" - params.NewChildS("replace", "A A `aaa_` ``") + params.NewChildS("replace", "").AddChild(params.NewChildS("", "A A `aaa_` ``")) // reverse the order of matching elements, replace underscore with dash and "aaa" with "bbb" - params.NewChildS("replace_regex", "A B `^(aaa)_(\\d+)_(\\w+)$` `$3-$2-bbb`") + params.NewChildS("replace_regex", "").AddChild(params.NewChildS("", "A B `^(aaa)_(\\d+)_(\\w+)$` `$3-$2-bbb`")) // exclude instance if label "A" has value "aaa bbb ccc" - params.NewChildS("exclude_equals", "A `aaa bbb ccc`") + params.NewChildS("exclude_equals", "").AddChild(params.NewChildS("", "A `aaa bbb ccc`")) // exclude instance if label "A" contains "_aaa_" - params.NewChildS("exclude_contains", "A `_aaa_`") + params.NewChildS("exclude_contains", "").AddChild(params.NewChildS("", "A `_aaa_`")) // exclude instance of label value has prefix "aaa_" followed by at least one digit - params.NewChildS("exclude_regex", "A `^aaa_\\d+$`") + params.NewChildS("exclude_regex", "").AddChild(params.NewChildS("", "A `^aaa_\\d+$`")) // create metric "status", if label "state" is one of the 3, map metric value to respective index - params.NewChildS("value_mapping", "status state up,sleeping,down") + params.NewChildS("value_mapping", "").AddChild(params.NewChildS("", "status state up,sleeping,down")) // similar to above, but if none of the values is matching, use default value "4" - params.NewChildS("value_mapping", "stage stage init `1`") + params.NewChildS("value_mapping", "").AddChild(params.NewChildS("", "stage stage init `1`")) // create metric "new_status", if label "state" is one of the up/ok[zapi/rest], map metric value to respective index - params.NewChildS("value_to_num", "new_status state up ok") + params.NewChildS("value_to_num", "").AddChild(params.NewChildS("", "new_status state up ok")) // create metric "new_stage", but if none of the values is matching, use default value "4" - params.NewChildS("value_to_num", "new_stage stage init start `4`") + params.NewChildS("value_to_num", "").AddChild(params.NewChildS("", "new_stage stage init start `4`")) // create metric "new_outage", if empty value is expected and non empty means wrong, use default value "0" - params.NewChildS("value_to_num", "new_outage outage - - `0`") + params.NewChildS("value_to_num", "").AddChild(params.NewChildS("", "new_outage outage - - `0`")) abc := plugin.New("Test", nil, params, nil) p = &LabelAgent{AbstractPlugin: abc} diff --git a/cmd/poller/plugin/label_agent/parse_rules.go b/cmd/poller/plugin/label_agent/parse_rules.go index b2b42e45c..b67ce6784 100644 --- a/cmd/poller/plugin/label_agent/parse_rules.go +++ b/cmd/poller/plugin/label_agent/parse_rules.go @@ -28,33 +28,38 @@ func (me *LabelAgent) parseRules() int { for _, c := range me.Params.GetChildren() { name := c.GetNameS() - rule := strings.TrimSpace(c.GetContentS()) - - switch name { - case "split": - me.parseSplitSimpleRule(rule) - case "split_regex": - me.parseSplitRegexRule(rule) - case "split_pairs": - me.parseSplitPairsRule(rule) - case "join": - me.parseJoinSimpleRule(rule) - case "replace": - me.parseReplaceSimpleRule(rule) - case "replace_regex": - me.parseReplaceRegexRule(rule) - case "exclude_equals": - me.parseExcludeEqualsRule(rule) - case "exclude_contains": - me.parseExcludeContainsRule(rule) - case "exclude_regex": - me.parseExcludeRegexRule(rule) - case "value_mapping": - me.parseValueMappingRule(rule) - case "value_to_num": - me.parseValueToNumRule(rule) - default: - me.Logger.Warn().Msgf("unknown rule (%s)", name) + + rules := c.GetChildren() + // loop over all rules + for _, rc := range rules { + rule := strings.TrimSpace(rc.GetContentS()) + + switch name { + case "split": + me.parseSplitSimpleRule(rule) + case "split_regex": + me.parseSplitRegexRule(rule) + case "split_pairs": + me.parseSplitPairsRule(rule) + case "join": + me.parseJoinSimpleRule(rule) + case "replace": + me.parseReplaceSimpleRule(rule) + case "replace_regex": + me.parseReplaceRegexRule(rule) + case "exclude_equals": + me.parseExcludeEqualsRule(rule) + case "exclude_contains": + me.parseExcludeContainsRule(rule) + case "exclude_regex": + me.parseExcludeRegexRule(rule) + case "value_mapping": + me.parseValueMappingRule(rule) + case "value_to_num": + me.parseValueToNumRule(rule) + default: + me.Logger.Warn().Msgf("unknown rule (%s)", name) + } } } diff --git a/cmd/poller/poller.go b/cmd/poller/poller.go index 4057d2e18..e71ec294d 100644 --- a/cmd/poller/poller.go +++ b/cmd/poller/poller.go @@ -556,7 +556,8 @@ func (p *Poller) loadCollector(c conf.Collector, object string) error { logger.Debug(). Str("template", t). Msg("Merged template.") - template.Merge(subTemplate) + // do not overwrite child of objects. They will be concatenated + template.Merge(subTemplate, []string{"objects"}) } } } diff --git a/cmd/tools/doctor/doctor.go b/cmd/tools/doctor/doctor.go index 718d8232a..d39c39558 100644 --- a/cmd/tools/doctor/doctor.go +++ b/cmd/tools/doctor/doctor.go @@ -5,6 +5,8 @@ import ( "github.com/spf13/cobra" "goharvest2/pkg/color" "goharvest2/pkg/conf" + "goharvest2/pkg/tree" + harvestyaml "goharvest2/pkg/tree/yaml" "gopkg.in/yaml.v3" "io/ioutil" "os" @@ -14,6 +16,8 @@ import ( type options struct { ShouldPrintConfig bool Color string + BaseTemplate string + MergeTemplate string } var opts = &options{ @@ -33,6 +37,39 @@ var Cmd = &cobra.Command{ Run: doDoctorCmd, } +var mergeCmd = &cobra.Command{ + Use: "merge", + Hidden: true, + Short: "merge templates", + Run: doMergeCmd, +} + +func doMergeCmd(cmd *cobra.Command, _ []string) { + doMerge(opts.BaseTemplate, opts.MergeTemplate) +} + +func doMerge(path1 string, path2 string) { + template, err := tree.Import("yaml", path1) + if err != nil { + fmt.Printf("error reading template file [%s]. err=%+v\n", path1, err) + return + } + subTemplate, err := tree.Import("yaml", path2) + if err != nil { + fmt.Printf("error reading template file [%s] err=%+v\n", path2, err) + return + } + template.PreprocessTemplate() + subTemplate.PreprocessTemplate() + template.Merge(subTemplate, nil) + data, err := harvestyaml.Dump(template) + if err != nil { + fmt.Printf("error reading parsing template file [%s] err=%+v\n", data, err) + return + } + fmt.Println(string(data)) +} + func doDoctorCmd(cmd *cobra.Command, _ []string) { var config = cmd.Root().PersistentFlags().Lookup("config") doDoctor(config.Value.String()) @@ -232,6 +269,14 @@ func collectNodes(root *yaml.Node, nodes *[]*yaml.Node) { } func init() { + Cmd.AddCommand(mergeCmd) + mFlags := mergeCmd.PersistentFlags() + + mFlags.StringVarP(&opts.BaseTemplate, "template", "", "", "Base template path ") + mFlags.StringVarP(&opts.MergeTemplate, "with", "", "", "Extended file path. ") + + _ = mergeCmd.MarkPersistentFlagRequired("template") + _ = mergeCmd.MarkPersistentFlagRequired("with") Cmd.Flags().BoolVarP( &opts.ShouldPrintConfig, "print", diff --git a/conf/zapi/7mode/8.6.0/aggr.yaml b/conf/zapi/7mode/8.6.0/aggr.yaml index c8a494a27..20f7d95d2 100644 --- a/conf/zapi/7mode/8.6.0/aggr.yaml +++ b/conf/zapi/7mode/8.6.0/aggr.yaml @@ -51,9 +51,11 @@ counters: plugins: LabelAgent: - value_mapping: status state online `1` + value_mapping: + - status state online `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state online online `0` + value_to_num: + - new_status state online online `0` export_options: instance_keys: diff --git a/conf/zapi/7mode/8.6.0/disk.yaml b/conf/zapi/7mode/8.6.0/disk.yaml index 894298667..72d124a21 100644 --- a/conf/zapi/7mode/8.6.0/disk.yaml +++ b/conf/zapi/7mode/8.6.0/disk.yaml @@ -22,9 +22,11 @@ counters: plugins: - LabelAgent: - value_mapping: status offline false `0` + value_mapping: + - status offline false `0` # metric label zapi_value rest_value `default_value` - value_to_num: new_status offline - - `0` #ok_value is empty value, '-' would be converted to blank while processing. + value_to_num: + - new_status offline - - `0` #ok_value is empty value, '-' would be converted to blank while processing. export_options: instance_keys: diff --git a/conf/zapi/7mode/8.6.0/node.yaml b/conf/zapi/7mode/8.6.0/node.yaml index ba1d409a2..6edd97593 100644 --- a/conf/zapi/7mode/8.6.0/node.yaml +++ b/conf/zapi/7mode/8.6.0/node.yaml @@ -21,9 +21,11 @@ counters: plugins: - LabelAgent: - value_mapping: status healthy true `1` + value_mapping: + - status healthy true `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status healthy true up `0` + value_to_num: + - new_status healthy true up `0` export_options: require_instance_keys: false diff --git a/conf/zapi/7mode/8.6.0/shelf.yaml b/conf/zapi/7mode/8.6.0/shelf.yaml index b402ff79f..05484cc03 100644 --- a/conf/zapi/7mode/8.6.0/shelf.yaml +++ b/conf/zapi/7mode/8.6.0/shelf.yaml @@ -78,9 +78,11 @@ plugins: # - ^power-supply-is-error # - ^power-supply-is-not-installed LabelAgent: - value_mapping: status state normal `1` + value_mapping: + - status state normal `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state normal ok `0` + value_to_num: + - new_status state normal ok `0` export_options: instance_keys: diff --git a/conf/zapi/7mode/8.6.0/status.yaml b/conf/zapi/7mode/8.6.0/status.yaml index 770b855a5..55805f5ae 100644 --- a/conf/zapi/7mode/8.6.0/status.yaml +++ b/conf/zapi/7mode/8.6.0/status.yaml @@ -13,9 +13,11 @@ no_max_records: true plugins: - LabelAgent: - value_mapping: status status ok `1` + value_mapping: + - status status ok `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status status ok ok `0` + value_to_num: + - new_status status ok ok `0` export_options: include_all_labels: true diff --git a/conf/zapi/7mode/8.6.0/status_7.yaml b/conf/zapi/7mode/8.6.0/status_7.yaml index f7349ef29..93eb6f249 100644 --- a/conf/zapi/7mode/8.6.0/status_7.yaml +++ b/conf/zapi/7mode/8.6.0/status_7.yaml @@ -15,7 +15,8 @@ collect_only_labels: true plugins: - LabelAgent: # metric label zapi_value rest_value `default_value` - value_to_num: 7mode_status health ok todo `0` + value_to_num: + - 7mode_status health ok todo `0` export_options: instance_keys: diff --git a/conf/zapi/7mode/8.6.0/subsystem.yaml b/conf/zapi/7mode/8.6.0/subsystem.yaml index 665cb34a3..3c361d98b 100644 --- a/conf/zapi/7mode/8.6.0/subsystem.yaml +++ b/conf/zapi/7mode/8.6.0/subsystem.yaml @@ -13,9 +13,11 @@ counters: plugins: - LabelAgent: - value_mapping: status health ok `1` + value_mapping: + - status health ok `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status health ok todo `0` # REST gap will be filled up later. + value_to_num: + - new_status health ok todo `0` # REST gap will be filled up later. export_options: instance_keys: diff --git a/conf/zapi/7mode/8.6.0/volume.yaml b/conf/zapi/7mode/8.6.0/volume.yaml index 61a8199d6..ea40dc731 100644 --- a/conf/zapi/7mode/8.6.0/volume.yaml +++ b/conf/zapi/7mode/8.6.0/volume.yaml @@ -30,9 +30,11 @@ counters: plugins: LabelAgent: - value_mapping: status state online `1` + value_mapping: + - status state online `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state online online `0` + value_to_num: + - new_status state online online `0` export_options: instance_keys: diff --git a/conf/zapi/cdot/9.8.0/aggr.yaml b/conf/zapi/cdot/9.8.0/aggr.yaml index 3caace6c5..e30725afc 100644 --- a/conf/zapi/cdot/9.8.0/aggr.yaml +++ b/conf/zapi/cdot/9.8.0/aggr.yaml @@ -60,9 +60,11 @@ counters: plugins: LabelAgent: - value_mapping: status state online `1` + value_mapping: + - status state online `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state online online `0` + value_to_num: + - new_status state online online `0` export_options: instance_keys: diff --git a/conf/zapi/cdot/9.8.0/disk.yaml b/conf/zapi/cdot/9.8.0/disk.yaml index 30f2f28e0..fe413a6d1 100644 --- a/conf/zapi/cdot/9.8.0/disk.yaml +++ b/conf/zapi/cdot/9.8.0/disk.yaml @@ -37,9 +37,11 @@ counters: plugins: - LabelAgent: - value_mapping: status outage , `0` # ok_value is empty value + value_mapping: + - status outage , `0` # ok_value is empty value # metric label zapi_value rest_value `default_value` - value_to_num: new_status outage - - `0` #ok_value is empty value, '-' would be converted to blank while processing. + value_to_num: + - new_status outage - - `0` #ok_value is empty value, '-' would be converted to blank while processing. export_options: instance_keys: diff --git a/conf/zapi/cdot/9.8.0/lun.yaml b/conf/zapi/cdot/9.8.0/lun.yaml index d9631ce0a..732962d35 100644 --- a/conf/zapi/cdot/9.8.0/lun.yaml +++ b/conf/zapi/cdot/9.8.0/lun.yaml @@ -17,12 +17,15 @@ counters: plugins: - LabelAgent: - value_mapping: status state online `1` + value_mapping: + - status state online `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state online online `0` + value_to_num: + - new_status state online online `0` # path is something like "/vol/vol_georg_fcp401/lun401" # we only want lun name, which is 4th element - split: path `/` ,,,lun + split: + - path `/` ,,,lun export_options: instance_keys: diff --git a/conf/zapi/cdot/9.8.0/node.yaml b/conf/zapi/cdot/9.8.0/node.yaml index 1b13f9b05..77d99506b 100644 --- a/conf/zapi/cdot/9.8.0/node.yaml +++ b/conf/zapi/cdot/9.8.0/node.yaml @@ -41,10 +41,13 @@ counters: plugins: - LabelAgent: - value_mapping: status healthy true `1` + value_mapping: + - status healthy true `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status healthy true up `0` - join: warnings `; ` failed_fan_message,failed_power_message,over_temperature + value_to_num: + - new_status healthy true up `0` + join: + - warnings `; ` failed_fan_message,failed_power_message,over_temperature export_options: instance_keys: diff --git a/conf/zapi/cdot/9.8.0/shelf.yaml b/conf/zapi/cdot/9.8.0/shelf.yaml index 8e95d32bd..7e56f5b26 100644 --- a/conf/zapi/cdot/9.8.0/shelf.yaml +++ b/conf/zapi/cdot/9.8.0/shelf.yaml @@ -63,9 +63,11 @@ plugins: - voltage-sensor-reading => reading LabelAgent: - value_mapping: status op_status normal `1` + value_mapping: + - status op_status normal `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state online ok `0` + value_to_num: + - new_status state online ok `0` export_options: instance_keys: diff --git a/conf/zapi/cdot/9.8.0/status.yaml b/conf/zapi/cdot/9.8.0/status.yaml index 82a953348..5b9eb2326 100644 --- a/conf/zapi/cdot/9.8.0/status.yaml +++ b/conf/zapi/cdot/9.8.0/status.yaml @@ -12,9 +12,11 @@ no_max_records: true plugins: - LabelAgent: - value_mapping: status status ok `1` + value_mapping: + - status status ok `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status status ok ok `0` + value_to_num: + - new_status status ok ok `0` export_options: include_all_labels: true diff --git a/conf/zapi/cdot/9.8.0/subsystem.yaml b/conf/zapi/cdot/9.8.0/subsystem.yaml index e94a3befb..9f0f65b1f 100644 --- a/conf/zapi/cdot/9.8.0/subsystem.yaml +++ b/conf/zapi/cdot/9.8.0/subsystem.yaml @@ -12,9 +12,11 @@ counters: plugins: - LabelAgent: - value_mapping: status health ok `1` + value_mapping: + - status health ok `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status health ok todo `0` # REST gap will be filled up later. + value_to_num: + - new_status health ok todo `0` # REST gap will be filled up later. export_options: instance_keys: diff --git a/conf/zapi/cdot/9.8.0/volume.yaml b/conf/zapi/cdot/9.8.0/volume.yaml index eb8e56927..840b352c9 100644 --- a/conf/zapi/cdot/9.8.0/volume.yaml +++ b/conf/zapi/cdot/9.8.0/volume.yaml @@ -56,11 +56,15 @@ counters: plugins: LabelAgent: - value_mapping: status state online `1` + value_mapping: + - status state online `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state online online `0` - exclude_equals: style `flexgroup_constituent` - replace: style style `flexgroup_constituent` `flexgroup` + value_to_num: + - new_status state online online `0` + exclude_equals: + - style `flexgroup_constituent` + replace: + - style style `flexgroup_constituent` `flexgroup` Aggregator: volumevolume node,svm,aggr,style diff --git a/conf/zapiperf/7mode/8.2.5/disk.yaml b/conf/zapiperf/7mode/8.2.5/disk.yaml index 636379a7e..bc0f09180 100644 --- a/conf/zapiperf/7mode/8.2.5/disk.yaml +++ b/conf/zapiperf/7mode/8.2.5/disk.yaml @@ -28,7 +28,8 @@ counters: plugins: LabelAgent: - split: raid_group `/` ,aggr,plex,raid + split: + - raid_group `/` ,aggr,plex,raid Aggregator: - aggr diff --git a/conf/zapiperf/7mode/8.2.5/lun.yaml b/conf/zapiperf/7mode/8.2.5/lun.yaml index 420c80eee..b881735c4 100644 --- a/conf/zapiperf/7mode/8.2.5/lun.yaml +++ b/conf/zapiperf/7mode/8.2.5/lun.yaml @@ -20,7 +20,8 @@ counters: plugins: - LabelAgent: - split: lun `/` ,,volume,lun + split: + - lun `/` ,,volume,lun export_options: instance_keys: diff --git a/conf/zapiperf/7mode/8.2.5/nic_common.yaml b/conf/zapiperf/7mode/8.2.5/nic_common.yaml index 9bc43a7a4..0207637ff 100644 --- a/conf/zapiperf/7mode/8.2.5/nic_common.yaml +++ b/conf/zapiperf/7mode/8.2.5/nic_common.yaml @@ -30,9 +30,11 @@ override: plugins: - Nic - LabelAgent: - value_mapping: status state up `1` + value_mapping: + - status state up `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state up up `0` + value_to_num: + - new_status state up up `0` export_options: instance_keys: diff --git a/conf/zapiperf/7mode/8.2.5/path.yaml b/conf/zapiperf/7mode/8.2.5/path.yaml index 0983ca87c..8491f519d 100644 --- a/conf/zapiperf/7mode/8.2.5/path.yaml +++ b/conf/zapiperf/7mode/8.2.5/path.yaml @@ -20,7 +20,8 @@ counters: plugins: LabelAgent: - split: path `_` hostadapter,target_wwpn + split: + - path `_` hostadapter,target_wwpn export_options: instance_keys: diff --git a/conf/zapiperf/cdot/9.8.0/disk.yaml b/conf/zapiperf/cdot/9.8.0/disk.yaml index 1f5c51888..38021b8fc 100644 --- a/conf/zapiperf/cdot/9.8.0/disk.yaml +++ b/conf/zapiperf/cdot/9.8.0/disk.yaml @@ -30,7 +30,8 @@ counters: plugins: LabelAgent: - split: raid_group `/` ,aggr,plex,raid + split: + - raid_group `/` ,aggr,plex,raid Aggregator: # plugin will create summary/average for each object # any names after the object names will be threated as diff --git a/conf/zapiperf/cdot/9.8.0/lun.yaml b/conf/zapiperf/cdot/9.8.0/lun.yaml index 23c387264..e181141a0 100644 --- a/conf/zapiperf/cdot/9.8.0/lun.yaml +++ b/conf/zapiperf/cdot/9.8.0/lun.yaml @@ -38,7 +38,8 @@ override: plugins: LabelAgent: - split: lun `/` ,,volume,lun + split: + - lun `/` ,,volume,lun export_options: instance_keys: diff --git a/conf/zapiperf/cdot/9.8.0/nic_common.yaml b/conf/zapiperf/cdot/9.8.0/nic_common.yaml index 43162eb60..d11ba6ec6 100644 --- a/conf/zapiperf/cdot/9.8.0/nic_common.yaml +++ b/conf/zapiperf/cdot/9.8.0/nic_common.yaml @@ -30,9 +30,11 @@ override: plugins: - Nic - LabelAgent: - value_mapping: status state up `1` + value_mapping: + - status state up `1` # metric label zapi_value rest_value `default_value` - value_to_num: new_status state up up `0` + value_to_num: + - new_status state up up `0` export_options: instance_keys: diff --git a/conf/zapiperf/cdot/9.8.0/path.yaml b/conf/zapiperf/cdot/9.8.0/path.yaml index a624b152d..ec4f98d4b 100644 --- a/conf/zapiperf/cdot/9.8.0/path.yaml +++ b/conf/zapiperf/cdot/9.8.0/path.yaml @@ -20,7 +20,8 @@ counters: plugins: LabelAgent: - split: path `_` hostadapter,target_wwpn + split: + - path `_` hostadapter,target_wwpn export_options: instance_keys: diff --git a/conf/zapiperf/cdot/9.8.0/qtree.yaml b/conf/zapiperf/cdot/9.8.0/qtree.yaml index 88370dab2..acb96e9e9 100644 --- a/conf/zapiperf/cdot/9.8.0/qtree.yaml +++ b/conf/zapiperf/cdot/9.8.0/qtree.yaml @@ -14,7 +14,8 @@ counters: - total_ops plugins: - LabelAgent: - split: qtreefull `/` ,qtree + split: + - qtreefull `/` ,qtree export_options: instance_keys: - qtree diff --git a/pkg/test/mergeTemplates/21.08.0_lun_merge_21.08.0_extended.yaml b/pkg/test/mergeTemplates/21.08.0_lun_merge_21.08.0_extended.yaml new file mode 100644 index 000000000..66dfd35b6 --- /dev/null +++ b/pkg/test/mergeTemplates/21.08.0_lun_merge_21.08.0_extended.yaml @@ -0,0 +1,38 @@ +name: Lun +query: lun-get-iter +object: lun +counters: + lun-info: + - ^node + - ^path + - ^qtree + - size + - size-used + - ^state + - ^^uuid + - ^volume + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - status state online `1` + - custom_status state online `1` + value_to_num: + - new_status state online online `0` + split: + - path `/` ,,,lun + new_mapping: + - xyz + - nic + Aggregator: + - node<>node_cpu1 + - nodetest +export_options: + instance_keys: + - node + - qtree + - lun + - volume + - svm + instance_labels: + - state \ No newline at end of file diff --git a/pkg/test/mergeTemplates/21.08.0_lun_merge_extended.yaml b/pkg/test/mergeTemplates/21.08.0_lun_merge_extended.yaml new file mode 100644 index 000000000..214d7d740 --- /dev/null +++ b/pkg/test/mergeTemplates/21.08.0_lun_merge_extended.yaml @@ -0,0 +1,41 @@ +name: customLun +query: lun-get-iter +object: lun +counters: + lun-info: + - ^node + - ^path + - ^qtree + - size + - size-used + - ^state + - ^^uuid + - ^volume + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - status state online `1` + - custom_status state online `1` + value_to_num: + - new_status state online online `0` + split: + - path `/` ,,,lun + new_mapping: + - xyz + Aggregator: + - node<>node_cpu1 +export_options: + instance_keys: + - node + - qtree + - lun + - volume + - svm + - node1 + instance_labels: + - state +override: + KB_copied: delta + key2: test +export_data: false \ No newline at end of file diff --git a/pkg/test/mergeTemplates/lun_merge.yaml b/pkg/test/mergeTemplates/lun_merge.yaml new file mode 100644 index 000000000..8873aea91 --- /dev/null +++ b/pkg/test/mergeTemplates/lun_merge.yaml @@ -0,0 +1,42 @@ +name: customLun +query: lun-get-iter +object: lun +counters: + lun-info: + - ^node + - ^path + - ^qtree + - size + - size-used + - ^state + - ^^uuid + - ^volume + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - status state online `1` + - custom_status state online `1` + value_to_num: + - new_status state online online `0` + split: + - path `/` ,,,lun + new_mapping: + - xyz + Aggregator: + - aggr + - node<>node_cpu1 +export_options: + instance_keys: + - node + - qtree + - lun + - volume + - svm + - node1 + instance_labels: + - state +override: + KB_copied: delta + key2: test +export_data: false \ No newline at end of file diff --git a/pkg/test/mergeTemplates/lun_merge_21.08.0_extended.yaml b/pkg/test/mergeTemplates/lun_merge_21.08.0_extended.yaml new file mode 100644 index 000000000..f565bf9fe --- /dev/null +++ b/pkg/test/mergeTemplates/lun_merge_21.08.0_extended.yaml @@ -0,0 +1,39 @@ +name: Lun +query: lun-get-iter +object: lun +counters: + lun-info: + - ^node + - ^path + - ^qtree + - size + - size-used + - ^state + - ^^uuid + - ^volume + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - status state online `1` + - custom_status state online `1` + value_to_num: + - new_status state online online `0` + split: + - path `/` ,,,lun + new_mapping: + - xyz + Aggregator: + - aggr + - node<>node_cpu1 + - nodetest + - nic +export_options: + instance_keys: + - node + - qtree + - lun + - volume + - svm + instance_labels: + - state \ No newline at end of file diff --git a/pkg/test/node_test.go b/pkg/test/node_test.go index 4efdb6c21..eaddf31ea 100644 --- a/pkg/test/node_test.go +++ b/pkg/test/node_test.go @@ -2,13 +2,17 @@ package test import ( "goharvest2/pkg/tree" + "goharvest2/pkg/tree/yaml" + "io/ioutil" + "strings" "testing" ) +// Merge default.yaml and custom.yaml func TestNode_Merge(t *testing.T) { - defaultTemplate, _ := tree.Import("yaml", "testdata/default.yaml") - customTemplate, _ := tree.Import("yaml", "testdata/custom.yaml") - defaultTemplate.Merge(customTemplate) + defaultTemplate, _ := tree.Import("yaml", "testdata/default_collector.yaml") + customTemplate, _ := tree.Import("yaml", "testdata/extend_collector.yaml") + defaultTemplate.Merge(customTemplate, []string{"objects"}) // count number of objects post merge want := 10 @@ -23,7 +27,7 @@ func TestNode_Merge(t *testing.T) { } // Compare overwritten values for object - want1 := "node2.yaml" + want1 := "node.yaml,node2.yaml" got1 := defaultTemplate.GetChildS("objects").GetChildS("Node").GetContentS() if got1 != want1 { @@ -45,3 +49,297 @@ func TestNode_Merge(t *testing.T) { } } + +// merge collector templates for 21.08.6+ versions +// change is LabelAgent child will have list of rules instead of key-value pair +func TestNode_MergeCollector(t *testing.T) { + defaultTemplate, _ := tree.Import("yaml", "testdata/lun.yaml") + customTemplate, _ := tree.Import("yaml", "testdata/extend_lun.yaml") + defaultTemplate.PreprocessTemplate() + customTemplate.PreprocessTemplate() + defaultTemplate.Merge(customTemplate, nil) + + gotString1, _ := yaml.Dump(defaultTemplate) + gotString := strings.TrimSpace(string(gotString1)) + expected, _ := ioutil.ReadFile("mergeTemplates/lun_merge.yaml") + expectedString := strings.TrimSpace(string(expected)) + + if gotString != expectedString { + t.Errorf("got %v, want %v", gotString, expectedString) + } + + // object name overwrite + want := "customLun" + got := "" + if name := defaultTemplate.GetChildS("name"); name != nil { + got = name.GetContentS() + if got != want { + t.Errorf("got %v, want %v", got, want) + } + } + + // Add new counter + want1 := 9 + got1 := 0 + counters := defaultTemplate.GetChildS("counters").GetChildS("lun-info") + + if counters != nil { + for range counters.GetChildren() { + got1 += 1 + } + } + + if got1 != want1 { + t.Errorf("got %v, want %v", got1, want1) + } + + // plugins labelagent add new child to existing plugin + want2 := 2 + got2 := 0 + counters = defaultTemplate.GetChildS("plugins").GetChildS("LabelAgent").GetChildS("value_mapping") + if counters != nil { + for range counters.GetChildren() { + got2 += 1 + } + } + + if got2 != want2 { + t.Errorf("got %v, want %v", got2, want2) + } + + // plugins labelagent add same child to existing plugin + want3 := 1 + got3 := 0 + counters = defaultTemplate.GetChildS("plugins").GetChildS("LabelAgent").GetChildS("value_to_num") + if counters != nil { + for range counters.GetChildren() { + got3 += 1 + } + } + + if got3 != want3 { + t.Errorf("got %v, want %v", got3, want3) + } + + // plugins labelagent add same child to existing plugin + want4 := 1 + got4 := 0 + counters = defaultTemplate.GetChildS("plugins").GetChildS("LabelAgent").GetChildS("new_mapping") + if counters != nil { + for range counters.GetChildren() { + got4 += 1 + } + } + + if got4 != want4 { + t.Errorf("got %v, want %v", got4, want4) + } + + // plugins labelagent existing child no change + want5 := 1 + got5 := 0 + counters = defaultTemplate.GetChildS("plugins").GetChildS("LabelAgent").GetChildS("split") + if counters != nil { + for range counters.GetChildren() { + got5 += 1 + } + } + + if got5 != want5 { + t.Errorf("got %v, want %v", got5, want5) + } + + // plugins aggregator add new child + want8 := 2 + got8 := 0 + counters = defaultTemplate.GetChildS("plugins").GetChildS("Aggregator") + if counters != nil { + for range counters.GetChildren() { + got8 += 1 + } + } + + if got8 != want8 { + t.Errorf("got %v, want %v", got8, want8) + } + + //export_options add new instance_key + want6 := 6 + got6 := 0 + counters = defaultTemplate.GetChildS("export_options").GetChildS("instance_keys") + if counters != nil { + for range counters.GetChildren() { + got6 += 1 + } + } + + if got6 != want6 { + t.Errorf("got %v, want %v", want6, got6) + } + + //export_options add same instance_labels + want7 := 1 + got7 := 0 + counters = defaultTemplate.GetChildS("export_options").GetChildS("instance_labels") + if counters != nil { + for range counters.GetChildren() { + got7 += 1 + } + } + + if got7 != want7 { + t.Errorf("got %v, want %v", want7, got7) + } + + //override block + want9 := 2 + got9 := 0 + counters = defaultTemplate.GetChildS("override") + if counters != nil { + for range counters.GetChildren() { + got9 += 1 + } + } + + if want9 != got9 { + t.Errorf("got %v, want %v", want9, got9) + } + + //export block + + export := defaultTemplate.GetChildS("export") + if export != nil { + t.Errorf("missing export block") + } + + if want9 != got9 { + t.Errorf("got %v, want %v", want9, got9) + } +} + +// Merge collector templates where custom templates are from 21.08.6 and before +// LabelAgent child did have key-value pair of rules instead of a list +func TestNode_MergeCollectorOld(t *testing.T) { + defaultTemplate, _ := tree.Import("yaml", "testdata/lun.yaml") + customTemplate, _ := tree.Import("yaml", "testdata/21.08.0_extend_lun.yaml") + defaultTemplate.PreprocessTemplate() + customTemplate.PreprocessTemplate() + defaultTemplate.Merge(customTemplate, nil) + + // plugins labelagent add new child to existing plugin + want2 := 2 + got2 := 0 + counters := defaultTemplate.GetChildS("plugins").GetChildS("LabelAgent").GetChildS("value_mapping") + if counters != nil { + for range counters.GetChildren() { + got2 += 1 + } + } + + if got2 != want2 { + t.Errorf("got %v, want %v", got2, want2) + } + + // plugins labelagent add same child to existing plugin + want3 := 1 + got3 := 0 + counters = defaultTemplate.GetChildS("plugins").GetChildS("LabelAgent").GetChildS("value_to_num") + if counters != nil { + for range counters.GetChildren() { + got3 += 1 + } + } + + if got3 != want3 { + t.Errorf("got %v, want %v", got3, want3) + } + + // plugins labelagent add same child to existing plugin + want4 := 1 + got4 := 0 + counters = defaultTemplate.GetChildS("plugins").GetChildS("LabelAgent").GetChildS("new_mapping") + if counters != nil { + for range counters.GetChildren() { + got4 += 1 + } + } + + if got4 != want4 { + t.Errorf("got %v, want %v", got4, want4) + } + + // plugins aggregator add new child + want5 := 3 + got5 := 0 + counters = defaultTemplate.GetChildS("plugins").GetChildS("Aggregator") + if counters != nil { + for range counters.GetChildren() { + got5 += 1 + } + } + + if got5 != want5 { + t.Errorf("got %v, want %v", got5, want5) + } +} + +func TestNode_PreProcessCollector(t *testing.T) { + + tests := []struct { + name string + sourceFile string + compareFile string + }{ + {name: "preprocess template from 21.08.0", sourceFile: "testdata/21.08.0_extend_lun.yaml", compareFile: "preProcessResultData/p_21.08.0_extend_lun.yaml"}, + {name: "preprocess template after 21.08.0", sourceFile: "testdata/21.08.0_lun.yaml", compareFile: "preProcessResultData/p_21.08.0_lun.yaml"}, + {name: "process collector template", sourceFile: "testdata/default_collector.yaml", compareFile: "preProcessResultData/p_default_collector.yaml"}, + {name: "process extended collector template", sourceFile: "testdata/extend_collector.yaml", compareFile: "preProcessResultData/p_extend_collector.yaml"}, + {name: "process extended object template", sourceFile: "testdata/extend_lun.yaml", compareFile: "preProcessResultData/p_extend_lun.yaml"}, + {name: "process object template", sourceFile: "testdata/lun.yaml", compareFile: "preProcessResultData/p_lun.yaml"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + template, _ := tree.Import("yaml", tt.sourceFile) + template.PreprocessTemplate() + got, _ := yaml.Dump(template) + expected, _ := ioutil.ReadFile(tt.compareFile) + gotString := strings.TrimSpace(string(got)) + expectedString := strings.TrimSpace(string(expected)) + if gotString != expectedString { + t.Errorf("got %v, want %v", gotString, expectedString) + } + }) + } +} + +func TestNode_PreProcessMergeCollector(t *testing.T) { + + tests := []struct { + name string + baseTemplate string + extendTemplate string + mergeTemplate string + }{ + {name: "Case1: Both base and extended template follow new convention for labelagent which is list", baseTemplate: "testdata/lun.yaml", extendTemplate: "testdata/extend_lun.yaml", mergeTemplate: "mergeTemplates/lun_merge.yaml"}, + {name: "Case2: base template follow new convention for labelagent and extended template follow 21.08.0", baseTemplate: "testdata/lun.yaml", extendTemplate: "testdata/21.08.0_extend_lun.yaml", mergeTemplate: "mergeTemplates/lun_merge_21.08.0_extended.yaml"}, + {name: "Case3: base template follow old convention for labelagent and extended template follow 21.08.0", baseTemplate: "testdata/21.08.0_lun.yaml", extendTemplate: "testdata/21.08.0_extend_lun.yaml", mergeTemplate: "mergeTemplates/21.08.0_lun_merge_21.08.0_extended.yaml"}, + {name: "Case4: base template follow old convention for labelagent and extended template follow new", baseTemplate: "testdata/21.08.0_lun.yaml", extendTemplate: "testdata/extend_lun.yaml", mergeTemplate: "mergeTemplates/21.08.0_lun_merge_extended.yaml"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + baseTemplate, _ := tree.Import("yaml", tt.baseTemplate) + extendTemplate, _ := tree.Import("yaml", tt.extendTemplate) + baseTemplate.PreprocessTemplate() + extendTemplate.PreprocessTemplate() + baseTemplate.Merge(extendTemplate, nil) + gotString1, _ := yaml.Dump(baseTemplate) + gotString := strings.TrimSpace(string(gotString1)) + expected, _ := ioutil.ReadFile(tt.mergeTemplate) + expectedString := strings.TrimSpace(string(expected)) + + if gotString != expectedString { + t.Errorf("got %v, want %v", gotString, expectedString) + } + }) + } +} diff --git a/pkg/test/preProcessResultData/p_21.08.0_extend_lun.yaml b/pkg/test/preProcessResultData/p_21.08.0_extend_lun.yaml new file mode 100644 index 000000000..ce033b32d --- /dev/null +++ b/pkg/test/preProcessResultData/p_21.08.0_extend_lun.yaml @@ -0,0 +1,12 @@ +plugins: + - nic + LabelAgent: + value_mapping: + - custom_status state online `1` + value_to_num: + - new_status state online online `0` + new_mapping: + - xyz + Aggregator: + - node<>node_cpu1 + - nodetest diff --git a/pkg/test/preProcessResultData/p_21.08.0_lun.yaml b/pkg/test/preProcessResultData/p_21.08.0_lun.yaml new file mode 100644 index 000000000..c7fd66ce9 --- /dev/null +++ b/pkg/test/preProcessResultData/p_21.08.0_lun.yaml @@ -0,0 +1,31 @@ +name: Lun +query: lun-get-iter +object: lun +counters: + lun-info: + - ^node + - ^path + - ^qtree + - size + - size-used + - ^state + - ^^uuid + - ^volume + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - status state online `1` + value_to_num: + - new_status state online online `0` + split: + - path `/` ,,,lun +export_options: + instance_keys: + - node + - qtree + - lun + - volume + - svm + instance_labels: + - state \ No newline at end of file diff --git a/pkg/test/preProcessResultData/p_default_collector.yaml b/pkg/test/preProcessResultData/p_default_collector.yaml new file mode 100644 index 000000000..517527737 --- /dev/null +++ b/pkg/test/preProcessResultData/p_default_collector.yaml @@ -0,0 +1,14 @@ +collector: Zapi +schedule: + instance: 600s + data: 180s +objects: + Node: node.yaml + Aggregate: aggr.yaml + Volume: volume.yaml + SnapMirror: snapmirror.yaml + Disk: disk.yaml + Shelf: shelf.yaml + Status: status.yaml + Subsystem: subsystem.yaml + Lun: lun.yaml \ No newline at end of file diff --git a/pkg/test/preProcessResultData/p_extend_collector.yaml b/pkg/test/preProcessResultData/p_extend_collector.yaml new file mode 100644 index 000000000..18f74e897 --- /dev/null +++ b/pkg/test/preProcessResultData/p_extend_collector.yaml @@ -0,0 +1,6 @@ +schedule: + instance: 650s + data: 185s +objects: + Node: node2.yaml + Sensor: sensor.yaml \ No newline at end of file diff --git a/pkg/test/preProcessResultData/p_extend_lun.yaml b/pkg/test/preProcessResultData/p_extend_lun.yaml new file mode 100644 index 000000000..0888ef551 --- /dev/null +++ b/pkg/test/preProcessResultData/p_extend_lun.yaml @@ -0,0 +1,23 @@ +name: customLun +counters: + lun-info: + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - custom_status state online `1` + value_to_num: + - new_status state online online `0` + new_mapping: + - xyz + Aggregator: + - node<>node_cpu1 +override: + KB_copied: delta + key2: test +export_data: false +export_options: + instance_keys: + - node1 + instance_labels: + - state diff --git a/pkg/test/preProcessResultData/p_lun.yaml b/pkg/test/preProcessResultData/p_lun.yaml new file mode 100644 index 000000000..3f9a62986 --- /dev/null +++ b/pkg/test/preProcessResultData/p_lun.yaml @@ -0,0 +1,33 @@ +name: Lun +query: lun-get-iter +object: lun +counters: + lun-info: + - ^node + - ^path + - ^qtree + - size + - size-used + - ^state + - ^^uuid + - ^volume + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - status state online `1` + value_to_num: + - new_status state online online `0` + split: + - path `/` ,,,lun + Aggregator: + - aggr +export_options: + instance_keys: + - node + - qtree + - lun + - volume + - svm + instance_labels: + - state \ No newline at end of file diff --git a/pkg/test/testdata/21.08.0_extend_lun.yaml b/pkg/test/testdata/21.08.0_extend_lun.yaml new file mode 100644 index 000000000..7071fa94d --- /dev/null +++ b/pkg/test/testdata/21.08.0_extend_lun.yaml @@ -0,0 +1,9 @@ +plugins: + - nic + LabelAgent: + value_mapping: custom_status state online `1` + value_to_num: new_status state online online `0` + new_mapping: xyz + Aggregator: + - node<>node_cpu1 + - nodetest diff --git a/pkg/test/testdata/21.08.0_lun.yaml b/pkg/test/testdata/21.08.0_lun.yaml new file mode 100644 index 000000000..ed995983a --- /dev/null +++ b/pkg/test/testdata/21.08.0_lun.yaml @@ -0,0 +1,28 @@ +name: Lun +query: lun-get-iter +object: lun +counters: + lun-info: + - ^node + - ^path + - ^qtree + - size + - size-used + - ^state + - ^^uuid + - ^volume + - ^vserver => svm +plugins: + - LabelAgent: + value_mapping: status state online `1` + value_to_num: new_status state online online `0` + split: path `/` ,,,lun +export_options: + instance_keys: + - node + - qtree + - lun + - volume + - svm + instance_labels: + - state \ No newline at end of file diff --git a/pkg/test/testdata/default.yaml b/pkg/test/testdata/default_collector.yaml similarity index 93% rename from pkg/test/testdata/default.yaml rename to pkg/test/testdata/default_collector.yaml index c7b559499..e95921370 100644 --- a/pkg/test/testdata/default.yaml +++ b/pkg/test/testdata/default_collector.yaml @@ -1,11 +1,7 @@ - collector: Zapi - -# Order here matters! schedule: - instance: 600s - data: 180s - objects: Node: node.yaml Aggregate: aggr.yaml diff --git a/pkg/test/testdata/custom.yaml b/pkg/test/testdata/extend_collector.yaml similarity index 100% rename from pkg/test/testdata/custom.yaml rename to pkg/test/testdata/extend_collector.yaml diff --git a/pkg/test/testdata/extend_lun.yaml b/pkg/test/testdata/extend_lun.yaml new file mode 100644 index 000000000..af5328767 --- /dev/null +++ b/pkg/test/testdata/extend_lun.yaml @@ -0,0 +1,23 @@ +name: customLun +counters: + lun-info: + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - custom_status state online `1` + value_to_num: + - new_status state online online `0` + new_mapping: + - xyz + Aggregator: + - node<>node_cpu1 +override: + - KB_copied: delta + - key2: test +export_data: false +export_options: + instance_keys: + - node1 + instance_labels: + - state diff --git a/pkg/test/testdata/lun.yaml b/pkg/test/testdata/lun.yaml new file mode 100644 index 000000000..3f9a62986 --- /dev/null +++ b/pkg/test/testdata/lun.yaml @@ -0,0 +1,33 @@ +name: Lun +query: lun-get-iter +object: lun +counters: + lun-info: + - ^node + - ^path + - ^qtree + - size + - size-used + - ^state + - ^^uuid + - ^volume + - ^vserver => svm +plugins: + LabelAgent: + value_mapping: + - status state online `1` + value_to_num: + - new_status state online online `0` + split: + - path `/` ,,,lun + Aggregator: + - aggr +export_options: + instance_keys: + - node + - qtree + - lun + - volume + - svm + instance_labels: + - state \ No newline at end of file diff --git a/pkg/tree/node/node.go b/pkg/tree/node/node.go index 97dce9e91..39786fff8 100644 --- a/pkg/tree/node/node.go +++ b/pkg/tree/node/node.go @@ -202,6 +202,16 @@ func (n *Node) GetChildContentS(name string) string { return "" } +// GetChildByContent Compare child content +func (n *Node) GetChildByContent(content string) *Node { + for _, child := range n.Children { + if child.GetContentS() == content { + return child + } + } + return nil +} + func (n *Node) SetChildContentS(name, content string) { if child := n.GetChildS(name); child != nil { child.SetContentS(content) @@ -259,19 +269,64 @@ func (n *Node) Union(source *Node) { } } -func (me *Node) Merge(source *Node) { +//fetchRoot return if a parent name ancestor exists +func (n *Node) searchAncestor(ancestor string) *Node { + if n == nil { + return nil + } + p := n.GetParent() + if p == nil { + return nil + } + if p != nil && p.GetNameS() == ancestor { + return n + } + return p.searchAncestor(ancestor) +} + +func (me *Node) PreprocessTemplate() { + for _, child := range me.Children { + mine := me.GetChild(child.GetName()) + if mine != nil && len(child.GetName()) > 0 { + if mine.searchAncestor("LabelAgent") != nil { + if len(mine.GetContentS()) > 0 { + mine.NewChildS("", child.GetContentS()) + mine.SetContentS("") + } + } + mine.PreprocessTemplate() + } + } +} +//Merge method will merge the subtemplate into the receiver, modifying the receiver in-place. +//skipOverwrite is a readonly list of keys that will not be overwritten in the receiver. +func (me *Node) Merge(subtemplate *Node, skipOverwrite []string) { + if subtemplate == nil { + return + } if len(me.Content) == 0 { - me.Content = source.Content + me.Content = subtemplate.Content } - - for _, child := range source.Children { - if mine := me.GetChild(child.GetName()); mine == nil { + for _, child := range subtemplate.Children { + mine := me.GetChild(child.GetName()) + if len(child.GetName()) == 0 { + if mine != nil && mine.GetParent() != nil && mine.GetParent().GetChildByContent(child.GetContentS()) == nil { + mine.GetParent().AddChild(child) + } else { + if me.GetChildByContent(child.GetContentS()) == nil { + me.AddChild(child) + } + } + } else if mine == nil { me.AddChild(child) } else { - // set content - mine.SetContentS(child.GetContentS()) - mine.Merge(child) + if mine.GetParent() != nil && util.Contains(skipOverwrite, mine.GetParent().GetNameS()) { + mine.SetContentS(mine.GetContentS() + "," + child.GetContentS()) + } else { + mine.SetContentS(child.GetContentS()) + } + mine.Merge(child, skipOverwrite) } } } diff --git a/pkg/util/util.go b/pkg/util/util.go index 209c77f9f..087eaf2ad 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -179,3 +179,12 @@ func ContainsWholeWord(source string, search string) bool { } return false } + +func Contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +}