From 04e4442ac293102d00f2ee5cd5874f619d699913 Mon Sep 17 00:00:00 2001
From: Pavel Vorobyov
Date: Mon, 1 Jun 2020 11:22:46 +0300
Subject: [PATCH] expression exclude fixed
---
store/parser.go | 15 ---------
store/store.go | 41 +++++++++++++++++--------
store/store_test.go | 62 ++++++++++++++++++++++++++++++++++++--
stringslice/stringslice.go | 8 +++++
4 files changed, 95 insertions(+), 31 deletions(-)
diff --git a/store/parser.go b/store/parser.go
index c002cd4..3a957df 100644
--- a/store/parser.go
+++ b/store/parser.go
@@ -4,8 +4,6 @@ import (
"fmt"
"regexp"
"strings"
-
- "github.com/viert/xc/stringslice"
)
type tokenType int
@@ -49,19 +47,6 @@ func newToken() *token {
return ct
}
-func maybeAddHost(hostlist *[]string, host string, exclude bool) {
- newHl := *hostlist
- if exclude {
- hIdx := stringslice.Index(newHl, host)
- if hIdx >= 0 {
- newHl = append(newHl[:hIdx], newHl[hIdx+1:]...)
- }
- } else {
- newHl = append(newHl, host)
- }
- *hostlist = newHl
-}
-
func parseExpression(expr []rune) ([]*token, error) {
ct := newToken()
res := make([]*token, 0)
diff --git a/store/store.go b/store/store.go
index 8b7a29c..2978733 100644
--- a/store/store.go
+++ b/store/store.go
@@ -22,6 +22,12 @@ type Store struct {
naturalSort bool
}
+// expandedToken represents one token expanded into a hostlist
+type expandedToken struct {
+ exclude bool
+ hosts []string
+}
+
func (s *Store) reinitStore() {
s.datacenters = new(dcstore)
s.datacenters._id = make(map[string]*Datacenter)
@@ -163,14 +169,19 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
return nil, err
}
- hostlist := make([][]string, 0)
+ expanded := make([]expandedToken, 0)
for _, token := range tokens {
- singleTokenHosts := make([]string, 0)
+
+ etoken := expandedToken{
+ exclude: token.Exclude,
+ hosts: make([]string, 0),
+ }
+
switch token.Type {
case tTypeHostRegexp:
for _, host := range s.matchHost(token.RegexpFilter) {
- maybeAddHost(&singleTokenHosts, host, token.Exclude)
+ etoken.hosts = append(etoken.hosts, host)
}
case tTypeHost:
@@ -191,7 +202,7 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
}
}
}
- maybeAddHost(&singleTokenHosts, host, token.Exclude)
+ etoken.hosts = append(etoken.hosts, host)
}
case tTypeGroup:
@@ -221,7 +232,7 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
continue
}
}
- maybeAddHost(&singleTokenHosts, host.FQDN, token.Exclude)
+ etoken.hosts = append(etoken.hosts, host.FQDN)
}
}
@@ -271,27 +282,31 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
}
}
- maybeAddHost(&singleTokenHosts, host.FQDN, token.Exclude)
+ etoken.hosts = append(etoken.hosts, host.FQDN)
}
}
}
- if len(singleTokenHosts) > 0 {
- hostlist = append(hostlist, singleTokenHosts)
+ if len(etoken.hosts) > 0 {
+ expanded = append(expanded, etoken)
}
}
results := make([]string, 0)
- for _, sthosts := range hostlist {
+ for _, etoken := range expanded {
// sorting within one expression token only
// the order of tokens themselves should be respected
if s.naturalSort {
- natsort.Sort(sthosts)
+ natsort.Sort(etoken.hosts)
} else {
- sort.Strings(sthosts)
+ sort.Strings(etoken.hosts)
}
- for _, host := range sthosts {
- results = append(results, host)
+ if etoken.exclude {
+ for _, exhost := range etoken.hosts {
+ stringslice.Remove(&results, exhost)
+ }
+ } else {
+ results = append(results, etoken.hosts...)
}
}
return results, nil
diff --git a/store/store_test.go b/store/store_test.go
index d99e0cc..08f0e31 100644
--- a/store/store_test.go
+++ b/store/store_test.go
@@ -60,7 +60,15 @@ func (fb *FakeBackend) Load() error {
Tags: []string{"special"},
}
- fb.groups = append(fb.groups, group1, group2, group3)
+ group4 := &Group{
+ ID: "g4",
+ Name: "group4",
+ WorkGroupID: "wg1",
+ ParentID: "",
+ Tags: []string{},
+ }
+
+ fb.groups = append(fb.groups, group1, group2, group3, group4)
dc1 := &Datacenter{
ID: "dc1",
@@ -93,7 +101,25 @@ func (fb *FakeBackend) Load() error {
DatacenterID: "dc2",
}
- fb.hosts = append(fb.hosts, host, host2)
+ host3 := &Host{
+ ID: "h3",
+ FQDN: "host3.example.com",
+ Aliases: []string{"host3", "host3.i"},
+ Tags: []string{},
+ GroupID: "g4",
+ DatacenterID: "dc2",
+ }
+
+ host4 := &Host{
+ ID: "h4",
+ FQDN: "host4.example.com",
+ Aliases: []string{"host4", "host4.i"},
+ Tags: []string{},
+ GroupID: "g4",
+ DatacenterID: "dc2",
+ }
+
+ fb.hosts = append(fb.hosts, host, host2, host3, host4)
return nil
}
@@ -214,7 +240,7 @@ func TestHostlist1(t *testing.T) {
}
if len(hostlist) != 1 {
- t.Errorf("hostlist %%group1#special is expected to contain exactly 1 element")
+ t.Errorf("hostlist %%group1#special is expected to contain exactly 1 element, %v", hostlist)
return
}
@@ -244,3 +270,33 @@ func TestHostlist2(t *testing.T) {
return
}
}
+
+func TestExclude(t *testing.T) {
+ fb := newFB()
+ fb.Load()
+
+ s, err := CreateStore(fb)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ hostlist, err := s.HostList([]rune("%group4"))
+ if err != nil {
+ t.Error(err)
+ }
+
+ if len(hostlist) != 2 {
+ t.Errorf("hostlist is expected to consist of exactly two elements, %v", hostlist)
+ }
+
+ hostlist, err = s.HostList([]rune("%group4,-host3.example.com"))
+ if err != nil {
+ t.Error(err)
+ }
+
+ if len(hostlist) != 1 {
+ t.Errorf("hostlist is expected to consist of exactly one element, %v", hostlist)
+ }
+
+}
diff --git a/stringslice/stringslice.go b/stringslice/stringslice.go
index ce6d189..b3dc153 100644
--- a/stringslice/stringslice.go
+++ b/stringslice/stringslice.go
@@ -14,3 +14,11 @@ func Index(arr []string, item string) int {
func Contains(arr []string, item string) bool {
return Index(arr, item) >= 0
}
+
+// Remove removes an item from array if it's in there
+func Remove(arr *[]string, item string) {
+ idx := Index(*arr, item)
+ if idx >= 0 {
+ *arr = append((*arr)[0:idx], (*arr)[idx+1:len(*arr)]...)
+ }
+}