blob: 62c84ada256bd6fe2a55264d40c659a997d52a05 [file] [log] [blame]
// Package starter provides a single function that starts up servers for a
// mounttable and a device manager that is mounted on it.
package starter
import (
"time"
"v.io/core/veyron/services/mgmt/device/config"
"v.io/core/veyron/services/mgmt/device/impl"
mounttable "v.io/core/veyron/services/mounttable/lib"
"v.io/core/veyron2"
"v.io/core/veyron2/context"
"v.io/core/veyron2/ipc"
"v.io/core/veyron2/naming"
"v.io/core/veyron2/vlog"
)
type NamespaceArgs struct {
Name string // Name to publish the mounttable service under.
ListenSpec ipc.ListenSpec // ListenSpec for the server.
ACLFile string // Path to the ACL file used by the mounttable.
// Name in the local neighborhood on which to make the mounttable
// visible. If empty, the mounttable will not be visible in the local
// neighborhood.
Neighborhood string
}
type DeviceArgs struct {
Name string // Name to publish the device service under.
ListenSpec ipc.ListenSpec // ListenSpec for the device server.
ConfigState *config.State // Configuration for the device.
TestMode bool // Whether the device is running in test mode or not.
RestartCallback func() // Callback invoked when the device service is restarted.
}
type Args struct {
Namespace NamespaceArgs
Device DeviceArgs
// If true, the global namespace will be made available on the
// mounttable server under "global/".
MountGlobalNamespaceInLocalNamespace bool
}
// Start creates servers for the mounttable and device services and links them together.
//
// Returns the callback to be invoked to shutdown the services on success, or
// an error on failure.
func Start(ctx *context.T, args Args) (func(), error) {
mtName, stopMT, err := mounttable.StartServers(ctx, args.Namespace.ListenSpec, args.Namespace.Name, args.Namespace.Neighborhood, args.Namespace.ACLFile)
if err != nil {
vlog.Errorf("mounttable.StartServers(%#v) failed: %v", args.Namespace, err)
return nil, err
}
vlog.Infof("Local mounttable (%v) published as %q", mtName, args.Namespace.Name)
if args.Device.Name == "" {
args.Device.Name = naming.Join(mtName, "devmgr")
}
stopDevice, err := startDeviceServer(ctx, args.Device, mtName)
if err != nil {
stopMT()
vlog.Errorf("Failed to start device service: %v", err)
return nil, err
}
if args.MountGlobalNamespaceInLocalNamespace {
mountGlobalNamespaceInLocalNamespace(ctx, mtName)
}
impl.InvokeCallback(ctx, args.Device.ConfigState.Name)
return func() {
stopDevice()
stopMT()
}, nil
}
// startDeviceServer creates an ipc.Server and sets it up to server the Device service.
//
// ls: ListenSpec for the server
// configState: configuration for the Device service dispatcher
// mt: Object address of the mounttable
// dm: Name to publish the device service under
// testMode: whether the service is to be run in test mode
// restarted: callback invoked when the device manager is restarted.
//
// Returns:
// (1) Function to be called to force the service to shutdown
// (2) Any errors in starting the service (in which case, (1) will be nil)
func startDeviceServer(ctx *context.T, args DeviceArgs, mt string) (shutdown func(), err error) {
server, err := veyron2.NewServer(ctx)
if err != nil {
return nil, err
}
shutdown = func() { server.Stop() }
endpoints, err := server.Listen(args.ListenSpec)
if err != nil {
shutdown()
return nil, err
}
args.ConfigState.Name = endpoints[0].Name()
vlog.Infof("Device manager object name: %v", args.ConfigState.Name)
dispatcher, err := impl.NewDispatcher(ctx, args.ConfigState, mt, args.TestMode, args.RestartCallback)
if err != nil {
shutdown()
return nil, err
}
shutdown = func() {
server.Stop()
impl.Shutdown(dispatcher)
}
if err := server.ServeDispatcher(args.Name, dispatcher); err != nil {
shutdown()
return nil, err
}
return shutdown, nil
}
func mountGlobalNamespaceInLocalNamespace(ctx *context.T, localMT string) {
ns := veyron2.GetNamespace(ctx)
for _, root := range ns.Roots() {
go func(r string) {
for {
err := ns.Mount(ctx, naming.Join(localMT, "global"), r, 0 /* forever */, naming.ServesMountTableOpt(true))
if err == nil {
break
}
vlog.Infof("Failed to Mount global namespace: %v", err)
time.Sleep(time.Second)
}
}(root)
}
}