File: filter.go

package info (click to toggle)
aws-nuke 2.16.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 1,852 kB
  • sloc: makefile: 17; sh: 1
file content (129 lines) | stat: -rw-r--r-- 2,492 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package config

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/mb0/glob"
)

type FilterType string

const (
	FilterTypeEmpty         FilterType = ""
	FilterTypeExact                    = "exact"
	FilterTypeGlob                     = "glob"
	FilterTypeRegex                    = "regex"
	FilterTypeContains                 = "contains"
	FilterTypeDateOlderThan            = "dateOlderThan"
)

type Filters map[string][]Filter

func (f Filters) Merge(f2 Filters) {
	for resourceType, filter := range f2 {
		f[resourceType] = append(f[resourceType], filter...)
	}
}

type Filter struct {
	Property string
	Type     FilterType
	Value    string
	Invert   string
}

func (f Filter) Match(o string) (bool, error) {
	switch f.Type {
	case FilterTypeEmpty:
		fallthrough

	case FilterTypeExact:
		return f.Value == o, nil

	case FilterTypeContains:
		return strings.Contains(o, f.Value), nil

	case FilterTypeGlob:
		return glob.Match(f.Value, o)

	case FilterTypeRegex:
		re, err := regexp.Compile(f.Value)
		if err != nil {
			return false, err
		}
		return re.MatchString(o), nil

	case FilterTypeDateOlderThan:
		if o == "" {
			return false, nil
		}
		duration, err := time.ParseDuration(f.Value)
		if err != nil {
			return false, err
		}
		fieldTime, err := parseDate(o)
		if err != nil {
			return false, err
		}
		fieldTimeWithOffset := fieldTime.Add(duration)

		return fieldTimeWithOffset.After(time.Now()), nil

	default:
		return false, fmt.Errorf("unknown type %s", f.Type)
	}
}

func parseDate(input string) (time.Time, error) {
	if i, err := strconv.ParseInt(input, 10, 64); err == nil {
		t := time.Unix(i, 0)
		return t, nil
	}

	formats := []string{"2006-01-02",
		"2006/01/02",
		"2006-01-02T15:04:05Z",
		time.RFC3339Nano, // Format of t.MarshalText() and t.MarshalJSON()
		time.RFC3339,
	}
	for _, f := range formats {
		t, err := time.Parse(f, input)
		if err == nil {
			return t, nil
		}
	}
	return time.Now(), fmt.Errorf("unable to parse time %s", input)
}

func (f *Filter) UnmarshalYAML(unmarshal func(interface{}) error) error {
	var value string

	if unmarshal(&value) == nil {
		f.Type = FilterTypeExact
		f.Value = value
		return nil
	}

	m := map[string]string{}
	err := unmarshal(m)
	if err != nil {
		return err
	}

	f.Type = FilterType(m["type"])
	f.Value = m["value"]
	f.Property = m["property"]
	f.Invert = m["invert"]
	return nil
}

func NewExactFilter(value string) Filter {
	return Filter{
		Type:  FilterTypeExact,
		Value: value,
	}
}