Repository: kentik/ktranslate (go)

Issue:
💡 `GetCondition` needs to respect string matching as well as integer values
revisiting PR #350 here...

The [GetCondition](https://github.com/kentik/ktranslate/blob/65e861175b50a96ecffa85ce7659611ed737092c/pkg/inputs/snmp/mibs/profile.go#L950-L968) function looks like it will error if the comparison is anything but an integer right now.

We have a need to expand this functionality to support a string match as well for OIDs that use the `SnmpAdminString` type like this:
```yaml
      - name: cempMemPoolHCUsed
        OID: 1.3.6.1.4.1.9.9.221.1.1.1.1.18
        poll_time_sec: 60
        tag: MemoryUsed
        allow_duplicate: true
        condition: cempMemPoolName="DP System memory"
```

Pull request description:
Fix 720, allow strings in the comparison operator
Closes #720 

Does this work for you? I've just updated the comparison operator to handle strings and ints. Also some more unit tests. Tested cases:

```
		`cempMemPoolName="DP System memory"`: []condTest{
			condTest{si: "ddd", r: false},
			condTest{si: "DP System memory", r: true},
		},
		`MemoryCache=4`: []condTest{
			condTest{ii: 2, r: false},
			condTest{ii: 4, r: true},
		},
```




Patch:
diff --git a/pkg/inputs/snmp/metrics/device_metrics.go b/pkg/inputs/snmp/metrics/device_metrics.go
index bbb3605..9638140 100644
--- a/pkg/inputs/snmp/metrics/device_metrics.go
+++ b/pkg/inputs/snmp/metrics/device_metrics.go
@@ -480,7 +480,7 @@ func (w wrapper) checkCondition(idx string, results []wrapper) bool { // Check c
 			oidNameWr := wr.mib.GetName() // Does the name match our target?
 			if oidNameWr == w.mib.Condition.TargetName {
 				// If it does, does it match our target value?
-				return snmp_util.ToInt64(wr.variable.Value) == w.mib.Condition.TargetValue
+				return w.mib.Condition.Check(wr.variable.Value)
 			}
 		}
 		return true // Keep this one because condition evals to true.
diff --git a/pkg/inputs/snmp/mibs/profile.go b/pkg/inputs/snmp/mibs/profile.go
index 11d89cd..28dad0d 100644
--- a/pkg/inputs/snmp/mibs/profile.go
+++ b/pkg/inputs/snmp/mibs/profile.go
@@ -953,7 +953,11 @@ func (o *OID) GetCondition(log logger.ContextL) *kt.MibCondition {
 		if len(pts) == 2 {
 			val, err := strconv.Atoi(pts[1])
 			if err != nil {
-				log.Errorf("Skipping invalid profile condition in %s: %s. RHS (%s) must be an int and operator must be '='.", o.Name, o.Condition, pts[1])
+				log.Infof("Using profile condition as string in %s: %s = %s.", o.Name, pts[0], pts[1])
+				return &kt.MibCondition{
+					TargetName:   pts[0],
+					TargetString: strings.Trim(pts[1], ` "`),
+				}
 			} else {
 				return &kt.MibCondition{
 					TargetName:  pts[0],
diff --git a/pkg/kt/snmp.go b/pkg/kt/snmp.go
index bcc2c67..b42d180 100644
--- a/pkg/kt/snmp.go
+++ b/pkg/kt/snmp.go
@@ -373,8 +373,41 @@ const (
 )
 
 type MibCondition struct {
-	TargetName  string
-	TargetValue int64
+	TargetName   string
+	TargetValue  int64
+	TargetString string
+}
+
+func (mc *MibCondition) Check(input interface{}) bool {
+	if mc == nil {
+		return false
+	}
+	switch v := input.(type) {
+	case uint:
+		return int64(v) == mc.TargetValue
+	case uint8: // same as byte
+		return int64(v) == mc.TargetValue
+	case uint16:
+		return int64(v) == mc.TargetValue
+	case uint32:
+		return int64(v) == mc.TargetValue
+	case uint64:
+		return int64(v) == mc.TargetValue
+	case int:
+		return int64(v) == mc.TargetValue
+	case int8:
+		return int64(v) == mc.TargetValue
+	case int16:
+		return int64(v) == mc.TargetValue
+	case int32: // same as rune
+		return int64(v) == mc.TargetValue
+	case int64:
+		return int64(v) == mc.TargetValue
+	case string:
+		return v == mc.TargetString
+	default:
+		return false
+	}
 }
 
 type Mib struct {


Test patch:
diff --git a/pkg/inputs/snmp/mibs/profile_test.go b/pkg/inputs/snmp/mibs/profile_test.go
index 0373ce3..3608ff2 100644
--- a/pkg/inputs/snmp/mibs/profile_test.go
+++ b/pkg/inputs/snmp/mibs/profile_test.go
@@ -224,3 +224,37 @@ func TestGetTableName(t *testing.T) {
 		assert.Equal(t, expected, res)
 	}
 }
+
+type condTest struct {
+	si string
+	ii int
+	r  bool
+}
+
+func TestGetCondition(t *testing.T) {
+	l := lt.NewTestContextL(logger.NilContext, t)
+	tests := map[string][]condTest{
+		`cempMemPoolName="DP System memory"`: []condTest{
+			condTest{si: "ddd", r: false},
+			condTest{si: "DP System memory", r: true},
+		},
+		`MemoryCache=4`: []condTest{
+			condTest{ii: 2, r: false},
+			condTest{ii: 4, r: true},
+		},
+	}
+
+	for cond, expected := range tests {
+		oid := OID{
+			Condition: cond,
+		}
+		res := oid.GetCondition(l)
+		for _, tst := range expected {
+			if tst.ii != 0 {
+				assert.Equal(t, tst.r, res.Check(tst.ii), tst.ii)
+			} else {
+				assert.Equal(t, tst.r, res.Check(tst.si), tst.si)
+			}
+		}
+	}
+}