Merge "[VOL-2736]host and port should be specified as a single argument not as two separate arguments"
diff --git a/VERSION b/VERSION
index b08cf5b..0664a8f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.5-dev
+1.1.6
diff --git a/internal/pkg/commands/devices.go b/internal/pkg/commands/devices.go
index b6864f6..3068902 100644
--- a/internal/pkg/commands/devices.go
+++ b/internal/pkg/commands/devices.go
@@ -41,7 +41,10 @@
ADMINSTATE: {{.AdminState}}
OPERSTATUS: {{.OperStatus}}
CONNECTSTATUS: {{.ConnectStatus}}`
- DEFAULT_DEVICE_VALUE_GET_FORMAT = "table{{.Name}}\t{{.Result}}"
+ DEFAULT_DEVICE_PM_CONFIG_GET_FORMAT = "table{{.DefaultFreq}}\t{{.Grouped}}\t{{.FreqOverride}}"
+ DEFAULT_DEVICE_PM_CONFIG_METRIC_LIST_FORMAT = "table{{.Name}}\t{{.Type}}\t{{.Enabled}}\t{{.SampleFreq}}"
+ DEFAULT_DEVICE_PM_CONFIG_GROUP_LIST_FORMAT = "table{{.GroupName}}\t{{.Enabled}}\t{{.GroupFreq}}"
+ DEFAULT_DEVICE_VALUE_GET_FORMAT = "table{{.Name}}\t{{.Result}}"
)
type DeviceList struct {
@@ -57,6 +60,8 @@
type DeviceId string
+type MetricName string
+type GroupName string
type PortNum uint32
type ValueFlag string
@@ -119,6 +124,71 @@
} `positional-args:"yes"`
}
+type DevicePmConfigsGet struct {
+ ListOutputOptions
+ Args struct {
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type DevicePmConfigMetricList struct {
+ ListOutputOptions
+ Args struct {
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type DevicePmConfigGroupList struct {
+ ListOutputOptions
+ Args struct {
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type DevicePmConfigGroupMetricList struct {
+ ListOutputOptions
+ Args struct {
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ Group GroupName `positional-arg-name:"GROUP_NAME" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type DevicePmConfigFrequencySet struct {
+ OutputOptions
+ Args struct {
+ Frequency uint32 `positional-arg-name:"FREQUENCY" required:"yes"`
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type DevicePmConfigMetricEnable struct {
+ Args struct {
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ Metrics []MetricName `positional-arg-name:"METRIC_NAME" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type DevicePmConfigMetricDisable struct {
+ Args struct {
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ Metrics []MetricName `positional-arg-name:"METRIC_NAME" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type DevicePmConfigGroupEnable struct {
+ Args struct {
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ Groups []GroupName `positional-arg-name:"GROUP_NAME" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type DevicePmConfigGroupDisable struct {
+ Args struct {
+ Id DeviceId `positional-arg-name:"DEVICE_ID" required:"yes"`
+ Groups []GroupName `positional-arg-name:"GROUP_NAME" required:"yes"`
+ } `positional-args:"yes"`
+}
+
type DeviceGetExtValue struct {
ListOutputOptions
Args struct {
@@ -143,6 +213,25 @@
Value struct {
Get DeviceGetExtValue `command:"get"`
} `command:"value"`
+ PmConfig struct {
+ Get DevicePmConfigsGet `command:"get"`
+ Frequency struct {
+ Set DevicePmConfigFrequencySet `command:"set"`
+ } `command:"frequency"`
+ Metric struct {
+ List DevicePmConfigMetricList `command:"list"`
+ Enable DevicePmConfigMetricEnable `command:"enable"`
+ Disable DevicePmConfigMetricDisable `command:"disable"`
+ } `command:"metric"`
+ Group struct {
+ List DevicePmConfigGroupList `command:"list"`
+ Enable DevicePmConfigGroupEnable `command:"enable"`
+ Disable DevicePmConfigGroupDisable `command:"disable"`
+ } `command:"group"`
+ GroupMetric struct {
+ List DevicePmConfigGroupMetricList `command:"list"`
+ } `command:"groupmetric"`
+ } `command:"pmconfig"`
}
var deviceOpts = DeviceOpts{}
@@ -153,6 +242,109 @@
}
}
+func (i *MetricName) Complete(match string) []flags.Completion {
+ conn, err := NewConnection()
+ if err != nil {
+ return nil
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ var deviceId string
+found:
+ for i := len(os.Args) - 1; i >= 0; i -= 1 {
+ switch os.Args[i] {
+ case "enable":
+ fallthrough
+ case "disable":
+ if len(os.Args) > i+1 {
+ deviceId = os.Args[i+1]
+ } else {
+ return nil
+ }
+ break found
+ default:
+ }
+ }
+
+ if len(deviceId) == 0 {
+ return nil
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(deviceId)}
+
+ pmconfigs, err := client.ListDevicePmConfigs(ctx, &id)
+
+ if err != nil {
+ return nil
+ }
+
+ list := make([]flags.Completion, 0)
+ for _, metrics := range pmconfigs.Metrics {
+ if strings.HasPrefix(metrics.Name, match) {
+ list = append(list, flags.Completion{Item: metrics.Name})
+ }
+ }
+
+ return list
+}
+
+func (i *GroupName) Complete(match string) []flags.Completion {
+ conn, err := NewConnection()
+ if err != nil {
+ return nil
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ var deviceId string
+found:
+ for i := len(os.Args) - 1; i >= 0; i -= 1 {
+ switch os.Args[i] {
+ case "list":
+ fallthrough
+ case "enable":
+ fallthrough
+ case "disable":
+ if len(os.Args) > i+1 {
+ deviceId = os.Args[i+1]
+ } else {
+ return nil
+ }
+ break found
+ default:
+ }
+ }
+
+ if len(deviceId) == 0 {
+ return nil
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(deviceId)}
+
+ pmconfigs, err := client.ListDevicePmConfigs(ctx, &id)
+
+ if err != nil {
+ return nil
+ }
+
+ list := make([]flags.Completion, 0)
+ for _, group := range pmconfigs.Groups {
+ if strings.HasPrefix(group.GroupName, match) {
+ list = append(list, flags.Completion{Item: group.GroupName})
+ }
+ }
+ return list
+}
+
func (i *PortNum) Complete(match string) []flags.Completion {
conn, err := NewConnection()
if err != nil {
@@ -473,9 +665,6 @@
if outputFormat == "" {
outputFormat = GetCommandOptionWithDefault("device-ports", "format", DEFAULT_DEVICE_PORTS_FORMAT)
}
- if options.Quiet {
- outputFormat = "{{.Id}}"
- }
orderBy := options.OrderBy
if orderBy == "" {
@@ -592,6 +781,406 @@
return nil
}
+func (options *DevicePmConfigsGet) Execute(args []string) error {
+
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = GetCommandOptionWithDefault("device-pm-configs", "format", DEFAULT_DEVICE_PM_CONFIG_GET_FORMAT)
+ }
+
+ orderBy := options.OrderBy
+ if orderBy == "" {
+ orderBy = GetCommandOptionWithDefault("device-pm-configs", "order", "")
+ }
+
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ Filter: options.Filter,
+ OrderBy: orderBy,
+ OutputAs: toOutputType(options.OutputAs),
+ NameLimit: options.NameLimit,
+ Data: pmConfigs,
+ }
+
+ GenerateOutput(&result)
+ return nil
+
+}
+
+func (options *DevicePmConfigMetricList) Execute(args []string) error {
+
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ if !pmConfigs.Grouped {
+ for _, metric := range pmConfigs.Metrics {
+ if metric.SampleFreq == 0 {
+ metric.SampleFreq = pmConfigs.DefaultFreq
+ }
+ }
+
+ }
+
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = GetCommandOptionWithDefault("device-pm-configs", "format", DEFAULT_DEVICE_PM_CONFIG_METRIC_LIST_FORMAT)
+ }
+
+ orderBy := options.OrderBy
+ if orderBy == "" {
+ orderBy = GetCommandOptionWithDefault("device-pm-configs", "order", "")
+ }
+
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ Filter: options.Filter,
+ OrderBy: orderBy,
+ OutputAs: toOutputType(options.OutputAs),
+ NameLimit: options.NameLimit,
+ Data: pmConfigs.Metrics,
+ }
+
+ GenerateOutput(&result)
+ return nil
+
+}
+
+func (options *DevicePmConfigMetricEnable) Execute(args []string) error {
+
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ if !pmConfigs.Grouped {
+ for _, metric := range pmConfigs.Metrics {
+ for _, mName := range options.Args.Metrics {
+ if string(mName) == metric.Name && !metric.Enabled {
+ metric.Enabled = true
+ _, err := client.UpdateDevicePmConfigs(ctx, pmConfigs)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func (options *DevicePmConfigMetricDisable) Execute(args []string) error {
+
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ if !pmConfigs.Grouped {
+ for _, metric := range pmConfigs.Metrics {
+ for _, mName := range options.Args.Metrics {
+ if string(mName) == metric.Name && metric.Enabled {
+ metric.Enabled = false
+ _, err := client.UpdateDevicePmConfigs(ctx, pmConfigs)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func (options *DevicePmConfigGroupEnable) Execute(args []string) error {
+
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ if pmConfigs.Grouped {
+ for _, group := range pmConfigs.Groups {
+ for _, gName := range options.Args.Groups {
+ if string(gName) == group.GroupName && !group.Enabled {
+ group.Enabled = true
+ _, err := client.UpdateDevicePmConfigs(ctx, pmConfigs)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func (options *DevicePmConfigGroupDisable) Execute(args []string) error {
+
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ if pmConfigs.Grouped {
+ for _, group := range pmConfigs.Groups {
+ for _, gName := range options.Args.Groups {
+ if string(gName) == group.GroupName && group.Enabled {
+ group.Enabled = false
+ _, err := client.UpdateDevicePmConfigs(ctx, pmConfigs)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func (options *DevicePmConfigGroupList) Execute(args []string) error {
+
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ if pmConfigs.Grouped {
+ for _, group := range pmConfigs.Groups {
+ if group.GroupFreq == 0 {
+ group.GroupFreq = pmConfigs.DefaultFreq
+ }
+ }
+
+ }
+
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = GetCommandOptionWithDefault("device-pm-configs", "format", DEFAULT_DEVICE_PM_CONFIG_GROUP_LIST_FORMAT)
+ }
+
+ orderBy := options.OrderBy
+ if orderBy == "" {
+ orderBy = GetCommandOptionWithDefault("device-pm-configs", "order", "")
+ }
+
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ Filter: options.Filter,
+ OrderBy: orderBy,
+ OutputAs: toOutputType(options.OutputAs),
+ NameLimit: options.NameLimit,
+ Data: pmConfigs.Groups,
+ }
+
+ GenerateOutput(&result)
+ return nil
+
+}
+
+func (options *DevicePmConfigGroupMetricList) Execute(args []string) error {
+
+ var metrics []*voltha.PmConfig
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ for _, groups := range pmConfigs.Groups {
+
+ if string(options.Args.Group) == groups.GroupName {
+ for _, metric := range groups.Metrics {
+ if metric.SampleFreq == 0 && groups.GroupFreq == 0 {
+ metric.SampleFreq = pmConfigs.DefaultFreq
+ } else {
+ metric.SampleFreq = groups.GroupFreq
+ }
+ }
+ metrics = groups.Metrics
+ }
+ }
+
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = GetCommandOptionWithDefault("device-pm-configs", "format", DEFAULT_DEVICE_PM_CONFIG_METRIC_LIST_FORMAT)
+ }
+
+ orderBy := options.OrderBy
+ if orderBy == "" {
+ orderBy = GetCommandOptionWithDefault("device-pm-configs", "order", "")
+ }
+
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ Filter: options.Filter,
+ OrderBy: orderBy,
+ OutputAs: toOutputType(options.OutputAs),
+ NameLimit: options.NameLimit,
+ Data: metrics,
+ }
+
+ GenerateOutput(&result)
+ return nil
+
+}
+
+func (options *DevicePmConfigFrequencySet) Execute(args []string) error {
+
+ conn, err := NewConnection()
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ client := voltha.NewVolthaServiceClient(conn)
+
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ defer cancel()
+
+ id := voltha.ID{Id: string(options.Args.Id)}
+
+ pmConfigs, err := client.ListDevicePmConfigs(ctx, &id)
+ if err != nil {
+ return err
+ }
+
+ pmConfigs.DefaultFreq = options.Args.Frequency
+
+ _, err = client.UpdateDevicePmConfigs(ctx, pmConfigs)
+ if err != nil {
+ return err
+ }
+
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = GetCommandOptionWithDefault("device-pm-configs", "format", DEFAULT_DEVICE_PM_CONFIG_GET_FORMAT)
+ }
+ if options.Quiet {
+ outputFormat = "{{.Id}}"
+ }
+
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ OutputAs: toOutputType(options.OutputAs),
+ NameLimit: options.NameLimit,
+ Data: pmConfigs,
+ }
+
+ GenerateOutput(&result)
+ return nil
+
+}
+
type ReturnValueRow struct {
Name string `json:"name"`
Result interface{} `json:"result"`
diff --git a/internal/pkg/commands/log.go b/internal/pkg/commands/log.go
index b142804..52ab6cb 100644
--- a/internal/pkg/commands/log.go
+++ b/internal/pkg/commands/log.go
@@ -624,7 +624,7 @@
if len(options.Args.Component) == 0 {
componentList, err = cm.RetrieveComponentList(ctx, config.ConfigTypeLogLevel)
if err != nil {
- return fmt.Errorf("Unable to retrieve list of voltha components : %s ", err)
+ return fmt.Errorf("Unable to retrieve list of voltha components : %s \nIs ETCD available at %s:%d?", err, host, port)
}
} else {
componentList = toStringArray(options.Args.Component)
diff --git a/internal/pkg/commands/logicaldevices.go b/internal/pkg/commands/logicaldevices.go
index e59f69d..3a5dd66 100644
--- a/internal/pkg/commands/logicaldevices.go
+++ b/internal/pkg/commands/logicaldevices.go
@@ -21,13 +21,14 @@
"github.com/golang/protobuf/ptypes/empty"
flags "github.com/jessevdk/go-flags"
"github.com/opencord/voltctl/pkg/format"
+ "github.com/opencord/voltha-protos/v3/go/openflow_13"
"github.com/opencord/voltha-protos/v3/go/voltha"
"strings"
)
const (
DEFAULT_LOGICAL_DEVICE_FORMAT = "table{{ .Id }}\t{{printf \"%016x\" .DatapathId}}\t{{.RootDeviceId}}\t{{.Desc.SerialNum}}\t{{.SwitchFeatures.NBuffers}}\t{{.SwitchFeatures.NTables}}\t{{printf \"0x%08x\" .SwitchFeatures.Capabilities}}"
- DEFAULT_LOGICAL_DEVICE_PORT_FORMAT = "table{{.Id}}\t{{.DeviceId}}\t{{.DevicePortNo}}\t{{.RootPort}}\t{{.Openflow.PortNo}}\t{{.Openflow.HwAddr}}\t{{.Openflow.Name}}\t{{.Openflow.State}}\t{{.Openflow.Features.Current}}\t{{.Openflow.Bitrate.Current}}"
+ DEFAULT_LOGICAL_DEVICE_PORT_FORMAT = "table{{.Id}}\t{{.DeviceId}}\t{{.DevicePortNo}}\t{{.RootPort}}\t{{.OfpPortStats.PortNo}}\t{{.OfpPort.HwAddr}}\t{{.OfpPort.Name}}\t{{printf \"0x%08x\" .OfpPort.State}}\t{{printf \"0x%08x\" .OfpPort.Curr}}\t{{.OfpPort.CurrSpeed}}"
DEFAULT_LOGICAL_DEVICE_INSPECT_FORMAT = `ID: {{.Id}}
DATAPATHID: {{.DatapathId}}
ROOTDEVICEID: {{.RootDeviceId}}
@@ -173,6 +174,16 @@
return err
}
+ // ensure no nil pointers
+ for _, v := range ports.Items {
+ if v.OfpPortStats == nil {
+ v.OfpPortStats = &openflow_13.OfpPortStats{}
+ }
+ if v.OfpPort == nil {
+ v.OfpPort = &openflow_13.OfpPort{}
+ }
+ }
+
outputFormat := CharReplacer.Replace(options.Format)
if outputFormat == "" {
outputFormat = GetCommandOptionWithDefault("logical-device-ports", "format", DEFAULT_LOGICAL_DEVICE_PORT_FORMAT)
diff --git a/pkg/filter/filter.go b/pkg/filter/filter.go
index f566d94..e704790 100644
--- a/pkg/filter/filter.go
+++ b/pkg/filter/filter.go
@@ -17,6 +17,7 @@
import (
"fmt"
+ "log"
"reflect"
"regexp"
"strings"
@@ -138,37 +139,65 @@
return true
}
-func (f Filter) Evaluate(item interface{}) bool {
- val := reflect.ValueOf(item)
-
+func (f Filter) EvaluateTerm(k string, v FilterTerm, val reflect.Value, recurse bool) bool {
// If we have been given a pointer, then deference it
if val.Kind() == reflect.Ptr {
val = reflect.Indirect(val)
}
- for k, v := range f {
- field := val.FieldByName(k)
+ // If the user gave us an explicitly named dotted field, then split it
+ if strings.Contains(k, ".") {
+ parts := strings.SplitN(k, ".", 2)
+ field := val.FieldByName(parts[0])
if !field.IsValid() {
+ log.Printf("Failed to find dotted field %s while filtering\n", parts[0])
return false
}
+ return f.EvaluateTerm(parts[1], v, field, false)
+ }
- if (field.Kind() == reflect.Slice) || (field.Kind() == reflect.Array) {
- // For an array, check to see if any item matches
- someMatch := false
- for i := 0; i < field.Len(); i++ {
- arrayElem := field.Index(i)
- if testField(v, arrayElem) {
- someMatch = true
- }
- }
- if !someMatch {
- return false
- }
- } else {
- if !testField(v, field) {
- return false
+ field := val.FieldByName(k)
+ if !field.IsValid() {
+ log.Printf("Failed to find field %s while filtering\n", k)
+ return false
+ }
+
+ if (field.Kind() == reflect.Slice) || (field.Kind() == reflect.Array) {
+ // For an array, check to see if any item matches
+ someMatch := false
+ for i := 0; i < field.Len(); i++ {
+ arrayElem := field.Index(i)
+ if testField(v, arrayElem) {
+ someMatch = true
}
}
+ if !someMatch {
+ //if recurse && val.Kind() == reflect.Struct {
+ // TODO: implement automatic recursion when the user did not
+ // use a dotted notation. Go through the list of fields
+ // in the struct, recursively check each one.
+ //}
+ return false
+ }
+ } else {
+ if !testField(v, field) {
+ return false
+ }
}
+
+ return true
+}
+
+func (f Filter) Evaluate(item interface{}) bool {
+ val := reflect.ValueOf(item)
+
+ for k, v := range f {
+ matches := f.EvaluateTerm(k, v, val, true)
+ if !matches {
+ // If any of the filter fail, the overall match fails
+ return false
+ }
+ }
+
return true
}
diff --git a/pkg/order/order.go b/pkg/order/order.go
index 715b302..0f324cd 100644
--- a/pkg/order/order.go
+++ b/pkg/order/order.go
@@ -92,6 +92,15 @@
sort.SliceStable(data, func(i, j int) bool {
left := reflect.ValueOf(slice.Index(i).Interface())
right := reflect.ValueOf(slice.Index(j).Interface())
+
+ if left.Kind() == reflect.Ptr {
+ left = reflect.Indirect(left)
+ }
+
+ if right.Kind() == reflect.Ptr {
+ right = reflect.Indirect(right)
+ }
+
for _, term := range s {
fleft := left.FieldByName(term.Name)
fright := right.FieldByName(term.Name)