8093933500
Work out which hosts a puppet-prod change can affect, so a catalog test can
fan out over exactly those hosts instead of the whole estate.
- add cmd/catalog-impact and internal/impact
- map hieradata paths onto fact selectors from the hiera hierarchy
- trace manifest classes back to role classes through include, contain,
class {} and hiera_include, to a fixed point
- fetch the estate fact table from pdbmux in one query via FactsByName
- widen to all hosts, loudly, for any path that matches no rule
- ship the binary and its completions in the RPM
89 lines
3.7 KiB
Go
89 lines
3.7 KiB
Go
package impact
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
// fixtureNodes mirrors the shape of the real estate: one country, two regions,
|
|
// physical and virtual hosts, and a mix of OS releases.
|
|
func fixtureNodes() []Node {
|
|
return []Node{
|
|
{Certname: "web1", Role: "roles::apps::media::jellyfin",
|
|
Tier1: "apps", Tier2: "media", Tier3: "jellyfin",
|
|
Country: "au", Region: "syd1", Virtual: "lxc",
|
|
OSName: "AlmaLinux", OSMajor: "9", OSMinor: "7"},
|
|
{Certname: "k8s1", Role: "roles::infra::k8s::node",
|
|
Tier1: "infra", Tier2: "k8s", Tier3: "node",
|
|
Country: "au", Region: "syd1", Virtual: "physical",
|
|
OSName: "AlmaLinux", OSMajor: "9", OSMinor: "8"},
|
|
{Certname: "k8s2", Role: "roles::infra::k8s::node",
|
|
Tier1: "infra", Tier2: "k8s", Tier3: "node",
|
|
Country: "au", Region: "drw1", Virtual: "physical",
|
|
OSName: "Debian", OSMajor: "12", OSMinor: "1"},
|
|
{Certname: "prox1", Role: "roles::infra::proxmox::node",
|
|
Tier1: "infra", Tier2: "proxmox", Tier3: "node",
|
|
Country: "nz", Region: "akl1", Virtual: "physical",
|
|
OSName: "AlmaLinux", OSMajor: "8", OSMinor: "10"},
|
|
{Certname: "bare1", Role: "roles::base", Tier1: "base",
|
|
Country: "au", Region: "syd1", Virtual: "lxc",
|
|
OSName: "AlmaLinux", OSMajor: "9", OSMinor: "7"},
|
|
}
|
|
}
|
|
|
|
func TestSelectorSelect(t *testing.T) {
|
|
nodes := fixtureNodes()
|
|
tests := []struct {
|
|
name string
|
|
sel Selector
|
|
want []string
|
|
}{
|
|
{"all", Selector{All: true}, []string{"web1", "k8s1", "k8s2", "prox1", "bare1"}},
|
|
{"certname", Selector{Certname: "k8s2"}, []string{"k8s2"}},
|
|
{"role exact", Selector{RoleExact: "roles::infra::k8s::node"}, []string{"k8s1", "k8s2"}},
|
|
{"tier1 prefix", Selector{RoleTiers: []string{"infra"}}, []string{"k8s1", "k8s2", "prox1"}},
|
|
{"tier2 prefix", Selector{RoleTiers: []string{"infra", "k8s"}}, []string{"k8s1", "k8s2"}},
|
|
{"tier3 exact", Selector{RoleTiers: []string{"apps", "media", "jellyfin"}}, []string{"web1"}},
|
|
{"tier1 only node", Selector{RoleTiers: []string{"base"}}, []string{"bare1"}},
|
|
{"tier prefix longer than node", Selector{RoleTiers: []string{"base", "x"}}, nil},
|
|
{"country", Selector{Country: "au"}, []string{"web1", "k8s1", "k8s2", "bare1"}},
|
|
{"country region", Selector{Country: "au", Region: "syd1"}, []string{"web1", "k8s1", "bare1"}},
|
|
{"country region role", Selector{Country: "au", Region: "syd1", RoleTiers: []string{"infra"}},
|
|
[]string{"k8s1"}},
|
|
{"country role", Selector{Country: "au", RoleTiers: []string{"infra", "k8s"}}, []string{"k8s1", "k8s2"}},
|
|
{"virtual", Selector{Virtual: "physical"}, []string{"k8s1", "k8s2", "prox1"}},
|
|
{"os name", Selector{OSName: "AlmaLinux"}, []string{"web1", "k8s1", "prox1", "bare1"}},
|
|
{"os major", Selector{OSName: "AlmaLinux", OSMajor: "9"}, []string{"web1", "k8s1", "bare1"}},
|
|
{"os major minor", Selector{OSName: "AlmaLinux", OSMajor: "9", OSMinor: "7"},
|
|
[]string{"web1", "bare1"}},
|
|
{"os name case insensitive", Selector{OSName: "almalinux", OSMajor: "8"}, []string{"prox1"}},
|
|
{"os other name", Selector{OSName: "Debian", OSMajor: "12"}, []string{"k8s2"}},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := tc.sel.Select(nodes); !reflect.DeepEqual(got, tc.want) {
|
|
t.Errorf("Select() = %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSelectorString(t *testing.T) {
|
|
if got := (Selector{All: true}).String(); got != "all hosts" {
|
|
t.Errorf("all selector = %q", got)
|
|
}
|
|
got := Selector{Country: "au", Region: "syd1", RoleTiers: []string{"infra", "puppet"}}.String()
|
|
want := "role-prefix=infra::puppet country=au region=syd1"
|
|
if got != want {
|
|
t.Errorf("String() = %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestNodeTiersTruncatesAtGap(t *testing.T) {
|
|
n := Node{Tier1: "base"}
|
|
if got := n.Tiers(); !reflect.DeepEqual(got, []string{"base"}) {
|
|
t.Errorf("Tiers() = %v", got)
|
|
}
|
|
}
|