reduced dashboard update frequency, updated metadata scraping loop to be more HA friendly

pull/99/head
James Batt 4 years ago
parent d667e1f49d
commit 159d0ea95b

@ -142,6 +142,10 @@ func (d *DeviceManager) DeleteDevice(user string, name string) error {
return nil return nil
} }
func (d *DeviceManager) GetByPublicKey(publicKey string) (*storage.Device, error) {
return d.storage.GetByPublicKey(publicKey)
}
var nextIPLock = sync.Mutex{} var nextIPLock = sync.Mutex{}
func (d *DeviceManager) nextClientAddress() (string, error) { func (d *DeviceManager) nextClientAddress() (string, error) {

@ -16,29 +16,28 @@ func metadataLoop(d *DeviceManager) {
func syncMetrics(d *DeviceManager) { func syncMetrics(d *DeviceManager) {
logrus.Debug("metadata sync executing") logrus.Debug("metadata sync executing")
devices, err := d.ListAllDevices()
if err != nil {
logrus.Warn(errors.Wrap(err, "failed to list devices - metrics cannot be recorded"))
return
}
peers, err := d.wg.ListPeers() peers, err := d.wg.ListPeers()
if err != nil { if err != nil {
logrus.Warn(errors.Wrap(err, "failed to list peers - metrics cannot be recorded")) logrus.Warn(errors.Wrap(err, "failed to list peers - metrics cannot be recorded"))
return return
} }
for _, peer := range peers { for _, peer := range peers {
for _, device := range devices { // if the peer is connected we can update their metrics
if peer.PublicKey.String() == device.PublicKey { // importantly, we'll ignore peers that we know about
// but aren't connected at the moment.
// they may actually be connected to another replica.
if peer.Endpoint != nil {
if device, err := d.GetByPublicKey(peer.PublicKey.String()); err == nil {
device.Endpoint = peer.Endpoint.IP.String()
device.ReceiveBytes = peer.ReceiveBytes device.ReceiveBytes = peer.ReceiveBytes
device.TransmitBytes = peer.TransmitBytes device.TransmitBytes = peer.TransmitBytes
if !peer.LastHandshakeTime.IsZero() { if !peer.LastHandshakeTime.IsZero() {
device.LastHandshakeTime = &peer.LastHandshakeTime device.LastHandshakeTime = &peer.LastHandshakeTime
} }
if peer.Endpoint != nil {
device.Endpoint = peer.Endpoint.IP.String()
}
if err := d.SaveDevice(device); err != nil { if err := d.SaveDevice(device); err != nil {
logrus.Debug(errors.Wrap(err, "failed to update device metadata")) logrus.Error(errors.Wrap(err, "failed to save device during metadata sync"))
} }
} }
} }

@ -14,6 +14,7 @@ type Storage interface {
Save(device *Device) error Save(device *Device) error
List(owner string) ([]*Device, error) List(owner string) ([]*Device, error)
Get(owner string, name string) (*Device, error) Get(owner string, name string) (*Device, error)
GetByPublicKey(publicKey string) (*Device, error)
Delete(device *Device) error Delete(device *Device) error
Close() error Close() error
Open() error Open() error
@ -33,7 +34,7 @@ type Device struct {
OwnerEmail string `json:"owner_email"` OwnerEmail string `json:"owner_email"`
OwnerProvider string `json:"owner_provider"` OwnerProvider string `json:"owner_provider"`
Name string `json:"name" gorm:"type:varchar(100);unique_index:key;primary_key"` Name string `json:"name" gorm:"type:varchar(100);unique_index:key;primary_key"`
PublicKey string `json:"public_key"` PublicKey string `json:"public_key" gorm:"unique_index"`
Address string `json:"address"` Address string `json:"address"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`

@ -57,6 +57,19 @@ func (s *InMemoryStorage) Get(owner string, name string) (*Device, error) {
return device, nil return device, nil
} }
func (s *InMemoryStorage) GetByPublicKey(publicKey string) (*Device, error) {
devices, err := s.List("")
if err != nil {
return nil, err
}
for _, device := range devices {
if device.PublicKey == publicKey {
return device, nil
}
}
return nil, errors.New("device doesn't exist")
}
func (s *InMemoryStorage) Delete(device *Device) error { func (s *InMemoryStorage) Delete(device *Device) error {
delete(s.db, key(device)) delete(s.db, key(device))
s.emitDelete(device) s.emitDelete(device)

@ -170,6 +170,14 @@ func (s *SQLStorage) Get(owner string, name string) (*Device, error) {
return device, nil return device, nil
} }
func (s *SQLStorage) GetByPublicKey(publicKey string) (*Device, error) {
device := &Device{}
if err := s.db.Where("public_key = ?", publicKey).First(&device).Error; err != nil {
return nil, errors.Wrapf(err, "failed to read device")
}
return device, nil
}
func (s *SQLStorage) Delete(device *Device) error { func (s *SQLStorage) Delete(device *Device) error {
if err := s.db.Delete(&device).Error; err != nil { if err := s.db.Delete(&device).Error; err != nil {
return errors.Wrap(err, "failed to delete device file") return errors.Wrap(err, "failed to delete device file")

@ -73,16 +73,14 @@ export class DeviceListItem extends React.Component<Props> {
</> </>
)} )}
{AppState.info?.metadataEnabled && !device.connected && ( {AppState.info?.metadataEnabled && !device.connected && (
<> <tr>
<tr> <td>Disconnected</td>
<td>Disconnected</td> </tr>
</tr>
<tr>
<td>Last Seen</td>
<td>{lastSeen(device.lastHandshakeTime)}</td>
</tr>
</>
)} )}
<tr>
<td>Last Seen</td>
<td>{lastSeen(device.lastHandshakeTime)}</td>
</tr>
<tr> <tr>
<td>Public key</td> <td>Public key</td>
<td> <td>

@ -10,7 +10,7 @@ import { AddDevice } from './AddDevice';
@observer @observer
export class Devices extends React.Component { export class Devices extends React.Component {
@observable @observable
devices = autorefresh(5, async () => { devices = autorefresh(30, async () => {
return (await grpc.devices.listDevices({})).items; return (await grpc.devices.listDevices({})).items;
}); });

@ -67,11 +67,11 @@ export class GetConnected extends React.Component<Props> {
<LinuxIcon /> <LinuxIcon />
</Button> </Button>
<Button <Button
onClick={() => this.go('https://download.WireGuard.com/windows-client/WireGuard-amd64-0.1.1.msi')} onClick={() => this.go('https://www.wireguard.com/install/')}
> >
<WindowsIcon /> <WindowsIcon />
</Button> </Button>
<Button onClick={() => this.go('https://itunes.apple.com/us/app/WireGuard/id1451685025?ls=1&mt=12')}> <Button onClick={() => this.go('https://www.wireguard.com/install/#macos-app-store')}>
<MacOSIcon /> <MacOSIcon />
</Button> </Button>
</ButtonGroup> </ButtonGroup>

@ -6,11 +6,13 @@ import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead'; import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow'; import TableRow from '@material-ui/core/TableRow';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { grpc } from '../../Api'; import { grpc } from '../../Api';
import { lastSeen, lazy } from '../../Util'; import { lastSeen, lazy } from '../../Util';
import { Device } from '../../sdk/devices_pb'; import { Device } from '../../sdk/devices_pb';
import { confirm } from '../../components/Present'; import { confirm } from '../../components/Present';
import { AppState } from '../../AppState';
@observer @observer
export class AllDevices extends React.Component { export class AllDevices extends React.Component {
@ -42,38 +44,52 @@ export class AllDevices extends React.Component {
const showProviderCol = rows.length >= 2 && rows.some((r) => r.ownerProvider !== rows[0].ownerProvider); const showProviderCol = rows.length >= 2 && rows.some((r) => r.ownerProvider !== rows[0].ownerProvider);
return ( return (
<TableContainer> <div style={{ display: 'grid', gridGap: 25, gridAutoFlow: 'row'}}>
<Table stickyHeader> <Typography variant="h5" component="h5">
<TableHead> Devices
<TableRow> </Typography>
<TableCell>Owner</TableCell> <TableContainer>
{showProviderCol && <TableCell>Auth Provider</TableCell>} <Table stickyHeader>
<TableCell>Device</TableCell> <TableHead>
<TableCell>Connected</TableCell> <TableRow>
<TableCell>Last Seen</TableCell> <TableCell>Owner</TableCell>
<TableCell>Actions</TableCell> {showProviderCol && <TableCell>Auth Provider</TableCell>}
</TableRow> <TableCell>Device</TableCell>
</TableHead> <TableCell>Connected</TableCell>
<TableBody> <TableCell>Last Seen</TableCell>
{rows.map((row, i) => ( <TableCell>Actions</TableCell>
<TableRow key={i}>
<TableCell component="th" scope="row">
{row.ownerName || row.ownerEmail || row.owner}
</TableCell>
{showProviderCol && <TableCell>{row.ownerProvider}</TableCell>}
<TableCell>{row.name}</TableCell>
<TableCell>{row.connected ? 'yes' : 'no'}</TableCell>
<TableCell>{lastSeen(row.lastHandshakeTime)}</TableCell>
<TableCell>
<Button variant="outlined" color="secondary" onClick={() => this.deleteDevice(row)}>
Delete
</Button>
</TableCell>
</TableRow> </TableRow>
))} </TableHead>
</TableBody> <TableBody>
</Table> {rows.map((row, i) => (
</TableContainer> <TableRow key={i}>
<TableCell component="th" scope="row">
{row.ownerName || row.ownerEmail || row.owner}
</TableCell>
{showProviderCol && <TableCell>{row.ownerProvider}</TableCell>}
<TableCell>{row.name}</TableCell>
<TableCell>{row.connected ? 'yes' : 'no'}</TableCell>
<TableCell>{lastSeen(row.lastHandshakeTime)}</TableCell>
<TableCell>
<Button variant="outlined" color="secondary" onClick={() => this.deleteDevice(row)}>
Delete
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Typography variant="h5" component="h5">
Server Info
</Typography>
<code>
<pre>
{JSON.stringify(AppState.info, null, 2)}
</pre>
</code>
</div>
); );
} }
} }

Loading…
Cancel
Save