build graph from config
diff --git a/graph/.graph.go.swp b/graph/.graph.go.swp
new file mode 100644
index 0000000..14109d8
--- /dev/null
+++ b/graph/.graph.go.swp
Binary files differ
diff --git a/graph/graph.go b/graph/graph.go
new file mode 100644
index 0000000..35b1f23
--- /dev/null
+++ b/graph/graph.go
@@ -0,0 +1,123 @@
+package graph
+
+import (
+	"fmt"
+
+	confpb "code.hackerspace.pl/q3k/topo/proto/config"
+	"github.com/golang/glog"
+)
+
+type MachinePort struct {
+	OtherEnd *SwitchPort
+	Name     string
+}
+
+type SwitchPort struct {
+	OtherEnd *MachinePort
+	Name     string
+}
+
+type Machine struct {
+	Name     string
+	Complete bool
+
+	Ports map[string]*MachinePort
+}
+
+type Switch struct {
+	Name     string
+	Complete bool
+
+	Ports map[string]*SwitchPort
+}
+
+type Graph struct {
+	Switches map[string]*Switch
+	Machines map[string]*Machine
+}
+
+func New() *Graph {
+	return &Graph{
+		Switches: make(map[string]*Switch),
+		Machines: make(map[string]*Machine),
+	}
+}
+
+func (g *Graph) RemoveMachine(name string) {
+	glog.Infof("Removed machine %q", name)
+}
+
+func (g *Graph) RemoveSwitch(name string) {
+	glog.Infof("Removed switch %q", name)
+}
+
+func (g *Graph) LoadConfig(conf *confpb.Config) error {
+	loadedMachines := make(map[string]bool)
+	loadedSwitches := make(map[string]bool)
+
+	// Add new machines and switches.
+	for _, machinepb := range conf.Machine {
+		if machinepb.Name == "" {
+			return fmt.Errorf("empty machine name")
+		}
+		machine, ok := g.Machines[machinepb.Name]
+		if !ok {
+			machine = &Machine{
+				Name:  machinepb.Name,
+				Ports: make(map[string]*MachinePort),
+			}
+			for _, portpb := range machinepb.ManagedPort {
+				machine.Ports[portpb.Name] = &MachinePort{
+					Name: portpb.Name,
+				}
+			}
+			g.Machines[machinepb.Name] = machine
+			glog.Infof("Added machine %q with %d managed ports", machine.Name, len(machine.Ports))
+		}
+		machine.Complete = false
+		loadedMachines[machinepb.Name] = true
+	}
+	for _, switchpb := range conf.Switch {
+		if switchpb.Name == "" {
+			return fmt.Errorf("empty switch name")
+		}
+		sw, ok := g.Switches[switchpb.Name]
+		if !ok {
+			sw = &Switch{
+				Name:  switchpb.Name,
+				Ports: make(map[string]*SwitchPort),
+			}
+			for _, portpb := range switchpb.ManagedPort {
+				sw.Ports[portpb.Name] = &SwitchPort{
+					Name: portpb.Name,
+				}
+			}
+			g.Switches[switchpb.Name] = sw
+			glog.Infof("Added switch %q with %d managed ports", sw.Name, len(sw.Ports))
+		}
+		sw.Complete = false
+		loadedSwitches[switchpb.Name] = true
+	}
+
+	// Remove old machines and switches.
+	removeMachines := make(map[string]bool)
+	removeSwitches := make(map[string]bool)
+	for name, _ := range g.Switches {
+		if !loadedSwitches[name] {
+			removeSwitches[name] = true
+		}
+	}
+	for name, _ := range g.Machines {
+		if !loadedMachines[name] {
+			removeMachines[name] = true
+		}
+	}
+	for name, _ := range removeMachines {
+		g.RemoveMachine(name)
+	}
+	for name, _ := range removeSwitches {
+		g.RemoveSwitch(name)
+	}
+	return nil
+
+}
diff --git a/main.go b/main.go
index 7d213f3..ce79ca7 100644
--- a/main.go
+++ b/main.go
@@ -1,17 +1,17 @@
 package main
 
 import (
-	"context"
 	"flag"
 	"io/ioutil"
 
-	"github.com/digitalocean/go-netbox/netbox"
-	"github.com/digitalocean/go-netbox/netbox/client"
-	"github.com/digitalocean/go-netbox/netbox/client/dcim"
-	"github.com/go-openapi/swag"
+	//"github.com/digitalocean/go-netbox/netbox"
+	//"github.com/digitalocean/go-netbox/netbox/client"
+	//"github.com/digitalocean/go-netbox/netbox/client/dcim"
+
 	"github.com/golang/glog"
 	"github.com/golang/protobuf/proto"
 
+	"code.hackerspace.pl/q3k/topo/graph"
 	confpb "code.hackerspace.pl/q3k/topo/proto/config"
 )
 
@@ -38,14 +38,19 @@
 
 	config := confpb.Config{}
 	proto.UnmarshalText(string(data), &config)
-	glog.Infof("%+v", config)
 
-	client.DefaultSchemes = []string{"https"}
-	nb := netbox.NewNetboxWithAPIKey(flagNetboxHost, flagNetboxAPIKey)
-	req := &dcim.DcimInterfaceConnectionsListParams{
-		Device:  swag.String("bc01n01"),
-		Context: context.Background(),
+	gr := graph.New()
+	err = gr.LoadConfig(&config)
+	if err != nil {
+		glog.Exitf("Initial config load failed: %v", err)
 	}
-	res, err := nb.Dcim.DcimInterfaceConnectionsList(req, nil)
-	glog.Infof("%+v, %v", res, err)
+
+	//client.DefaultSchemes = []string{"https"}
+	//nb := netbox.NewNetboxWithAPIKey(flagNetboxHost, flagNetboxAPIKey)
+	//req := &dcim.DcimInterfaceConnectionsListParams{
+	//	Device:  swag.String("bc01n01"),
+	//	Context: context.Background(),
+	//}
+	//res, err := nb.Dcim.DcimInterfaceConnectionsList(req, nil)
+	//glog.Infof("%+v, %v", res, err)
 }