package state import ( "context" "fmt" "sync" "google.golang.org/grpc" ipb "code.hackerspace.pl/hscloud/go/proto/infra" confpb "code.hackerspace.pl/hscloud/go/svc/topo/proto/config" "code.hackerspace.pl/hscloud/go/pki" ) type SwitchportState struct { Proto *ipb.SwitchPort } type SwitchState struct { Name string Ports []*SwitchportState Stub ipb.SwitchControlClient } func (s *SwitchState) Fetch(ctx context.Context) error { req := ipb.GetPortsRequest{} res, err := s.Stub.GetPorts(ctx, &req) if err != nil { return fmt.Errorf("GetPorts: %v", err) } s.Ports = make([]*SwitchportState, len(res.Ports)) for i, port := range res.Ports { s.Ports[i] = &SwitchportState{port} } return nil } type StateManager struct { Switches map[string]*SwitchState Conns map[string]*grpc.ClientConn Mu sync.RWMutex } func NewManager() *StateManager { return &StateManager{ Switches: make(map[string]*SwitchState), Conns: make(map[string]*grpc.ClientConn), } } func (s *StateManager) FetchState(ctx context.Context, conf *confpb.Config) error { s.Mu.Lock() defer s.Mu.Unlock() for _, sw := range conf.Switch { conn, ok := s.Conns[sw.ControlAddress] if !ok { var err error conn, err = grpc.Dial(sw.ControlAddress, pki.WithClientHSPKI()) if err != nil { return fmt.Errorf("when connecting to switch %s: %v", sw.Name, err) } s.Conns[sw.ControlAddress] = conn } s.Switches[sw.Name] = &SwitchState{ Name: sw.Name, Stub: ipb.NewSwitchControlClient(conn), } err := s.Switches[sw.Name].Fetch(ctx) if err != nil { return fmt.Errorf("%q.Fetch: %v", sw.Name, err) } } return nil }