blob: 1fdb5ab2170e4fc7f018b07135ec08fb956a4ea5 [file] [log] [blame]
Serge Bazanski28f49072018-10-06 11:31:18 +01001package graph
2
3import (
Serge Bazanski2c6c6d12018-10-06 11:55:04 +01004 "context"
Serge Bazanski28f49072018-10-06 11:31:18 +01005 "fmt"
6
Serge Bazanski2c6c6d12018-10-06 11:55:04 +01007 "github.com/davecgh/go-spew/spew"
8 "github.com/digitalocean/go-netbox/netbox/client"
9 "github.com/digitalocean/go-netbox/netbox/client/dcim"
Serge Bazanski28f49072018-10-06 11:31:18 +010010 "github.com/golang/glog"
Serge Bazanski2c6c6d12018-10-06 11:55:04 +010011
12 confpb "code.hackerspace.pl/q3k/topo/proto/config"
Serge Bazanski28f49072018-10-06 11:31:18 +010013)
14
15type MachinePort struct {
16 OtherEnd *SwitchPort
17 Name string
18}
19
20type SwitchPort struct {
21 OtherEnd *MachinePort
22 Name string
23}
24
25type Machine struct {
26 Name string
27 Complete bool
28
29 Ports map[string]*MachinePort
30}
31
32type Switch struct {
33 Name string
34 Complete bool
35
36 Ports map[string]*SwitchPort
37}
38
39type Graph struct {
40 Switches map[string]*Switch
41 Machines map[string]*Machine
42}
43
44func New() *Graph {
45 return &Graph{
46 Switches: make(map[string]*Switch),
47 Machines: make(map[string]*Machine),
48 }
49}
50
51func (g *Graph) RemoveMachine(name string) {
52 glog.Infof("Removed machine %q", name)
53}
54
55func (g *Graph) RemoveSwitch(name string) {
56 glog.Infof("Removed switch %q", name)
57}
58
59func (g *Graph) LoadConfig(conf *confpb.Config) error {
60 loadedMachines := make(map[string]bool)
61 loadedSwitches := make(map[string]bool)
62
63 // Add new machines and switches.
64 for _, machinepb := range conf.Machine {
65 if machinepb.Name == "" {
66 return fmt.Errorf("empty machine name")
67 }
Serge Bazanski2c6c6d12018-10-06 11:55:04 +010068 if loadedMachines[machinepb.Name] {
69 return fmt.Errorf("duplicate machine name: %v", machinepb.Name)
70 }
Serge Bazanski28f49072018-10-06 11:31:18 +010071 machine, ok := g.Machines[machinepb.Name]
72 if !ok {
73 machine = &Machine{
74 Name: machinepb.Name,
75 Ports: make(map[string]*MachinePort),
76 }
77 for _, portpb := range machinepb.ManagedPort {
78 machine.Ports[portpb.Name] = &MachinePort{
79 Name: portpb.Name,
80 }
81 }
82 g.Machines[machinepb.Name] = machine
83 glog.Infof("Added machine %q with %d managed ports", machine.Name, len(machine.Ports))
84 }
85 machine.Complete = false
86 loadedMachines[machinepb.Name] = true
87 }
88 for _, switchpb := range conf.Switch {
89 if switchpb.Name == "" {
90 return fmt.Errorf("empty switch name")
91 }
Serge Bazanski2c6c6d12018-10-06 11:55:04 +010092 if loadedSwitches[switchpb.Name] {
93 return fmt.Errorf("duplicate switch name: %v", switchpb.Name)
94 }
95 if loadedMachines[switchpb.Name] {
96 return fmt.Errorf("switch name collides with machine name: %v", switchpb.Name)
97 }
Serge Bazanski28f49072018-10-06 11:31:18 +010098 sw, ok := g.Switches[switchpb.Name]
99 if !ok {
100 sw = &Switch{
101 Name: switchpb.Name,
102 Ports: make(map[string]*SwitchPort),
103 }
104 for _, portpb := range switchpb.ManagedPort {
105 sw.Ports[portpb.Name] = &SwitchPort{
106 Name: portpb.Name,
107 }
108 }
109 g.Switches[switchpb.Name] = sw
110 glog.Infof("Added switch %q with %d managed ports", sw.Name, len(sw.Ports))
111 }
112 sw.Complete = false
113 loadedSwitches[switchpb.Name] = true
114 }
115
116 // Remove old machines and switches.
117 removeMachines := make(map[string]bool)
118 removeSwitches := make(map[string]bool)
119 for name, _ := range g.Switches {
120 if !loadedSwitches[name] {
121 removeSwitches[name] = true
122 }
123 }
124 for name, _ := range g.Machines {
125 if !loadedMachines[name] {
126 removeMachines[name] = true
127 }
128 }
129 for name, _ := range removeMachines {
130 g.RemoveMachine(name)
131 }
132 for name, _ := range removeSwitches {
133 g.RemoveSwitch(name)
134 }
135 return nil
136
137}
Serge Bazanski2c6c6d12018-10-06 11:55:04 +0100138
139func (g *Graph) FeedFromNetbox(ctx context.Context, nb *client.NetBox) error {
140 for _, machine := range g.Machines {
141 req := &dcim.DcimInterfaceConnectionsListParams{
142 Device: &machine.Name,
143 Context: ctx,
144 }
145 res, err := nb.Dcim.DcimInterfaceConnectionsList(req, nil)
146 if err != nil {
147 return fmt.Errorf("while querying information about %q: %v", machine.Name, err)
148 }
149 for _, connection := range res.Payload.Results {
150 glog.Info(spew.Sdump(connection))
151 }
152 }
153 return nil
154}