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

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

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

@ -16,29 +16,28 @@ func metadataLoop(d *DeviceManager) {
func syncMetrics(d *DeviceManager) {
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()
if err != nil {
logrus.Warn(errors.Wrap(err, "failed to list peers - metrics cannot be recorded"))
return
}
for _, peer := range peers {
for _, device := range devices {
if peer.PublicKey.String() == device.PublicKey {
// if the peer is connected we can update their metrics
// 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.TransmitBytes = peer.TransmitBytes
if !peer.LastHandshakeTime.IsZero() {
device.LastHandshakeTime = &peer.LastHandshakeTime
}
if peer.Endpoint != nil {
device.Endpoint = peer.Endpoint.IP.String()
}
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
List(owner string) ([]*Device, error)
Get(owner string, name string) (*Device, error)
GetByPublicKey(publicKey string) (*Device, error)
Delete(device *Device) error
Close() error
Open() error
@ -33,7 +34,7 @@ type Device struct {
OwnerEmail string `json:"owner_email"`
OwnerProvider string `json:"owner_provider"`
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"`
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
}
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 {
delete(s.db, key(device))
s.emitDelete(device)

@ -170,6 +170,14 @@ func (s *SQLStorage) Get(owner string, name string) (*Device, error) {
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 {
if err := s.db.Delete(&device).Error; err != nil {
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 && (
<>
<tr>
<td>Disconnected</td>
</tr>
<tr>
<td>Last Seen</td>
<td>{lastSeen(device.lastHandshakeTime)}</td>
</tr>
</>
<tr>
<td>Disconnected</td>
</tr>
)}
<tr>
<td>Last Seen</td>
<td>{lastSeen(device.lastHandshakeTime)}</td>
</tr>
<tr>
<td>Public key</td>
<td>

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

@ -67,11 +67,11 @@ export class GetConnected extends React.Component<Props> {
<LinuxIcon />
</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 />
</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 />
</Button>
</ButtonGroup>

@ -6,11 +6,13 @@ import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import { observer } from 'mobx-react';
import { grpc } from '../../Api';
import { lastSeen, lazy } from '../../Util';
import { Device } from '../../sdk/devices_pb';
import { confirm } from '../../components/Present';
import { AppState } from '../../AppState';
@observer
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);
return (
<TableContainer>
<Table stickyHeader>
<TableHead>
<TableRow>
<TableCell>Owner</TableCell>
{showProviderCol && <TableCell>Auth Provider</TableCell>}
<TableCell>Device</TableCell>
<TableCell>Connected</TableCell>
<TableCell>Last Seen</TableCell>
<TableCell>Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, i) => (
<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>
<div style={{ display: 'grid', gridGap: 25, gridAutoFlow: 'row'}}>
<Typography variant="h5" component="h5">
Devices
</Typography>
<TableContainer>
<Table stickyHeader>
<TableHead>
<TableRow>
<TableCell>Owner</TableCell>
{showProviderCol && <TableCell>Auth Provider</TableCell>}
<TableCell>Device</TableCell>
<TableCell>Connected</TableCell>
<TableCell>Last Seen</TableCell>
<TableCell>Actions</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</TableHead>
<TableBody>
{rows.map((row, i) => (
<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