cmd: automatic inverting of DatasetMapFilter

This commit is contained in:
Christian Schwarz 2017-09-13 22:55:10 +02:00
parent 1deaa459c8
commit e2149de840
2 changed files with 70 additions and 3 deletions

View File

@ -4,8 +4,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/zrepl/zrepl/zfs"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/zrepl/zrepl/zfs"
) )
type DatasetMapFilter struct { type DatasetMapFilter struct {
@ -144,14 +145,46 @@ func (m DatasetMapFilter) Filter(p *zfs.DatasetPath) (pass bool, err error) {
return return
} }
// Construct a new filter-only DatasetMapFilter from a mapping
// The new filter allows excactly those paths that were not forbidden by the mapping.
func (m DatasetMapFilter) InvertedFilter() (inv *DatasetMapFilter, err error) {
if m.filterOnly {
err = errors.Errorf("can only invert mappings")
return
}
inv = &DatasetMapFilter{
make([]datasetMapFilterEntry, len(m.entries)),
true,
}
for i, e := range m.entries {
inv.entries[i].path, err = zfs.NewDatasetPath(e.mapping)
if err != nil {
err = errors.Wrapf(err, "mapping cannot be inverted: '%s' is not a dataset path: %s", e.mapping)
return
}
inv.entries[i].mapping = MapFilterResultOk
inv.entries[i].subtreeMatch = e.subtreeMatch
}
return inv, nil
}
const (
MapFilterResultOk string = "ok"
MapFilterResultOmit string = "omit"
)
// Parse a dataset filter result // Parse a dataset filter result
func parseDatasetFilterResult(result string) (pass bool, err error) { func parseDatasetFilterResult(result string) (pass bool, err error) {
l := strings.ToLower(result) l := strings.ToLower(result)
switch strings.ToLower(l) { switch strings.ToLower(l) {
case "ok": case MapFilterResultOk:
pass = true pass = true
return return
case "omit": case MapFilterResultOmit:
return return
default: default:
err = fmt.Errorf("'%s' is not a valid filter result", result) err = fmt.Errorf("'%s' is not a valid filter result", result)

View File

@ -4,6 +4,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/kr/pretty"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zrepl/zrepl/util" "github.com/zrepl/zrepl/util"
"github.com/zrepl/zrepl/zfs" "github.com/zrepl/zrepl/zfs"
@ -135,3 +136,36 @@ func TestDatasetMapFilter(t *testing.T) {
expectFilter(filter2, "foo", false) // default to omit expectFilter(filter2, "foo", false) // default to omit
} }
func TestDatasetMapFilter_InvertedFilter(t *testing.T) {
mapspec := map[string]string{
"a/b": "1/2",
"a/b/c<": "3",
"a/b/c/d<": "1/2/a",
}
m, err := parseDatasetMapFilter(mapspec, false)
assert.Nil(t, err)
inv, err := m.InvertedFilter()
assert.Nil(t, err)
t.Log(pretty.Sprint(inv))
expectMapping := func(m *DatasetMapFilter, ps string, expRes bool) {
p, err := zfs.NewDatasetPath(ps)
assert.Nil(t, err)
r, err := m.Filter(p)
assert.Nil(t, err)
assert.Equal(t, expRes, r)
}
expectMapping(inv, "4", false)
expectMapping(inv, "3", true)
expectMapping(inv, "3/x", true)
expectMapping(inv, "1", false)
expectMapping(inv, "1/2", true)
expectMapping(inv, "1/2/3", false)
expectMapping(inv, "1/2/a/b", true)
}