veyron/services/mgmt/application: fix applicationd persistence
Applicationd's Dispatcher was not configuring a persistent backing
store for its state per
https://github.com/veyron/release-issues/issues/299. Fix this.
Change-Id: Ia0a60461308d3b6adb09c3da17228afa968479c4
diff --git a/services/mgmt/application/impl/dispatcher.go b/services/mgmt/application/impl/dispatcher.go
index 3fda1a4..3d9346b 100644
--- a/services/mgmt/application/impl/dispatcher.go
+++ b/services/mgmt/application/impl/dispatcher.go
@@ -1,6 +1,8 @@
package impl
import (
+ "path/filepath"
+
"veyron.io/veyron/veyron/services/mgmt/repository"
"veyron.io/veyron/veyron/services/mgmt/lib/fs"
@@ -17,14 +19,14 @@
var _ ipc.Dispatcher = (*dispatcher)(nil)
-// NewDispatcher is the dispatcher factory.
-func NewDispatcher(name string, authorizer security.Authorizer) (*dispatcher, error) {
- // TODO(rjkroege@google.com): Use the config service.
- store, err := fs.NewMemstore("")
+// NewDispatcher is the dispatcher factory. storeDir is a path to a directory in which to
+// serialize the applicationd state.
+func NewDispatcher(storeDir string, authorizer security.Authorizer) (*dispatcher, error) {
+ store, err := fs.NewMemstore(filepath.Join(storeDir, "applicationdstate.db"))
if err != nil {
return nil, err
}
- return &dispatcher{store: store, storeRoot: name, auth: authorizer}, nil
+ return &dispatcher{store: store, storeRoot: storeDir, auth: authorizer}, nil
}
// DISPATCHER INTERFACE IMPLEMENTATION
diff --git a/services/mgmt/application/impl/impl_test.go b/services/mgmt/application/impl/impl_test.go
index 845c5ee..50e9ce2 100644
--- a/services/mgmt/application/impl/impl_test.go
+++ b/services/mgmt/application/impl/impl_test.go
@@ -2,6 +2,7 @@
import (
"io/ioutil"
+ "os"
"reflect"
"testing"
@@ -17,21 +18,15 @@
// TestInterface tests that the implementation correctly implements
// the Application interface.
func TestInterface(t *testing.T) {
- runtime := rt.Init()
- ctx := runtime.NewContext()
- defer runtime.Cleanup()
+ ctx := rt.R().NewContext()
// Setup and start the application repository server.
- server, err := runtime.NewServer()
+ server, err := rt.R().NewServer()
if err != nil {
t.Fatalf("NewServer() failed: %v", err)
}
defer server.Stop()
- server, err = runtime.NewServer()
- if err != nil {
- t.Fatalf("NewServer() failed: %v", err)
- }
dir, prefix := "", ""
store, err := ioutil.TempDir(dir, prefix)
if err != nil {
@@ -156,3 +151,88 @@
t.Fatalf("Stop() failed: %v", err)
}
}
+
+func init() {
+ rt.Init()
+}
+
+func TestPreserveAcrossRestarts(t *testing.T) {
+ server, err := rt.R().NewServer()
+ if err != nil {
+ t.Fatalf("NewServer() failed: %v", err)
+ }
+ defer server.Stop()
+ dir, prefix := "", ""
+ storedir, err := ioutil.TempDir(dir, prefix)
+ if err != nil {
+ t.Fatalf("TempDir(%q, %q) failed: %v", dir, prefix, err)
+ }
+ defer os.RemoveAll(storedir)
+
+ dispatcher, err := NewDispatcher(storedir, nil)
+ if err != nil {
+ t.Fatalf("NewDispatcher() failed: %v", err)
+ }
+
+ endpoint, err := server.Listen(profiles.LocalListenSpec)
+ if err != nil {
+ t.Fatalf("Listen(%s) failed: %v", profiles.LocalListenSpec, err)
+ }
+ if err := server.ServeDispatcher("", dispatcher); err != nil {
+ t.Fatalf("Serve(%v) failed: %v", dispatcher, err)
+ }
+
+ // Create client stubs for talking to the server.
+ stubV1 := repository.ApplicationClient(naming.JoinAddressName(endpoint.String(), "search/v1"))
+
+ // Create example envelopes.
+ envelopeV1 := application.Envelope{
+ Args: []string{"--help"},
+ Env: []string{"DEBUG=1"},
+ Binary: "/veyron/name/of/binary",
+ }
+
+ if err := stubV1.Put(rt.R().NewContext(), []string{"media"}, envelopeV1); err != nil {
+ t.Fatalf("Put() failed: %v", err)
+ }
+
+ // There is content here now.
+ output, err := stubV1.Match(rt.R().NewContext(), []string{"media"})
+ if err != nil {
+ t.Fatalf("Match(%v) failed: %v", "media", err)
+ }
+ if !reflect.DeepEqual(envelopeV1, output) {
+ t.Fatalf("Incorrect output: expected %v, got %v", envelopeV1, output)
+ }
+
+ server.Stop()
+
+ // Setup and start a second application server in its place.
+ server, err = rt.R().NewServer()
+ if err != nil {
+ t.Fatalf("NewServer() failed: %v", err)
+ }
+ defer server.Stop()
+
+ dispatcher, err = NewDispatcher(storedir, nil)
+ if err != nil {
+ t.Fatalf("NewDispatcher() failed: %v", err)
+ }
+ endpoint, err = server.Listen(profiles.LocalListenSpec)
+ if err != nil {
+ t.Fatalf("Listen(%s) failed: %v", profiles.LocalListenSpec, err)
+ }
+ if err := server.ServeDispatcher("", dispatcher); err != nil {
+ t.Fatalf("Serve(%v) failed: %v", dispatcher, err)
+ }
+
+ stubV1 = repository.ApplicationClient(naming.JoinAddressName(endpoint.String(), "search/v1"))
+
+ output, err = stubV1.Match(rt.R().NewContext(), []string{"media"})
+ if err != nil {
+ t.Fatalf("Match(%v) failed: %v", "media", err)
+ }
+ if !reflect.DeepEqual(envelopeV1, output) {
+ t.Fatalf("Incorrect output: expected %v, got %v", envelopeV1, output)
+ }
+}
diff --git a/services/mgmt/profile/impl/dispatcher.go b/services/mgmt/profile/impl/dispatcher.go
index 6c28885..25c1862 100644
--- a/services/mgmt/profile/impl/dispatcher.go
+++ b/services/mgmt/profile/impl/dispatcher.go
@@ -1,6 +1,8 @@
package impl
import (
+ "path/filepath"
+
"veyron.io/veyron/veyron/services/mgmt/repository"
"veyron.io/veyron/veyron/services/mgmt/lib/fs"
@@ -17,14 +19,14 @@
var _ ipc.Dispatcher = (*dispatcher)(nil)
-// NewDispatcher is the dispatcher factory.
-func NewDispatcher(name string, authorizer security.Authorizer) (*dispatcher, error) {
- // TODO(rjkroege@google.com): Use the config service.
- store, err := fs.NewMemstore("")
+// NewDispatcher is the dispatcher factory. storeDir is a path to a
+// directory in which the profile state is persisted.
+func NewDispatcher(storeDir string, authorizer security.Authorizer) (*dispatcher, error) {
+ store, err := fs.NewMemstore(filepath.Join(storeDir, "profilestate.db"))
if err != nil {
return nil, err
}
- return &dispatcher{store: store, storeRoot: name, auth: authorizer}, nil
+ return &dispatcher{store: store, storeRoot: storeDir, auth: authorizer}, nil
}
// DISPATCHER INTERFACE IMPLEMENTATION
diff --git a/services/mgmt/profile/impl/impl_test.go b/services/mgmt/profile/impl/impl_test.go
index 8d0a9e7..d0a4521 100644
--- a/services/mgmt/profile/impl/impl_test.go
+++ b/services/mgmt/profile/impl/impl_test.go
@@ -2,6 +2,7 @@
import (
"io/ioutil"
+ "os"
"reflect"
"testing"
@@ -29,9 +30,7 @@
// TestInterface tests that the implementation correctly implements
// the Profile interface.
func TestInterface(t *testing.T) {
- runtime := rt.Init()
- defer runtime.Cleanup()
-
+ runtime := rt.R()
ctx := runtime.NewContext()
// Setup and start the profile repository server.
@@ -41,11 +40,6 @@
}
defer server.Stop()
- // Setup and start the profile server.
- server, err = runtime.NewServer()
- if err != nil {
- t.Fatalf("NewServer() failed: %v", err)
- }
dir, prefix := "", ""
store, err := ioutil.TempDir(dir, prefix)
if err != nil {
@@ -109,3 +103,88 @@
t.Fatalf("Stop() failed: %v", err)
}
}
+
+func init() {
+ rt.Init()
+}
+
+func TestPreserveAcrossRestarts(t *testing.T) {
+ runtime := rt.R()
+ ctx := runtime.NewContext()
+
+ // Setup and start the profile repository server.
+ server, err := runtime.NewServer()
+ if err != nil {
+ t.Fatalf("NewServer() failed: %v", err)
+ }
+ defer server.Stop()
+
+ dir, prefix := "", ""
+ storedir, err := ioutil.TempDir(dir, prefix)
+ if err != nil {
+ t.Fatalf("TempDir(%q, %q) failed: %v", dir, prefix, err)
+ }
+ defer os.RemoveAll(storedir)
+
+ dispatcher, err := NewDispatcher(storedir, nil)
+ if err != nil {
+ t.Fatalf("NewDispatcher() failed: %v", err)
+ }
+ endpoint, err := server.Listen(profiles.LocalListenSpec)
+ if err != nil {
+ t.Fatalf("Listen(%s) failed: %v", profiles.LocalListenSpec, err)
+ }
+ if err := server.ServeDispatcher("", dispatcher); err != nil {
+ t.Fatalf("Serve failed: %v", err)
+ }
+ t.Logf("Profile repository at %v", endpoint)
+
+ // Create client stubs for talking to the server.
+ stub := repository.ProfileClient(naming.JoinAddressName(endpoint.String(), "linux/base"))
+
+ if err := stub.Put(ctx, spec); err != nil {
+ t.Fatalf("Put() failed: %v", err)
+ }
+
+ label, err := stub.Label(ctx)
+ if err != nil {
+ t.Fatalf("Label() failed: %v", err)
+ }
+ if label != spec.Label {
+ t.Fatalf("Unexpected output: expected %v, got %v", spec.Label, label)
+ }
+
+ // Stop the first server.
+ server.Stop()
+
+ // Setup and start a second server.
+ server, err = runtime.NewServer()
+ if err != nil {
+ t.Fatalf("NewServer() failed: %v", err)
+ }
+ defer server.Stop()
+
+ dispatcher, err = NewDispatcher(storedir, nil)
+ if err != nil {
+ t.Fatalf("NewDispatcher() failed: %v", err)
+ }
+ endpoint, err = server.Listen(profiles.LocalListenSpec)
+ if err != nil {
+ t.Fatalf("Listen(%s) failed: %v", profiles.LocalListenSpec, err)
+ }
+ if err = server.ServeDispatcher("", dispatcher); err != nil {
+ t.Fatalf("Serve failed: %v", err)
+ }
+
+ // Create client stubs for talking to the server.
+ stub = repository.ProfileClient(naming.JoinAddressName(endpoint.String(), "linux/base"))
+
+ // Label
+ label, err = stub.Label(ctx)
+ if err != nil {
+ t.Fatalf("Label() failed: %v", err)
+ }
+ if label != spec.Label {
+ t.Fatalf("Unexpected output: expected %v, got %v", spec.Label, label)
+ }
+}