Skip to content

Commit

Permalink
Merge pull request #67 from inexio/pre-release
Browse files Browse the repository at this point in the history
Pre release
  • Loading branch information
TheFireMike authored Aug 19, 2021
2 parents 862dd7d + b75c8b6 commit 5af65f1
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 50 deletions.
26 changes: 21 additions & 5 deletions cmd/check_interface_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"github.com/inexio/thola/internal/request"
"github.com/inexio/thola/internal/utility"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
Expand All @@ -11,6 +12,8 @@ func init() {
checkCMD.AddCommand(checkInterfaceMetricsCMD)

checkInterfaceMetricsCMD.Flags().Bool("print-interfaces", false, "Print interfaces to plugin output")
checkInterfaceMetricsCMD.Flags().String("ifDescr-regex", "", "Apply a regex on the ifDescr of the interfaces. Use it together with the 'ifDescr-regex-replace' flag")
checkInterfaceMetricsCMD.Flags().String("ifDescr-regex-replace", "", "Apply a regex on the ifDescr of the interfaces. Use it together with the 'ifDescr-regex' flag")
checkInterfaceMetricsCMD.Flags().StringSlice("ifType-filter", []string{}, "Filter out interfaces which ifType equals the given types")
checkInterfaceMetricsCMD.Flags().StringSlice("ifName-filter", []string{}, "Filter out interfaces which ifName matches the given regex")
checkInterfaceMetricsCMD.Flags().StringSlice("ifDescr-filter", []string{}, "Filter out interfaces which ifDescription matches the given regex")
Expand All @@ -25,6 +28,14 @@ var checkInterfaceMetricsCMD = &cobra.Command{
if err != nil {
log.Fatal().Err(err).Msg("print-interfaces needs to be a boolean")
}
ifDescrRegex, err := cmd.Flags().GetString("ifDescr-regex")
if err != nil {
log.Fatal().Err(err).Msg("ifDescr-regex needs to be a string")
}
ifDescrRegexReplace, err := cmd.Flags().GetString("ifDescr-regex-replace")
if err != nil {
log.Fatal().Err(err).Msg("ifDescr-regex-replace needs to be a string")
}
ifTypeFilter, err := cmd.Flags().GetStringSlice("ifType-filter")
if err != nil {
log.Fatal().Err(err).Msg("ifType-filter needs to be a string")
Expand All @@ -37,13 +48,18 @@ var checkInterfaceMetricsCMD = &cobra.Command{
if err != nil {
log.Fatal().Err(err).Msg("ifDescr-filter needs to be a string")
}

var nullString *string
r := request.CheckInterfaceMetricsRequest{
CheckDeviceRequest: getCheckDeviceRequest(args[0]),
PrintInterfaces: printInterfaces,
IfTypeFilter: ifTypeFilter,
IfNameFilter: ifNameFilter,
IfDescrFilter: ifDescrFilter,
CheckDeviceRequest: getCheckDeviceRequest(args[0]),
PrintInterfaces: printInterfaces,
IfDescrRegex: utility.IfThenElse(cmd.Flags().Changed("ifDescr-regex"), &ifDescrRegex, nullString).(*string),
IfDescrRegexReplace: utility.IfThenElse(cmd.Flags().Changed("ifDescr-regex-replace"), &ifDescrRegexReplace, nullString).(*string),
IfTypeFilter: ifTypeFilter,
IfNameFilter: ifNameFilter,
IfDescrFilter: ifDescrFilter,
}

handleRequest(&r)
},
}
15 changes: 1 addition & 14 deletions config/device-classes/generic/planetos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,4 @@ identify:
- type: modify
modify_method: regexSubmatch
regex: 'PLANET ([^\s]+)\s'
format: "$1"

components:
interfaces:
properties:
detection: snmpwalk
values:
ifDescr:
oid: 1.3.6.1.2.1.2.2.1.2
operators:
- type: modify
modify_method: regexReplace
regex: '\s+'
replace: ' '
format: "$1"
34 changes: 30 additions & 4 deletions internal/request/check_interface_metrics_request.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
package request

import (
"context"
"github.com/pkg/errors"
"regexp"
)

// CheckInterfaceMetricsRequest
//
// CheckInterfaceRequest is a the request struct for the check interface metrics request.
//
// swagger:model
type CheckInterfaceMetricsRequest struct {
PrintInterfaces bool `yaml:"print_interfaces" json:"print_interfaces" xml:"print_interfaces"`
IfTypeFilter []string `yaml:"ifType_filter" json:"ifType_filter" xml:"ifType_filter"`
IfNameFilter []string `yaml:"ifName_filter" json:"ifName_filter" xml:"ifName_filter"`
IfDescrFilter []string `yaml:"ifDescr_filter" json:"ifDescr_filter" xml:"ifDescr_filter"`
PrintInterfaces bool `yaml:"print_interfaces" json:"print_interfaces" xml:"print_interfaces"`
IfDescrRegex *string `yaml:"ifDescr_regex" json:"ifDescr_regex" xml:"ifDescr_regex"`
ifDescrRegex *regexp.Regexp
IfDescrRegexReplace *string `yaml:"ifDescr_regex_replace" json:"ifDescr_regex_replace" xml:"ifDescr_regex_replace"`
IfTypeFilter []string `yaml:"ifType_filter" json:"ifType_filter" xml:"ifType_filter"`
IfNameFilter []string `yaml:"ifName_filter" json:"ifName_filter" xml:"ifName_filter"`
IfDescrFilter []string `yaml:"ifDescr_filter" json:"ifDescr_filter" xml:"ifDescr_filter"`
CheckDeviceRequest
}

func (r *CheckInterfaceMetricsRequest) validate(ctx context.Context) error {
if r.IfDescrRegex != nil && r.IfDescrRegexReplace == nil ||
r.IfDescrRegex == nil && r.IfDescrRegexReplace != nil {
return errors.New("'ifDescr-regex' and 'ifDescr-regex-replace' must be set together")
}

if r.IfDescrRegex != nil {
regex, err := regexp.Compile(*r.IfDescrRegex)
if err != nil {
return errors.Wrap(err, "compiling ifDescrRegex failed")
}
r.ifDescrRegex = regex
}

return r.CheckDeviceRequest.validate(ctx)
}
73 changes: 46 additions & 27 deletions internal/request/check_interface_metrics_request_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,35 @@ type interfaceCheckOutput struct {
func (r *CheckInterfaceMetricsRequest) process(ctx context.Context) (Response, error) {
r.init()

readInterfacesResponse, err := r.getData(ctx)
if r.mon.UpdateStatusOnError(err, monitoringplugin.UNKNOWN, "error while processing read interfaces request", true) {
readInterfacesRequest := ReadInterfacesRequest{ReadRequest{r.BaseRequest}}
response, err := readInterfacesRequest.process(ctx)
if err != nil {
return nil, err
}

readInterfacesResponse := response.(*ReadInterfacesResponse)

err = r.normalizeInterfaces(readInterfacesResponse.Interfaces)
if r.mon.UpdateStatusOnError(err, monitoringplugin.UNKNOWN, "error while normalizing interfaces", true) {
r.mon.PrintPerformanceData(false)
return &CheckResponse{r.mon.GetInfo()}, nil
}

interfaces, err := r.filterInterfaces(readInterfacesResponse.Interfaces)
if r.mon.UpdateStatusOnError(err, monitoringplugin.UNKNOWN, "error while filtering interfaces", true) {
r.mon.PrintPerformanceData(false)
return &CheckResponse{r.mon.GetInfo()}, nil
}

err = addCheckInterfacePerformanceData(readInterfacesResponse.Interfaces, r.mon)
err = addCheckInterfacePerformanceData(interfaces, r.mon)
if r.mon.UpdateStatusOnError(err, monitoringplugin.UNKNOWN, "error while adding performance data", true) {
r.mon.PrintPerformanceData(false)
return &CheckResponse{r.mon.GetInfo()}, nil
}

if r.PrintInterfaces {
var interfaces []interfaceCheckOutput
for _, interf := range readInterfacesResponse.Interfaces {
var interfaceOutput []interfaceCheckOutput
for _, interf := range interfaces {
var index *string
if interf.IfIndex != nil {
i := fmt.Sprint(*interf.IfIndex)
Expand All @@ -60,9 +74,9 @@ func (r *CheckInterfaceMetricsRequest) process(ctx context.Context) (Response, e
SubType: interf.SubType,
}

interfaces = append(interfaces, x)
interfaceOutput = append(interfaceOutput, x)
}
output, err := parser.Parse(interfaces, "json")
output, err := parser.Parse(interfaceOutput, "json")
if r.mon.UpdateStatusOnError(err, monitoringplugin.UNKNOWN, "error while marshalling output", true) {
r.mon.PrintPerformanceData(false)
return &CheckResponse{r.mon.GetInfo()}, nil
Expand All @@ -73,18 +87,10 @@ func (r *CheckInterfaceMetricsRequest) process(ctx context.Context) (Response, e
return &CheckResponse{r.mon.GetInfo()}, nil
}

func (r *CheckInterfaceMetricsRequest) getData(ctx context.Context) (*ReadInterfacesResponse, error) {
readInterfacesRequest := ReadInterfacesRequest{ReadRequest{r.BaseRequest}}
response, err := readInterfacesRequest.process(ctx)
if err != nil {
return nil, err
}

readInterfacesResponse := response.(*ReadInterfacesResponse)

func (r *CheckInterfaceMetricsRequest) filterInterfaces(interfaces []device.Interface) ([]device.Interface, error) {
var filterIndices []int
out:
for i, interf := range readInterfacesResponse.Interfaces {
for i, interf := range interfaces {
for _, filter := range r.IfTypeFilter {
if interf.IfType != nil && *interf.IfType == filter {
filterIndices = append(filterIndices, i)
Expand Down Expand Up @@ -117,9 +123,9 @@ out:
}
}

readInterfacesResponse.Interfaces = filterInterfaces(readInterfacesResponse.Interfaces, filterIndices, 0)
interfaces = filterInterfaces(interfaces, filterIndices, 0)

return readInterfacesResponse, nil
return interfaces, nil
}

func filterInterfaces(interfaces []device.Interface, toRemove []int, alreadyRemoved int) []device.Interface {
Expand All @@ -129,9 +135,24 @@ func filterInterfaces(interfaces []device.Interface, toRemove []int, alreadyRemo
return append(interfaces[:toRemove[0]-alreadyRemoved], filterInterfaces(interfaces[toRemove[0]+1-alreadyRemoved:], toRemove[1:], toRemove[0]+1)...)
}

func addCheckInterfacePerformanceData(interfaces []device.Interface, r *monitoringplugin.Response) error {
ifDescriptions := make(map[string]*device.Interface)
func (r *CheckInterfaceMetricsRequest) normalizeInterfaces(interfaces []device.Interface) error {
for i, interf := range interfaces {
// if the ifDescr is empty, use the ifIndex as the ifDescr and therefore also as the label for the metrics
if interf.IfDescr == nil {
if interf.IfIndex == nil {
return errors.New("interface does not have an ifDescription and ifIndex")
}
index := fmt.Sprint(*interfaces[i].IfIndex)
interfaces[i].IfDescr = &index
}

if r.ifDescrRegex != nil {
normalizedIfDescr := r.ifDescrRegex.ReplaceAllString(*interfaces[i].IfDescr, *r.IfDescrRegexReplace)
interfaces[i].IfDescr = &normalizedIfDescr
}
}

ifDescriptions := make(map[string]*device.Interface)
// if the device has multiple interfaces with the same ifDescr, the ifDescr will be modified and the ifIndex will be attached
// otherwise, the monitoring plugin will throw an error because of duplicate labels
for i, origInterf := range interfaces {
Expand All @@ -153,15 +174,13 @@ func addCheckInterfacePerformanceData(interfaces []device.Interface, r *monitori
} else {
ifDescriptions[*origInterf.IfDescr] = &interfaces[i]
}
} else {
if interfaces[i].IfIndex == nil {
return errors.New("interface does not have an ifDescription and ifIndex")
}
x := fmt.Sprint(*interfaces[i].IfIndex)
interfaces[i].IfDescr = &x
}
}

return nil
}

func addCheckInterfacePerformanceData(interfaces []device.Interface, r *monitoringplugin.Response) error {
for _, i := range interfaces {
//error_counter_in
if i.IfInErrors != nil {
Expand Down

0 comments on commit 5af65f1

Please sign in to comment.