Add peer meta data (#95)

* feature: add peer GET and DELETE API methods

* refactor: extract peer business logic to a separate file

* refactor: extract peer business logic to a separate file

* feature: add peer update HTTP endpoint

* chore: fill peer new fields

* merge with main

* refactor: HTTP methods according to standards

* feature: add peer system metadata

* feature: add peer status

* test: fix removal
This commit is contained in:
Mikhail Bragin
2021-08-24 11:50:19 +02:00
committed by GitHub
parent 95845c88fe
commit 0fa15e6920
10 changed files with 416 additions and 174 deletions

View File

@ -177,7 +177,11 @@ func TestAccountManager_AddPeer(t *testing.T) {
expectedPeerKey := key.PublicKey().String()
expectedPeerIP := "100.64.0.1"
peer, err := manager.AddPeer(setupKey.Key, expectedPeerKey)
peer, err := manager.AddPeer(setupKey.Key, Peer{
Key: expectedPeerKey,
Meta: PeerSystemMeta{},
Name: expectedPeerKey,
})
if err != nil {
t.Errorf("expecting peer to be added, got failure %v", err)
return

View File

@ -125,11 +125,27 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S
}
}
func (s *Server) registerPeer(peerKey wgtypes.Key, setupKey string) (*Peer, error) {
func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Peer, error) {
s.channelsMux.Lock()
defer s.channelsMux.Unlock()
peer, err := s.accountManager.AddPeer(setupKey, peerKey.String())
meta := req.GetMeta()
if meta == nil {
return nil, status.Errorf(codes.InvalidArgument, "peer meta data was not provided")
}
peer, err := s.accountManager.AddPeer(req.GetSetupKey(), Peer{
Key: peerKey.String(),
Name: meta.GetHostname(),
Meta: PeerSystemMeta{
Hostname: meta.GetHostname(),
GoOS: meta.GetGoOS(),
Kernel: meta.GetKernel(),
Core: meta.GetCore(),
Platform: meta.GetPlatform(),
OS: meta.GetOS(),
WtVersion: meta.GetWiretrusteeVersion(),
},
})
if err != nil {
return nil, status.Errorf(codes.NotFound, "provided setup key doesn't exists")
}
@ -187,7 +203,7 @@ func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto
}
//setup key is present -> try normal registration flow
peer, err = s.registerPeer(peerKey, loginReq.GetSetupKey())
peer, err = s.registerPeer(peerKey, loginReq)
if err != nil {
return nil, err
}
@ -306,6 +322,11 @@ func (s *Server) openUpdatesChannel(peerKey string) chan *UpdateChannelMessage {
channel := make(chan *UpdateChannelMessage, 100)
s.peerChannels[peerKey] = channel
err := s.accountManager.MarkPeerConnected(peerKey, true)
if err != nil {
log.Warnf("failed marking peer as connected %s %v", peerKey, err)
}
log.Debugf("opened updates channel for a peer %s", peerKey)
return channel
}
@ -319,6 +340,11 @@ func (s *Server) closeUpdatesChannel(peerKey string) {
close(channel)
}
err := s.accountManager.MarkPeerConnected(peerKey, false)
if err != nil {
log.Warnf("failed marking peer as disconnected %s %v", peerKey, err)
}
log.Debugf("closed updates channel of a peer %s", peerKey)
}

View File

@ -2,6 +2,7 @@ package handler
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
"github.com/wiretrustee/wiretrustee/management/server"
@ -118,8 +119,8 @@ func toPeerResponse(peer *server.Peer) *PeerResponse {
return &PeerResponse{
Name: peer.Name,
IP: peer.IP.String(),
Connected: peer.Connected,
LastSeen: peer.LastSeen,
OS: peer.OS,
Connected: peer.Status.Connected,
LastSeen: peer.Status.LastSeen,
OS: fmt.Sprintf("%s %s", peer.Meta.GoOS, peer.Meta.Core),
}
}

View File

@ -8,6 +8,7 @@ import (
"net"
"os"
"path/filepath"
"runtime"
sync2 "sync"
"time"
@ -71,8 +72,7 @@ var _ = Describe("Management service", func() {
s.Stop()
err := conn.Close()
Expect(err).NotTo(HaveOccurred())
err = os.RemoveAll(dataDir)
Expect(err).NotTo(HaveOccurred())
os.RemoveAll(dataDir)
})
Context("when calling IsHealthy endpoint", func() {
@ -442,7 +442,16 @@ var _ = Describe("Management service", func() {
func loginPeerWithValidSetupKey(serverPubKey wgtypes.Key, key wgtypes.Key, client mgmtProto.ManagementServiceClient) *mgmtProto.LoginResponse {
message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{SetupKey: ValidSetupKey})
meta := &mgmtProto.PeerSystemMeta{
Hostname: key.PublicKey().String(),
GoOS: runtime.GOOS,
OS: runtime.GOOS,
Core: "core",
Platform: "platform",
Kernel: "kernel",
WiretrusteeVersion: "",
}
message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{SetupKey: ValidSetupKey, Meta: meta})
Expect(err).NotTo(HaveOccurred())
resp, err := client.Login(context.TODO(), &mgmtProto.EncryptedMessage{

View File

@ -8,6 +8,24 @@ import (
"time"
)
// PeerSystemMeta is a metadata of a Peer machine system
type PeerSystemMeta struct {
Hostname string
GoOS string
Kernel string
Core string
Platform string
OS string
WtVersion string
}
type PeerStatus struct {
//LastSeen is the last time peer was connected to the management service
LastSeen time.Time
//Connected indicates whether peer is connected to the management service or not
Connected bool
}
//Peer represents a machine connected to the network.
//The Peer is a Wireguard peer identified by a public key
type Peer struct {
@ -17,26 +35,22 @@ type Peer struct {
SetupKey string
//IP address of the Peer
IP net.IP
//OS is peer's operating system
OS string
//Meta is a Peer system meta data
Meta PeerSystemMeta
//Name is peer's name (machine name)
Name string
//LastSeen is the last time peer was connected to the management service
LastSeen time.Time
//Connected indicates whether peer is connected to the management service or not
Connected bool
Name string
Status *PeerStatus
}
//Copy copies Peer object
func (p *Peer) Copy() *Peer {
return &Peer{
Key: p.Key,
SetupKey: p.SetupKey,
IP: p.IP,
OS: p.OS,
Name: p.Name,
LastSeen: p.LastSeen,
Connected: p.Connected,
Key: p.Key,
SetupKey: p.SetupKey,
IP: p.IP,
Meta: p.Meta,
Name: p.Name,
Status: p.Status,
}
}
@ -53,6 +67,31 @@ func (manager *AccountManager) GetPeer(peerKey string) (*Peer, error) {
return peer, nil
}
//MarkPeerConnected marks peer as connected (true) or disconnected (false)
func (manager *AccountManager) MarkPeerConnected(peerKey string, connected bool) error {
manager.mux.Lock()
defer manager.mux.Unlock()
peer, err := manager.Store.GetPeer(peerKey)
if err != nil {
return err
}
account, err := manager.Store.GetPeerAccount(peerKey)
if err != nil {
return err
}
peerCopy := peer.Copy()
peerCopy.Status.LastSeen = time.Now()
peerCopy.Status.Connected = connected
err = manager.Store.SavePeer(account.Id, peerCopy)
if err != nil {
return err
}
return nil
}
//RenamePeer changes peer's name
func (manager *AccountManager) RenamePeer(accountId string, peerKey string, newName string) (*Peer, error) {
manager.mux.Lock()
@ -125,7 +164,8 @@ func (manager *AccountManager) GetPeersForAPeer(peerKey string) ([]*Peer, error)
// will be returned, meaning the key is invalid
// Each new Peer will be assigned a new next net.IP from the Account.Network and Account.Network.LastIP will be updated (IP's are not reused).
// If the specified setupKey is empty then a new Account will be created //todo remove this part
func (manager *AccountManager) AddPeer(setupKey string, peerKey string) (*Peer, error) {
// The peer property is just a placeholder for the Peer properties to pass further
func (manager *AccountManager) AddPeer(setupKey string, peer Peer) (*Peer, error) {
manager.mux.Lock()
defer manager.mux.Unlock()
@ -163,13 +203,12 @@ func (manager *AccountManager) AddPeer(setupKey string, peerKey string) (*Peer,
nextIp, _ := AllocatePeerIP(network.Net, takenIps)
newPeer := &Peer{
Key: peerKey,
SetupKey: sk.Key,
IP: nextIp,
OS: "todo",
Name: "todo",
LastSeen: time.Now(),
Connected: true,
Key: peer.Key,
SetupKey: sk.Key,
IP: nextIp,
Meta: peer.Meta,
Name: peer.Name,
Status: &PeerStatus{Connected: false, LastSeen: time.Now()},
}
account.Peers[newPeer.Key] = newPeer