Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 74 additions & 51 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,68 +197,91 @@ func isIPExist(interfaces []interface{}, search string) bool {
return result
}

func itemValueMatchesFilter(itemValue gjson.Result, key string, queryValue string) bool {
searchValues := strings.Split(queryValue, ",")

switch itemValueType := itemValue.Type.String(); itemValueType {
case "JSON":
// ALL search values must match (AND logic)
for _, search := range searchValues {
switch key {
case "status.conditions":
if !isMigratable(itemValue.Value().([]interface{}), search) {
return false
}
case "status.interfaces":
if !isIPExist(itemValue.Value().([]interface{}), search) {
return false
}
default:
if !labelsIncludes(itemValue.Value().(map[string]interface{}), search) {
return false
}
}
}
return true

case "String":
// ANY search value can match (OR logic)
for _, search := range searchValues {
if strings.Contains(strings.ToLower(itemValue.Str), strings.ToLower(search)) {
return true
}
}
return false

case "Null":
// ALL search values must be "null" (AND logic)
for _, search := range searchValues {
if strings.ToLower(search) != "null" {
return false
}
}
return true

default:
return false // Unsupported type
}
}

const KEY_DELIMITER = "|"

func FilterResponseQuery(bodyBytes []byte, query url.Values) map[string]interface{} {
items := gjson.ParseBytes(bodyBytes).Get("items").Array()
filteredJson := []interface{}{}
isFilters := len(query) != 0
if isFilters {
nextItem:
for _, item := range items {
for key, val := range query {
for _, match := range val {
itemValue := item.Get(key)
matches := strings.Split(match, ",")
isMatch := false
for index, search := range matches {
switch typeResult := itemValue.Type.String(); typeResult {
case "JSON":
{
// case of json and all conditions (and) must apply (labels by input)
if key == "status.conditions" {
isMigrate := isMigratable(itemValue.Value().([]interface{}), search)
if !isMigrate {
continue nextItem
}
continue
}
if key == "status.interfaces" {
isIP := isIPExist(itemValue.Value().([]interface{}), search)
if !isIP {
continue nextItem
}
continue
}
okInclude := labelsIncludes(itemValue.Value().(map[string]interface{}), search)
if !okInclude {
continue nextItem
}
}

case "String":
{
//case of string and at least one must match (or) apply (name, template, status, os)
okString := strings.Contains(strings.ToLower(itemValue.Str), strings.ToLower(search))
if okString {
isMatch = true
break
}
if index == len(matches)-1 && !isMatch {
continue nextItem
}
}
case "Null":
{
if strings.ToLower(search) == "null" {
break
}
continue nextItem
}
default:
continue nextItem
for key, values := range query {
// values is a slice, because same key can repeat in the query string
// e.g. same.key=value1,value2&same.key=value3 results in values = []string{"value1,value2", "value3"}
// in Kubevirt UI the query string is created such way that the key doesn't repeat, so we can use values[0]
value := values[0]

if strings.Contains(key, KEY_DELIMITER) {
keys := strings.Split(key, KEY_DELIMITER)
keyMatched := false

for _, key := range keys {
itemValue := item.Get(key)
if itemValueMatchesFilter(itemValue, key, value) {
keyMatched = true
break
}
}

if !keyMatched {
continue nextItem
}
} else {
itemValue := item.Get(key)
if !itemValueMatchesFilter(itemValue, key, value) {
continue nextItem
}
}
}

valueJson := map[string]interface{}{}
err := json.Unmarshal([]byte(item.Raw), &valueJson)
if err != nil {
Expand Down