// Package demo starts fake PVE clusters (pvetest) and fills a database with // them, to try the web UI without a Proxmox cluster: a reference, two clients // with differences (missing objects, different fields, a missing mapping) and // a PVE 8 cluster that is refused. package demo import ( "context" "crypto/sha256" "encoding/hex" "pve-confsync/internal/adapter" "pve-confsync/internal/model" "pve-confsync/internal/pve/pvetest" "pve-confsync/internal/store" ) // Password of the demo accounts admin, operateur and lecteur. const Password = "confsync-demo" // Clusters are the fake clusters; Close stops them. type Clusters struct{ servers []*pvetest.Server } // Close stops the fake clusters. func (c *Clusters) Close() { for _, s := range c.servers { s.Close() } } // Start starts the fake clusters and records them (and the demo accounts) in st. func Start(ctx context.Context, st *store.Store) (*Clusters, error) { ref := pvetest.New("9.1.4") ref.Options = map[string]string{ "registered-tags": "backup;dev;prod", "tag-style": "color-map=prod:c0392b:ffffff;dev:2980b9:ffffff,ordering=config,shape=full", "next-id": "lower=100,upper=999999", "user-tag-access": "user-allow=list,user-allow-list=team-a;team-b", "keyboard": "fr", } ref.Pending.Zones["vlanz"] = map[string]any{"type": "vlan", "bridge": "vmbr0", "mtu": 1500, "ipam": "pve"} ref.Pending.Zones["stor"] = map[string]any{"type": "vlan", "bridge": "vmbr2", "mtu": 9000, "ipam": "pve"} ref.Pending.Zones["vxz"] = map[string]any{"type": "vxlan", "peers": "10.0.0.1,10.0.0.2", "mtu": 1450, "ipam": "pve"} ref.Pending.Zones["evpnz"] = map[string]any{"type": "evpn", "controller": "evpnctl", "vrf-vxlan": 4000} ref.Pending.VNets["v100"] = map[string]any{"zone": "vlanz", "tag": 100, "alias": "prod"} ref.Pending.VNets["v200"] = map[string]any{"zone": "vlanz", "tag": 200, "alias": "dev"} ref.Pending.VNets["ceph"] = map[string]any{"zone": "stor", "tag": 50, "alias": "ceph public"} ref.Pending.VNets["vx1"] = map[string]any{"zone": "vxz", "tag": 10001, "alias": "overlay"} ref.Pending.Subnets["vlanz-10.1.0.0-24"] = map[string]any{"vnet": "v100", "gateway": "10.1.0.1", "dhcp-range": []any{"start-address=10.1.0.100,end-address=10.1.0.200"}} ref.Pending.Subnets["vlanz-10.2.0.0-24"] = map[string]any{"vnet": "v200", "gateway": "10.2.0.1"} ref.Commit() // site-a: tags and an MTU behind, the VXLAN zone and the dev network missing a := pvetest.New("9.0.10") a.Options = map[string]string{ "registered-tags": "dev;prod", "tag-style": "color-map=prod:c0392b:ffffff;dev:2980b9:ffffff,ordering=config,shape=full", "next-id": "lower=2000,upper=2999", "keyboard": "en-us", } a.Pending.Zones["vlanz"] = map[string]any{"type": "vlan", "bridge": "vmbr1", "mtu": 9000, "ipam": "pve"} a.Pending.Zones["stor"] = map[string]any{"type": "vlan", "bridge": "vmbr2", "mtu": 9000, "ipam": "pve", "nodes": "pve-a1,pve-a2"} a.Pending.VNets["v100"] = map[string]any{"zone": "vlanz", "tag": 100, "alias": "production"} a.Pending.VNets["ceph"] = map[string]any{"zone": "stor", "tag": 50, "alias": "ceph public"} a.Pending.Subnets["vlanz-10.1.0.0-24"] = map[string]any{"vnet": "v100", "gateway": "10.1.0.254"} a.Commit() // site-b: nearly in line, but no mapping for the bridge of the "stor" zone // (blocking error) and a local zone absent from the reference (kept, no prune) b := pvetest.New("9.1.2") b.Options = map[string]string{ "registered-tags": "backup;dev;prod", "tag-style": "color-map=prod:c0392b:ffffff;dev:2980b9:ffffff,ordering=config,shape=full", "next-id": "lower=100,upper=999999", "user-tag-access": "user-allow=list,user-allow-list=team-a;team-b", } b.Pending.Zones["vlanz"] = map[string]any{"type": "vlan", "bridge": "vmbr0", "mtu": 1500, "ipam": "pve"} b.Pending.Zones["vxz"] = map[string]any{"type": "vxlan", "peers": "172.16.0.1,172.16.0.2", "mtu": 1450, "ipam": "pve"} b.Pending.Zones["labz"] = map[string]any{"type": "vlan", "bridge": "vmbr9", "ipam": "pve"} b.Pending.VNets["v100"] = map[string]any{"zone": "vlanz", "tag": 100, "alias": "prod"} b.Pending.VNets["v200"] = map[string]any{"zone": "vlanz", "tag": 200, "alias": "dev"} b.Pending.Subnets["vlanz-10.1.0.0-24"] = map[string]any{"vnet": "v100", "gateway": "10.1.0.1", "dhcp-range": []any{"start-address=10.1.0.100,end-address=10.1.0.200"}} b.Pending.Subnets["vlanz-10.2.0.0-24"] = map[string]any{"vnet": "v200", "gateway": "10.2.0.1"} b.Commit() // legacy: PVE 8, refused by the version check old := pvetest.New("8.4.1") c := &Clusters{servers: []*pvetest.Server{ref, a, b, old}} save := func(s *pvetest.Server, name, token string, refer bool, pos int, mapping map[model.Kind]map[string]map[string]any, pol map[model.Kind]map[string]adapter.Policy) error { sum := sha256.Sum256(s.Certificate().Raw) return st.SaveCluster(ctx, "", store.Cluster{Name: name, Reference: refer, Position: pos, URL: s.URL, TokenID: token, Secret: "demo-" + name, Fingerprint: hex.EncodeToString(sum[:]), Mapping: mapping, Policies: pol}) } steps := []error{ save(ref, "ref-rennes", "confsync@pve!ro", true, 0, nil, nil), save(a, "site-a", "confsync@pve!rw", false, 1, map[model.Kind]map[string]map[string]any{ model.KindDatacenter: {"datacenter": {"next-id": "lower=2000,upper=2999"}}, model.KindZone: { "vlanz": {"bridge": "vmbr1"}, "stor": {"bridge": "vmbr2", "nodes": "pve-a1,pve-a2"}, "vxz": {"peers": "192.168.10.1,192.168.10.2"}, }, }, nil), save(b, "site-b", "confsync@pve!rw", false, 2, map[model.Kind]map[string]map[string]any{ model.KindZone: { "vlanz": {"bridge": "vmbr0"}, "vxz": {"peers": "172.16.0.1,172.16.0.2"}, }, }, map[model.Kind]map[string]adapter.Policy{model.KindZone: {"mtu": adapter.Ignore}}), save(old, "legacy-pve8", "confsync@pve!rw", false, 3, nil, nil), st.SaveSettings(ctx, store.Settings{Kinds: model.Kinds, Policies: map[model.Kind]map[string]adapter.Policy{model.KindDatacenter: {"keyboard": adapter.Sync}}}), } for _, u := range []struct{ name, role string }{{"admin", store.RoleAdmin}, {"operateur", store.RoleOperator}, {"lecteur", store.RoleViewer}} { steps = append(steps, st.SaveUser(ctx, u.name, u.role, Password)) } for _, err := range steps { if err != nil { c.Close() return nil, err } } return c, nil }