Skip to content

Commit

Permalink
append issue if device not seen recently
Browse files Browse the repository at this point in the history
  • Loading branch information
sechmann committed Jun 26, 2024
1 parent 703f46c commit 92d6de9
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 7 deletions.
5 changes: 5 additions & 0 deletions cmd/apiserver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,11 @@ func run(log *logrus.Entry, cfg config.Config) error {
if err != nil {
return err
}

if issue := device.MaybeLstSeenIssue(); issue != nil {
device.Issues = append(device.GetIssues(), issue)
}

grpcHandler.SendDeviceConfiguration(device)
grpcHandler.SendAllGatewayConfigurations()
return nil
Expand Down
4 changes: 4 additions & 0 deletions internal/apiserver/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,10 @@ func sqlcDeviceToPbDevice(sqlcDevice sqlc.Device) (*pb.Device, error) {
pbDevice.LastSeen = timestamppb.New(stringToTime(sqlcDevice.LastSeen.String))
}

if issue := pbDevice.MaybeLstSeenIssue(); issue != nil {
pbDevice.Issues = append(pbDevice.Issues, issue)
}

return pbDevice, nil
}

Expand Down
5 changes: 3 additions & 2 deletions internal/apiserver/database/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/nais/device/internal/apiserver/testdatabase"
"github.com/nais/device/internal/pb"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/timestamppb"
)

const timeout = time.Second * 5
Expand Down Expand Up @@ -101,7 +102,7 @@ func TestAddDevice(t *testing.T) {
Title: "integration test issue",
},
}
d := &pb.Device{Username: "username", PublicKey: "publickey", Serial: serial, Platform: "darwin"}
d := &pb.Device{Username: "username", PublicKey: "publickey", Serial: serial, Platform: "darwin", LastSeen: timestamppb.Now()}
err := db.AddDevice(ctx, d)
assert.NoError(t, err)

Expand All @@ -121,7 +122,7 @@ func TestAddDevice(t *testing.T) {
assert.NoError(t, err)

newUsername, newPublicKey := "newUsername", "newPublicKey"
dUpdated := &pb.Device{Username: newUsername, PublicKey: newPublicKey, Serial: serial, Platform: "darwin"}
dUpdated := &pb.Device{Username: newUsername, PublicKey: newPublicKey, Serial: serial, Platform: "darwin", LastSeen: timestamppb.Now()}
err = db.AddDevice(ctx, dUpdated)
assert.NoError(t, err)

Expand Down
2 changes: 0 additions & 2 deletions internal/apiserver/kolide/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ func (failure *DeviceFailure) Relevant() bool {
return failure.Check.Severity() != pb.Severity_Info
}

const MaxTimeSinceKolideLastSeen = 25 * time.Hour

func (f DeviceFailure) AsDeviceIssue() *pb.DeviceIssue {
graceTime := GraceTime(f.Check.Severity())
if graceTime == DurationUnknown {
Expand Down
15 changes: 12 additions & 3 deletions internal/integration_test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestIntegration(t *testing.T) {
Serial: "test-serial",
PublicKey: "publicKey",
Username: "tester",
LastSeen: timestamppb.Now(),
Platform: "linux",
Issues: []*pb.DeviceIssue{
{
Expand All @@ -62,6 +63,7 @@ func TestIntegration(t *testing.T) {
PublicKey: "publicKey",
Username: "tester",
Platform: "linux",
LastSeen: timestamppb.Now(),
},
endState: pb.AgentState_Connected,
expectedGateways: map[string]*pb.Gateway{
Expand Down Expand Up @@ -371,12 +373,19 @@ func tableTest(t *testing.T, log *logrus.Entry, testDevice *pb.Device, endState
func assertEqualIssueLists(t *testing.T, expected, actual []*pb.DeviceIssue) {
t.Helper()
equalIssues := func(a, b *pb.DeviceIssue) bool {
t.Logf("comparing issues (%v,%v,%v,%v,%v)", a.Title == b.Title, a.Message == b.Message, a.Severity == b.Severity, a.DetectedAt.AsTime().Equal(b.DetectedAt.AsTime()), a.LastUpdated.AsTime().Equal(b.LastUpdated.AsTime()))
t.Logf("comparing issues (%v,%v,%v,%v,%v,%v)",
a.Title == b.Title,
a.Message == b.Message,
a.Severity == b.Severity,
a.GetDetectedAt().AsTime().Equal(b.GetDetectedAt().AsTime()),
a.GetLastUpdated().AsTime().Equal(b.GetLastUpdated().AsTime()),
a.GetResolveBefore().AsTime().Equal(b.GetResolveBefore().AsTime()))
return a.Title == b.Title &&
a.Message == b.Message &&
a.Severity == b.Severity &&
a.DetectedAt.AsTime().Equal(b.DetectedAt.AsTime()) &&
a.LastUpdated.AsTime().Equal(b.LastUpdated.AsTime())
a.GetDetectedAt().AsTime().Equal(b.GetDetectedAt().AsTime()) &&
a.GetLastUpdated().AsTime().Equal(b.GetLastUpdated().AsTime()) &&
a.GetResolveBefore().AsTime().Equal(b.GetResolveBefore().AsTime())
}

for _, expectedIssue := range expected {
Expand Down
44 changes: 44 additions & 0 deletions internal/pb/devices.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package pb

import (
"fmt"
"slices"
"time"

timestamppb "google.golang.org/protobuf/types/known/timestamppb"
)

// Satisfy WireGuard interface.
Expand Down Expand Up @@ -38,3 +41,44 @@ func (x *Device) Healthy() bool {

return !slices.ContainsFunc(x.GetIssues(), AfterGracePeriod)
}

const lastSeenGracePeriod = time.Hour

func (x *Device) MaybeLstSeenIssue() *DeviceIssue {
if x == nil {
return nil
}

if x.LastSeen == nil {
return lastSeenIssue("This device has never been seen by Kolide. Enroll device by asking @Kolide for a new installer on Slack. `/msg @Kolide installers`", x.LastUpdated)
}

lastSeenAfter := time.Now().Add(-lastSeenGracePeriod)
if x.LastSeen.AsTime().After(lastSeenAfter) {
return nil
}

// best effort to convert time to Oslo timezone
lastSeen := x.LastSeen.AsTime()
location, err := time.LoadLocation("Europe/Oslo")
if err == nil {
lastSeen = lastSeen.In(location)
}

msg := fmt.Sprintf(`This device has not been seen by Kolide since %v.
This is a problem because we have no idea what state the device is in.
To fix this make sure the Kolide launcher is running.
If it's not and you don't know why - re-install the launcher by asking @Kolide for a new installer on Slack.`, lastSeen.Format(time.RFC3339))
return lastSeenIssue(msg, x.LastSeen)
}

func lastSeenIssue(msg string, lastUpdated *timestamppb.Timestamp) *DeviceIssue {
return &DeviceIssue{
Title: "Device has not been seen recently",
Message: msg,
Severity: Severity_Critical,
DetectedAt: lastUpdated,
LastUpdated: lastUpdated,
ResolveBefore: timestamppb.New(time.Now().Add(-lastSeenGracePeriod)),
}
}

0 comments on commit 92d6de9

Please sign in to comment.