kvm/vendor/github.com/pilebones/go-udev/netlink/matcher.go

194 lines
3.6 KiB
Go

package netlink
import (
"regexp"
"strings"
)
type Matcher interface {
Evaluate(e UEvent) bool
EvaluateAction(a KObjAction) bool
EvaluateEnv(e map[string]string) bool
Compile() error
String() string
}
type RuleDefinition struct {
Action *string `json:"action,omitempty"`
Env map[string]string `json:"env,omitempty"`
rule *rule
}
// Evaluate return true if all condition match uevent and envs in rule exists in uevent
func (r RuleDefinition) Evaluate(e UEvent) bool {
// Compile if needed
if r.rule == nil {
if err := r.Compile(); err != nil {
return false
}
}
return r.EvaluateAction(e.Action) && r.EvaluateEnv(e.Env)
}
// EvaluateAction return true if the action match
func (r RuleDefinition) EvaluateAction(a KObjAction) bool {
// Compile if needed
if r.rule == nil {
if err := r.Compile(); err != nil {
return false
}
}
if r.rule.Action == nil {
return true
}
return r.rule.Action.MatchString(a.String())
}
// EvaluateEnv return true if all env match and exists
func (r RuleDefinition) EvaluateEnv(e map[string]string) bool {
// Compile if needed
if r.rule == nil {
if err := r.Compile(); err != nil {
return false
}
}
return r.rule.Env.Evaluate(e)
}
// Compile prepare rule definition to be able to Evaluate() an UEvent
func (r *RuleDefinition) Compile() error {
r.rule = &rule{
Env: make(map[string]*regexp.Regexp),
}
if r.Action != nil {
action, err := regexp.Compile(*(r.Action))
if err != nil {
return err
}
r.rule.Action = action
}
for k, v := range r.Env {
reg, err := regexp.Compile(v)
if err != nil {
return err
}
r.rule.Env[k] = reg
}
return nil
}
func (r RuleDefinition) String() string {
b := strings.Builder{}
b.WriteString("ruledef ( ")
if r.Action == nil && len(r.Env) == 0 {
b.WriteString("empty")
} else {
if r.Action != nil {
b.WriteString("action=")
b.WriteString(*r.Action)
b.WriteRune(' ')
}
for k, v := range r.Env {
b.WriteString("env.")
b.WriteString(k)
b.WriteRune('=')
b.WriteString(v)
b.WriteRune(' ')
}
}
b.WriteString(")")
return b.String()
}
// rule is the compiled version of the RuleDefinition
type rule struct {
Action *regexp.Regexp
Env Env
}
type Env map[string]*regexp.Regexp
func (e Env) Evaluate(env map[string]string) bool {
foundEnv := (len(e) == 0)
for envName, reg := range e {
foundEnv = false
for k, v := range env {
if k == envName {
foundEnv = true
if !reg.MatchString(v) {
return false
}
break
}
}
if !foundEnv {
return false
}
}
return foundEnv
}
// RuleDefinitions is like chained rule with OR operator
type RuleDefinitions struct {
Rules []RuleDefinition
}
func (rs *RuleDefinitions) AddRule(r RuleDefinition) {
rs.Rules = append(rs.Rules, r)
}
func (rs *RuleDefinitions) Compile() error {
for _, r := range rs.Rules {
if err := r.Compile(); err != nil {
return err
}
}
return nil
}
func (rs RuleDefinitions) Evaluate(e UEvent) bool {
for _, r := range rs.Rules {
if r.Evaluate(e) {
return true
}
}
return false
}
// EvaluateAction return true if the action match
func (rs RuleDefinitions) EvaluateAction(a KObjAction) (match bool) {
for _, r := range rs.Rules {
if r.EvaluateAction(a) {
return true
}
}
return false
}
// EvaluateEnv return true if almost one env match all regexp
func (rs RuleDefinitions) EvaluateEnv(e map[string]string) bool {
for _, r := range rs.Rules {
if r.EvaluateEnv(e) {
return true
}
}
return false
}
func (rs RuleDefinitions) String() string {
output := ""
for _, v := range rs.Rules {
output += "- " + v.String() + "\n"
}
return output
}