services/device/internal/impl: implement Status for device manager service
Use the InstanceState to describe the state for the device service. We may
decide down the road to have a special DeviceState enum instead.
Change-Id: Iba75370e48b32c23f758307dee789f5385773b09
diff --git a/services/device/internal/impl/device_service.go b/services/device/internal/impl/device_service.go
index c51a687..ce87157 100644
--- a/services/device/internal/impl/device_service.go
+++ b/services/device/internal/impl/device_service.go
@@ -654,6 +654,25 @@
return "Not implemented", nil
}
-func (*deviceService) Status(*context.T, rpc.ServerCall) (device.Status, error) {
- return nil, nil
+func (s *deviceService) Status(*context.T, rpc.ServerCall) (device.Status, error) {
+ state := device.InstanceStateRunning
+ if s.updating.updating {
+ state = device.InstanceStateUpdating
+ }
+ // Extract the version from the current link path.
+ //
+ // TODO(caprita): make the version available in the device's directory.
+ scriptPath, err := filepath.EvalSymlinks(s.config.CurrentLink)
+ if err != nil {
+ return nil, err
+ }
+ dir := filepath.Dir(scriptPath)
+ versionDir := filepath.Base(dir)
+ if versionDir == "." {
+ versionDir = "base"
+ }
+ return device.StatusInstance{Value: device.InstanceStatus{
+ State: state,
+ Version: versionDir,
+ }}, nil
}
diff --git a/services/device/internal/impl/impl_test.go b/services/device/internal/impl/impl_test.go
index 4a7743d..8e21f14 100644
--- a/services/device/internal/impl/impl_test.go
+++ b/services/device/internal/impl/impl_test.go
@@ -136,6 +136,11 @@
utiltest.Resolve(t, ctx, "claimable", 1)
// Brand new device manager must be claimed first.
utiltest.ClaimDevice(t, ctx, "claimable", "factoryDM", "mydevice", utiltest.NoPairingToken)
+
+ if v := utiltest.VerifyDeviceState(t, ctx, device.InstanceStateRunning, "factoryDM"); v != "factory" {
+ t.Errorf("Expected factory version, got %v instead", v)
+ }
+
// Simulate an invalid envelope in the application repository.
*envelope = utiltest.EnvelopeFromShell(sh, dmPauseBeforeStopEnv, utiltest.DeviceManagerCmd, "bogus", 0, 0, dmArgs...)
@@ -160,6 +165,7 @@
if scriptPathFactory == scriptPathV2 {
t.Fatalf("current link didn't change")
}
+ v2 := utiltest.VerifyDeviceState(t, ctx, device.InstanceStateUpdating, "factoryDM")
utiltest.UpdateDeviceExpectError(t, ctx, "factoryDM", impl.ErrOperationInProgress.ID)
@@ -219,6 +225,10 @@
servicetest.ReadPID(t, dmh)
utiltest.Resolve(t, ctx, "v3DM", 1) // Current link should have been launching v3.
+ v3 := utiltest.VerifyDeviceState(t, ctx, device.InstanceStateRunning, "v3DM")
+ if v2 == v3 {
+ t.Fatalf("version didn't change")
+ }
// Revert the device manager to its previous version (v2).
utiltest.RevertDevice(t, ctx, "v3DM")
diff --git a/services/device/internal/impl/reaping/instance_reaping_test.go b/services/device/internal/impl/reaping/instance_reaping_test.go
index d4c1aeb..81dd2ac 100644
--- a/services/device/internal/impl/reaping/instance_reaping_test.go
+++ b/services/device/internal/impl/reaping/instance_reaping_test.go
@@ -26,7 +26,7 @@
// Start a device manager.
// (Since it will be restarted, use the VeyronCredentials environment
// to maintain the same set of credentials across runs)
- dmCreds, err := ioutil.TempDir("", "TestDeviceManagerUpdateAndRevert")
+ dmCreds, err := ioutil.TempDir("", "TestReapReconciliationViaAppCycle")
if err != nil {
t.Fatal(err)
}
diff --git a/services/device/internal/impl/utiltest/helpers.go b/services/device/internal/impl/utiltest/helpers.go
index b92adf6..d461eb2 100644
--- a/services/device/internal/impl/utiltest/helpers.go
+++ b/services/device/internal/impl/utiltest/helpers.go
@@ -385,6 +385,21 @@
return dbg
}
+func VerifyDeviceState(t *testing.T, ctx *context.T, want device.InstanceState, name string) string {
+ s, err := DeviceStub(name).Status(ctx)
+ if err != nil {
+ t.Fatalf(testutil.FormatLogLine(2, "Status(%v) failed: %v [%v]", name, verror.ErrorID(err), err))
+ }
+ status, ok := s.(device.StatusInstance)
+ if !ok {
+ t.Fatalf(testutil.FormatLogLine(2, "Status(%v) returned unknown type: %T", name, s))
+ }
+ if status.Value.State != want {
+ t.Fatalf(testutil.FormatLogLine(2, "Status(%v) state: wanted %v, got %v", name, want, status.Value.State))
+ }
+ return status.Value.Version
+}
+
func Status(t *testing.T, ctx *context.T, nameComponents ...string) device.Status {
s, err := AppStub(nameComponents...).Status(ctx)
if err != nil {
diff --git a/services/device/internal/starter/starter.go b/services/device/internal/starter/starter.go
index e74c1e9..ac47761 100644
--- a/services/device/internal/starter/starter.go
+++ b/services/device/internal/starter/starter.go
@@ -343,6 +343,8 @@
}
shutdown = func() {
+ // TODO(caprita): Capture the Dying state by feeding it back to
+ // the dispatcher and exposing it in Status.
vlog.Infof("Stopping device server...")
server.Stop()
impl.Shutdown(dispatcher)