f-50: lab: topologie et calcul du plan #50

Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
GnomeZworc 2026-10-04 00:49:21 +02:00
commit 4d0fc7e18d
Signed by: nicolas.boufideline
GPG key ID: 4406BBBF8845D632
11 changed files with 1310 additions and 4 deletions

View file

@ -0,0 +1,151 @@
package topology
import (
"bytes"
"errors"
"fmt"
"os"
"go.yaml.in/yaml/v3"
)
const (
RoleSwitch = "switch"
RoleRR = "rr"
RoleHypervisor = "hypervisor"
DefaultMTU = 9000
)
type Topology struct {
Name string
Images []Image
Segments []Segment
Nodes []Node
}
type Image struct {
Name string
URL string
Sums string
}
type Segment struct {
Name string
Switch string
CIDR string
MTU int
}
type Node struct {
Name string
Role string
Image string
CPUs int
Memory int
Segments []string
Addresses map[string]string
}
type fileImage struct {
URL string `yaml:"url"`
Sums string `yaml:"sums"`
}
type fileSegment struct {
Switch string `yaml:"switch"`
CIDR string `yaml:"cidr"`
MTU int `yaml:"mtu"`
}
type fileNode struct {
Role string `yaml:"role"`
Image string `yaml:"image"`
CPUs int `yaml:"cpus"`
Memory int `yaml:"memory"`
Segments []string `yaml:"segments"`
Addresses map[string]string `yaml:"addresses"`
}
type file struct {
Name string `yaml:"name"`
Images map[string]fileImage `yaml:"images"`
Segments map[string]fileSegment `yaml:"segments"`
Nodes map[string]fileNode `yaml:"nodes"`
}
func Load(path string) (*Topology, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
t, err := Parse(data)
if err != nil {
return nil, fmt.Errorf("%s: %w", path, err)
}
return t, nil
}
func Parse(data []byte) (*Topology, error) {
var f file
dec := yaml.NewDecoder(bytes.NewReader(data))
dec.KnownFields(true)
if err := dec.Decode(&f); err != nil {
return nil, fmt.Errorf("yaml: %w", err)
}
var root yaml.Node
if err := yaml.Unmarshal(data, &root); err != nil {
return nil, fmt.Errorf("yaml: %w", err)
}
order, err := keyOrder(&root)
if err != nil {
return nil, err
}
t := &Topology{Name: f.Name}
for _, name := range order["images"] {
i := f.Images[name]
t.Images = append(t.Images, Image{Name: name, URL: i.URL, Sums: i.Sums})
}
for _, name := range order["segments"] {
s := f.Segments[name]
mtu := s.MTU
if mtu == 0 {
mtu = DefaultMTU
}
t.Segments = append(t.Segments, Segment{Name: name, Switch: s.Switch, CIDR: s.CIDR, MTU: mtu})
}
for _, name := range order["nodes"] {
n := f.Nodes[name]
t.Nodes = append(t.Nodes, Node{
Name: name,
Role: n.Role,
Image: n.Image,
CPUs: n.CPUs,
Memory: n.Memory,
Segments: n.Segments,
Addresses: n.Addresses,
})
}
return t, nil
}
func keyOrder(root *yaml.Node) (map[string][]string, error) {
order := map[string][]string{}
if root.Kind != yaml.DocumentNode || len(root.Content) != 1 || root.Content[0].Kind != yaml.MappingNode {
return nil, errors.New("yaml: the document must be a mapping")
}
top := root.Content[0]
for i := 0; i+1 < len(top.Content); i += 2 {
section := top.Content[i].Value
value := top.Content[i+1]
if value.Kind != yaml.MappingNode {
continue
}
for j := 0; j+1 < len(value.Content); j += 2 {
order[section] = append(order[section], value.Content[j].Value)
}
}
return order, nil
}