sensorlog_lite: Syncgroup create.
measured creates the syncgroup, transferring privileges on prefixes
to a specified admin blessing.
Updated runner scripts.
Change-Id: Id65d0d4cb1eaad88abfcc574cf79999b74b64f09
diff --git a/go/src/v.io/x/sensorlog/internal/config/defaults.go b/go/src/v.io/x/sensorlog/internal/config/defaults.go
index fdb3483..8e40688 100644
--- a/go/src/v.io/x/sensorlog/internal/config/defaults.go
+++ b/go/src/v.io/x/sensorlog/internal/config/defaults.go
@@ -5,9 +5,23 @@
// Sensor Log configuration constants and default flag values.
package config
+import (
+ "v.io/v23/naming"
+)
+
const (
DefaultSbService = "syncbase"
AppName = "sensorlog_lite"
DBName = "sldb"
+
+ SyncPriority = 42
+
+ StreamDefTable = "strdef"
)
+
+var AllTables = []string{StreamDefTable}
+
+func SyncGroupName(publishService, devId string) string {
+ return naming.Join(publishService, "%%sync", "sllite", "dev", devId)
+}
diff --git a/go/src/v.io/x/sensorlog/internal/measure/doc.go b/go/src/v.io/x/sensorlog/internal/measure/doc.go
new file mode 100644
index 0000000..e753d44
--- /dev/null
+++ b/go/src/v.io/x/sensorlog/internal/measure/doc.go
@@ -0,0 +1,8 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package measure implements Sensor Log measured methods, intended to run
+// against the measured device Syncbase. It supports configuring the device
+// syncgroup.
+package measure
diff --git a/go/src/v.io/x/sensorlog/internal/measure/syncgroup.go b/go/src/v.io/x/sensorlog/internal/measure/syncgroup.go
new file mode 100644
index 0000000..3b16a8b
--- /dev/null
+++ b/go/src/v.io/x/sensorlog/internal/measure/syncgroup.go
@@ -0,0 +1,80 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Measured methods for syncgroup management.
+
+package measure
+
+import (
+ "fmt"
+
+ "v.io/v23"
+ "v.io/v23/context"
+ "v.io/v23/security/access"
+ nosql_wire "v.io/v23/services/syncbase/nosql"
+ "v.io/v23/syncbase/nosql"
+ "v.io/v23/verror"
+ "v.io/x/sensorlog_lite/internal/config"
+ "v.io/x/sensorlog_lite/internal/sbutil"
+)
+
+// InitSyncGroup creates the syncgroup for the measuring device devId, giving
+// full configuration access to admin. The syncgroup uses sgPublishSb and
+// sgMountTables for publishing (create/join) and syncing, respectively.
+// InitSyncGroup must not be called concurrently for the same devId, or
+// retried with different parameters for the same devId, otherwise behaviour
+// is unspecified.
+func InitSyncGroup(ctx *context.T, db nosql.Database, devId, admin, sgPublishSb string, sgMountTables []string) error {
+ sgName := config.SyncGroupName(sgPublishSb, devId)
+ // Check for syncgroup. If it already exists, we have nothing to do.
+ if sgs, err := db.GetSyncGroupNames(ctx); err != nil {
+ return err
+ } else {
+ for _, sg := range sgs {
+ if sg == sgName {
+ return nil
+ }
+ }
+ }
+
+ // Both measured and admin client have full permissions on the syncgroup.
+ sgAcl := access.Permissions{}
+ sbutil.AddPermsForPrincipal(&sgAcl, v23.GetPrincipal(ctx), access.AllTypicalTags()...)
+ sbutil.AddPermsForPattern(&sgAcl, admin, access.AllTypicalTags()...)
+
+ // Maps all syncgroup prefixes to ACLs.
+ prefixSpec := make(map[nosql_wire.SyncGroupPrefix]access.Permissions)
+
+ // StreamDef : <devId>
+ // Admin client has full permissions, measured drops to readonly.
+ prefixStreamDef := nosql_wire.SyncGroupPrefix{
+ TableName: config.StreamDefTable,
+ RowPrefix: devId,
+ }
+ aclStreamDef := access.Permissions{}
+ sbutil.AddPermsForPrincipal(&aclStreamDef, v23.GetPrincipal(ctx), access.Resolve, access.Read)
+ sbutil.AddPermsForPattern(&aclStreamDef, admin, access.AllTypicalTags()...)
+ prefixSpec[prefixStreamDef] = aclStreamDef
+
+ var prefixes []nosql_wire.SyncGroupPrefix
+ // Apply prefix ACLs to all syncgroup prefixes.
+ for prefix, prefixAcl := range prefixSpec {
+ // Ignore ErrNoAccess, assume we already dropped permissions.
+ err := db.Table(prefix.TableName).SetPrefixPermissions(ctx, nosql.Prefix(prefix.RowPrefix), prefixAcl)
+ if err != nil && verror.ErrorID(err) != verror.ErrNoAccess.ID {
+ return err
+ }
+ prefixes = append(prefixes, prefix)
+ }
+
+ sgSpec := nosql_wire.SyncGroupSpec{
+ Description: fmt.Sprintf("measured-main-%s", devId),
+ Perms: sgAcl,
+ Prefixes: prefixes,
+ MountTables: sgMountTables,
+ }
+ sgMemberInfo := nosql_wire.SyncGroupMemberInfo{SyncPriority: config.SyncPriority}
+
+ return db.SyncGroup(sgName).Create(ctx, sgSpec, sgMemberInfo)
+}
diff --git a/go/src/v.io/x/sensorlog/internal/measure/syncgroup_test.go b/go/src/v.io/x/sensorlog/internal/measure/syncgroup_test.go
new file mode 100644
index 0000000..5c2d473
--- /dev/null
+++ b/go/src/v.io/x/sensorlog/internal/measure/syncgroup_test.go
@@ -0,0 +1,55 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package measure_test
+
+import (
+ "reflect"
+ "testing"
+
+ "v.io/v23/verror"
+ _ "v.io/x/ref/runtime/factories/generic"
+ sbtu "v.io/x/ref/services/syncbase/testutil"
+ "v.io/x/sensorlog_lite/internal/config"
+ "v.io/x/sensorlog_lite/internal/measure"
+ "v.io/x/sensorlog_lite/internal/sbutil"
+)
+
+func TestCreateSyncgroup(t *testing.T) {
+ _, ctxMeasured, sbName, _, cleanup := sbtu.SetupOrDieCustom("one", "one/sb", nil)
+ defer cleanup()
+
+ // Open app/db (create both) as measured.
+ db, err := sbutil.CreateOrOpenDB(ctxMeasured, sbName, config.AllTables)
+ if err != nil {
+ t.Fatalf("CreateOrOpenDB should have succeeded, got error: %v", err)
+ }
+
+ devId := "measured1"
+ admin := "root/two"
+ syncMts := []string{}
+
+ // Creating the syncgroup should succeed.
+ if err := measure.InitSyncGroup(ctxMeasured, db, devId, admin, sbName, syncMts); err != nil {
+ t.Fatalf("InitSyncGroup failed: %v", err)
+ }
+
+ sgName := config.SyncGroupName(sbName, devId)
+ if sgs, err := db.GetSyncGroupNames(ctxMeasured); err != nil {
+ t.Fatalf("GetSyncGroupNames failed: %v", err)
+ } else if got, want := sgs, []string{sgName}; !reflect.DeepEqual(got, want) {
+ t.Errorf("GetSyncGroupNames got: %v, want: %v", got, want)
+ }
+
+ // Creating the syncgroup should be idempotent.
+ if err := measure.InitSyncGroup(ctxMeasured, db, devId, admin, sbName, syncMts); err != nil {
+ t.Errorf("InitSyncGroup should be idempotent, retry failed: %v", err)
+ }
+
+ // measured should have dropped privileges on <StreamDefTable>/<devId>.
+ sgDataRow := db.Table(config.StreamDefTable).Row(devId + "$" + "foo")
+ if err := sgDataRow.Put(ctxMeasured, "bar"); verror.ErrorID(err) != verror.ErrNoAccess.ID {
+ t.Errorf("Put by measured should have failed with ErrNoAccess, got: %v", err)
+ }
+}
diff --git a/go/src/v.io/x/sensorlog/internal/sbutil/syncbase.go b/go/src/v.io/x/sensorlog/internal/sbutil/syncbase.go
new file mode 100644
index 0000000..8c7c708
--- /dev/null
+++ b/go/src/v.io/x/sensorlog/internal/sbutil/syncbase.go
@@ -0,0 +1,87 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Utilities for creating and opening the database in Syncbase.
+package sbutil
+
+import (
+ "v.io/v23"
+ "v.io/v23/context"
+ "v.io/v23/security"
+ "v.io/v23/security/access"
+ "v.io/v23/syncbase"
+ "v.io/v23/syncbase/nosql"
+ "v.io/v23/verror"
+ "v.io/x/sensorlog_lite/internal/config"
+)
+
+// CreateOrOpenDB opens the Sensor Log database hosted on specified Syncbase
+// instance, creating it if missing, initializing specified tables.
+func CreateOrOpenDB(ctx *context.T, sbService string, tables []string) (nosql.Database, error) {
+ aclFull := access.Permissions{}
+ // Allow everyone to resolve app/database to allow joining syncgroups.
+ AddPermsForPattern(&aclFull, string(security.AllPrincipals), access.Resolve)
+ // Restrict other permissions to self.
+ AddPermsForPrincipal(&aclFull, v23.GetPrincipal(ctx), access.Read, access.Write, access.Admin, access.Debug)
+
+ sbs := syncbase.NewService(sbService)
+ app := sbs.App(config.AppName)
+ if err := createIfMissing(ctx, app, aclFull); err != nil {
+ return nil, err
+ }
+
+ // TODO(ivanpi): Add schema version.
+ db := app.NoSQLDatabase(config.DBName, nil)
+ if err := createIfMissing(ctx, db, aclFull); err != nil {
+ return nil, err
+ }
+
+ // TODO(ivanpi): Add table schemas when available.
+ for _, tn := range tables {
+ tb := db.Table(tn)
+ if err := createIfMissing(ctx, tb, aclFull); err != nil {
+ return nil, err
+ }
+ }
+
+ return db, nil
+}
+
+// creatable is satisfied by Syncbase hierarchy layers (app, db, table) that
+// can be created and tested for existence.
+type creatable interface {
+ Create(ctx *context.T, acl access.Permissions) error
+ Exists(ctx *context.T) (bool, error)
+}
+
+// createIfMissing checks if the given creatable layer exists and, if not,
+// creates it.
+// TODO(ivanpi): Syncbase client helpers for MustExist / CreateIfMissing.
+func createIfMissing(ctx *context.T, target creatable, acl access.Permissions) error {
+ if exists, err := target.Exists(ctx); err != nil {
+ return err
+ } else if exists {
+ return nil
+ }
+ if err := target.Create(ctx, acl); err != nil && verror.ErrorID(err) != verror.ErrExist.ID {
+ return err
+ }
+ return nil
+}
+
+// AddPermsForPrincipal adds to the ACL all specified permissions for all
+// default blessings of the provided principal.
+func AddPermsForPrincipal(acl *access.Permissions, principal security.Principal, tags ...access.Tag) {
+ for _, pattern := range security.DefaultBlessingPatterns(principal) {
+ AddPermsForPattern(acl, string(pattern), tags...)
+ }
+}
+
+// AddPermsForPattern adds to the ACL all specified permissions for the
+// specified pattern.
+func AddPermsForPattern(acl *access.Permissions, pattern string, tags ...access.Tag) {
+ for _, tag := range tags {
+ acl.Add(security.BlessingPattern(pattern), string(tag))
+ }
+}
diff --git a/go/src/v.io/x/sensorlog/internal/util/syncbase_test.go b/go/src/v.io/x/sensorlog/internal/sbutil/syncbase_test.go
similarity index 70%
rename from go/src/v.io/x/sensorlog/internal/util/syncbase_test.go
rename to go/src/v.io/x/sensorlog/internal/sbutil/syncbase_test.go
index 22de38c..40c2016 100644
--- a/go/src/v.io/x/sensorlog/internal/util/syncbase_test.go
+++ b/go/src/v.io/x/sensorlog/internal/sbutil/syncbase_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package util_test
+package sbutil_test
import (
"bytes"
@@ -13,25 +13,27 @@
"v.io/v23/verror"
_ "v.io/x/ref/runtime/factories/generic"
sbtu "v.io/x/ref/services/syncbase/testutil"
- "v.io/x/sensorlog_lite/internal/util"
+ "v.io/x/sensorlog_lite/internal/sbutil"
)
func TestCreateOrOpenDB(t *testing.T) {
- _, ctxOwner, sbName, rootPrincipal, cleanup := sbtu.SetupOrDieCustom("one", "syncbase/one", nil)
+ _, ctxOwner, sbName, rootPrincipal, cleanup := sbtu.SetupOrDieCustom("one", "one/sb", nil)
defer cleanup()
ctxGuest := sbtu.NewCtx(ctxOwner, rootPrincipal, "two")
+ mockTables := []string{"tfoo", "tbar"}
+
// Try to open app/db (create both) as guest, fail with ErrNoAccess.
- if _, err := util.CreateOrOpenDB(ctxGuest, sbName); verror.ErrorID(err) != verror.ErrNoAccess.ID {
+ if _, err := sbutil.CreateOrOpenDB(ctxGuest, sbName, mockTables); verror.ErrorID(err) != verror.ErrNoAccess.ID {
t.Errorf("CreateOrOpenDB should have failed with ErrNoAccess, got error: %v", err)
}
// Open app/db (create both) as owner.
- dbOwner, err := util.CreateOrOpenDB(ctxOwner, sbName)
+ dbOwner, err := sbutil.CreateOrOpenDB(ctxOwner, sbName, mockTables)
if err != nil {
t.Fatalf("CreateOrOpenDB should have succeeded, got error: %v", err)
}
// Open existing app/db as guest.
- if _, err := util.CreateOrOpenDB(ctxGuest, sbName); err != nil {
+ if _, err := sbutil.CreateOrOpenDB(ctxGuest, sbName, mockTables); err != nil {
t.Errorf("CreateOrOpenDB should have succeeded, got error: %v", err)
}
// Destroy db (but not app) to simulate interrupted creation.
@@ -39,16 +41,17 @@
t.Errorf("dbOwner.Destroy should have succeeded, got error: %v", err)
}
// Try to open app/db (create db) as guest, fail with ErrNoAccess.
- if _, err := util.CreateOrOpenDB(ctxGuest, sbName); verror.ErrorID(err) != verror.ErrNoAccess.ID {
+ if _, err := sbutil.CreateOrOpenDB(ctxGuest, sbName, mockTables); verror.ErrorID(err) != verror.ErrNoAccess.ID {
t.Errorf("CreateOrOpenDB should have failed with ErrNoAccess, got error: %v", err)
}
// Open app/db (recreate db) as owner.
- dbOwner, err = util.CreateOrOpenDB(ctxOwner, sbName)
+ dbOwner, err = sbutil.CreateOrOpenDB(ctxOwner, sbName, mockTables)
if err != nil {
t.Fatalf("CreateOrOpenDB should have succeeded, got error: %v", err)
}
// Open recreated app/db as guest.
- if _, err := util.CreateOrOpenDB(ctxGuest, sbName); err != nil {
+ dbGuest, err := sbutil.CreateOrOpenDB(ctxGuest, sbName, mockTables)
+ if err != nil {
t.Errorf("CreateOrOpenDB should have succeeded, got error: %v", err)
}
// Expect db permissions with full access for owner, resolve only for others.
@@ -67,4 +70,11 @@
} else if got, want := perms, expectPerms; !reflect.DeepEqual(got, want) {
t.Errorf("Unexpected database permissions: got %v, want %v", got, want)
}
+ // Check that all tables exist.
+ for _, tn := range mockTables {
+ tb := dbGuest.Table(tn)
+ if exists, err := tb.Exists(ctxGuest); err != nil || !exists {
+ t.Errorf("Expected table %s to exist, got: %v (error: %v)", tb.Name(), exists, err)
+ }
+ }
}
diff --git a/go/src/v.io/x/sensorlog/internal/util/syncbase.go b/go/src/v.io/x/sensorlog/internal/util/syncbase.go
deleted file mode 100644
index 97dcb61..0000000
--- a/go/src/v.io/x/sensorlog/internal/util/syncbase.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Utilities for creating and opening the database in Syncbase.
-package util
-
-import (
- "v.io/v23"
- "v.io/v23/context"
- "v.io/v23/security"
- "v.io/v23/security/access"
- "v.io/v23/syncbase"
- "v.io/v23/syncbase/nosql"
- "v.io/v23/verror"
- "v.io/x/sensorlog_lite/internal/config"
-)
-
-// CreateOrOpenDB opens the Sensor Log database hosted on specified Syncbase
-// instance, creating it if missing.
-// TODO(ivanpi): Syncbase client helpers for MustExist / CreateIfMissing.
-func CreateOrOpenDB(ctx *context.T, sbService string) (nosql.Database, error) {
- patterns := security.DefaultBlessingPatterns(v23.GetPrincipal(ctx))
- acl := access.Permissions{}
- // Allow everyone to resolve app/database to allow joining syncgroups.
- acl.Add(security.AllPrincipals, string(access.Resolve))
- // Restrict other permissions to self.
- for _, tag := range access.AllTypicalTags() {
- if tag != access.Resolve {
- for _, pattern := range patterns {
- acl.Add(pattern, string(tag))
- }
- }
- }
-
- sbs := syncbase.NewService(sbService)
- app := sbs.App(config.AppName)
- if err := app.Create(ctx, acl); err != nil && verror.ErrorID(err) != verror.ErrExist.ID {
- return nil, err
- }
- // TODO(ivanpi): Add schema version.
- db := app.NoSQLDatabase(config.DBName, nil)
- if err := db.Create(ctx, acl); err != nil && verror.ErrorID(err) != verror.ErrExist.ID {
- return nil, err
- }
- return db, nil
-}
diff --git a/go/src/v.io/x/sensorlog/measured/measured.go b/go/src/v.io/x/sensorlog/measured/measured.go
index f98fdf0..a353c51 100644
--- a/go/src/v.io/x/sensorlog/measured/measured.go
+++ b/go/src/v.io/x/sensorlog/measured/measured.go
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// measured is the Sensor Log measuring daemon. Runs on any device, sampling
-// data points and writing them to Syncbase. Sampling configuration is read
-// from Syncbase as written by the client.
+// measured is the Sensor Log Lite measuring daemon. Runs on any device,
+// sampling data points and writing them to Syncbase. Sampling configuration
+// is read from Syncbase as written by the client.
package main
import (
@@ -12,15 +12,21 @@
"os"
"v.io/v23"
+ "v.io/v23/naming"
"v.io/x/lib/vlog"
"v.io/x/ref/lib/signals"
_ "v.io/x/ref/runtime/factories/generic"
"v.io/x/sensorlog_lite/internal/config"
- "v.io/x/sensorlog_lite/internal/util"
+ "v.io/x/sensorlog_lite/internal/measure"
+ "v.io/x/sensorlog_lite/internal/sbutil"
)
var (
flagSbService = flag.String("service", config.DefaultSbService, "Location of the Syncbase service to connect to. Can be absolute or relative to the namespace root.")
+ flagDevId = flag.String("devid", "", "DevId to be claimed by this measured. Must be specified.")
+ // Flags below are only applied the first time measured is run against a Syncbase service with the same devid.
+ flagAdmin = flag.String("admin", "", "Blessing of admin user allowed to join the syncgroup. Must be specified.")
+ flagPublishSb = flag.String("publish-sb", "", "Syncbase service to publish the syncgroup at. Must be absolute. Must be specified. The syncgroup is published as '"+config.SyncGroupName("<publish-sb>", "<devid>")+"'.")
)
func main() {
@@ -30,15 +36,34 @@
func runMain() int {
ctx, shutdown := v23.Init()
defer shutdown()
- vlog.VI(2).Infof("Default blessings: %v", v23.GetPrincipal(ctx).BlessingStore().Default())
- db, err := util.CreateOrOpenDB(ctx, *flagSbService)
+ if *flagDevId == "" {
+ vlog.Errorf("-devid must be specified")
+ return 1
+ }
+ if *flagAdmin == "" {
+ vlog.Errorf("-admin must be specified")
+ return 1
+ }
+ if !naming.Rooted(*flagPublishSb) {
+ vlog.Errorf("-publish-sb must be rooted")
+ return 1
+ }
+ publishMts := v23.GetNamespace(ctx).Roots()
+
+ db, err := sbutil.CreateOrOpenDB(ctx, *flagSbService, config.AllTables)
if err != nil {
vlog.Errorf("Failed opening Syncbase db: %v", err)
return 1
}
vlog.VI(0).Infof("measured connected to %s", db.FullName())
+ if err := measure.InitSyncGroup(ctx, db, *flagDevId, *flagAdmin, *flagPublishSb, publishMts); err != nil {
+ vlog.Errorf("Failed initializing syncgroup: %v", err)
+ return 1
+ }
+
<-signals.ShutdownOnSignals(ctx)
+
return 0
}
diff --git a/go/src/v.io/x/sensorlog/scripts/run_cli_syncbased.sh b/go/src/v.io/x/sensorlog/scripts/run_cli_syncbased.sh
index 3bff033..0e3d43a 100755
--- a/go/src/v.io/x/sensorlog/scripts/run_cli_syncbased.sh
+++ b/go/src/v.io/x/sensorlog/scripts/run_cli_syncbased.sh
@@ -10,16 +10,18 @@
source "${JIRI_ROOT}/experimental/projects/sensorlog_lite/src/v.io/x/sensorlog_lite/scripts/runner_lib.sh"
# Must be run with V23_CREDENTIALS set or through the agent.
-# Optional environment variables: SL_BLESSNAME, SL_NAME, SL_IPADDR_PORT, SL_TMPDIR
+# Optional environment variables: SL_PREFIX, SL_DEVID, SL_IPADDR_PORT, SL_TMPDIR
function main() {
- local -r BLESSNAME="${SL_BLESSNAME:-sluser}"
- local -r NAME="${SL_NAME:-client1}"
- local -r IPADDR_PORT="${SL_IPADDR_PORT:-127.0.0.1:8909}"
+ local -r PREFIX="${SL_PREFIX:-sl/client}"
+ local -r DEVID="${SL_DEVID:-$(gen_uuid)}"
+ local -r NAME="${PREFIX}/${DEVID}"
+ local -r IPADDR_PORT="${SL_IPADDR_PORT:-$(dig $(hostname) +short):8707}"
local -r TMPDIR="${SL_TMPDIR:-sltmp}/${NAME}"
+
mkdir -p "${TMPDIR}"
trap "kill_child_processes; exit 1" ERR EXIT
- run_mounttabled "${BLESSNAME}" "${NAME}" "${IPADDR_PORT}"
- run_syncbased "${BLESSNAME}" "/${IPADDR_PORT}" "syncbased/slcli/${NAME}" "${TMPDIR}"
+ run_mounttabled "${NAME}" "${IPADDR_PORT}"
+ run_syncbased "/${IPADDR_PORT}" "${NAME}" "${TMPDIR}"
# Wait for signal.
while true; do
sleep 10
diff --git a/go/src/v.io/x/sensorlog/scripts/run_measured.sh b/go/src/v.io/x/sensorlog/scripts/run_measured.sh
index 68e5fb0..5590274 100755
--- a/go/src/v.io/x/sensorlog/scripts/run_measured.sh
+++ b/go/src/v.io/x/sensorlog/scripts/run_measured.sh
@@ -4,22 +4,33 @@
# license that can be found in the LICENSE file.
# Starts an instance of measured and required services.
+#
+# mounttabled is started locally with syncbased. measured connects to it
+# and bootstraps the syncgroup joinable at:
+# /$IPADDR_PORT/$PREFIX/$DEVID/syncbased.
+# measured drops most permissions on prefixes in the syncgroup. Full admin
+# permissions are granted to $ADMIN (as a blessing extension of the same
+# default blessing as the one running this script).
set -eu
source "${JIRI_ROOT}/experimental/projects/sensorlog_lite/src/v.io/x/sensorlog_lite/scripts/runner_lib.sh"
# Must be run with V23_CREDENTIALS set or through the agent.
-# Optional environment variables: SL_BLESSNAME, SL_NAME, SL_IPADDR_PORT, SL_TMPDIR
+# Optional environment variables: SL_PREFIX, SL_DEVID, SL_ADMIN, SL_IPADDR_PORT, SL_TMPDIR
function main() {
- local -r BLESSNAME="${SL_BLESSNAME:-sluser}"
- local -r NAME="${SL_NAME:-measured1}"
- local -r IPADDR_PORT="${SL_IPADDR_PORT:-127.0.0.1:8707}"
+ local -r PREFIX="${SL_PREFIX:-sl/measured}"
+ local -r DEVID="${SL_DEVID:-$(gen_uuid)}"
+ local -r ADMIN="${SL_ADMIN:-sl/client}"
+ local -r NAME="${PREFIX}/${DEVID}"
+ local -r IPADDR_PORT="${SL_IPADDR_PORT:-$(dig $(hostname) +short):8707}"
local -r TMPDIR="${SL_TMPDIR:-sltmp}/${NAME}"
+
mkdir -p "${TMPDIR}"
trap "kill_child_processes; exit 1" ERR EXIT
- run_mounttabled "${BLESSNAME}" "${NAME}" "${IPADDR_PORT}"
- run_measured "${BLESSNAME}" "/${IPADDR_PORT}" "${NAME}" "${TMPDIR}"
+ run_mounttabled "${NAME}" "${IPADDR_PORT}"
+ run_syncbased "/${IPADDR_PORT}" "${NAME}" "${TMPDIR}"
+ run_measured "/${IPADDR_PORT}" "${NAME}" "${DEVID}" "${ADMIN}"
# Wait for signal.
while true; do
sleep 10
diff --git a/go/src/v.io/x/sensorlog/scripts/runner_lib.sh b/go/src/v.io/x/sensorlog/scripts/runner_lib.sh
index c81b82b..16c76d7 100644
--- a/go/src/v.io/x/sensorlog/scripts/runner_lib.sh
+++ b/go/src/v.io/x/sensorlog/scripts/runner_lib.sh
@@ -5,10 +5,12 @@
# Functions for starting the Sensor Log daemon and required services with
# appropriate blessings. Expected to be run with V23_CREDENTIALS or through
-# an agent.
+# an agent. NAME parameters are used both in service names and in blessing
+# extensions.
set -eu
+# Kills all child processes of the current process.
function kill_child_processes() {
kill -TERM -- -"${BASHPID}" || true
sleep 1
@@ -16,32 +18,48 @@
}
export -f kill_child_processes
+# Generates a hex-encoded 16-byte random UUID.
+function gen_uuid() {
+ head -c 256 /dev/urandom | sha256sum | cut -c 1-32
+}
+export -f gen_uuid
+
+readonly BLESSING_CHAIN_SEPARATOR='/'
+
+# Converts name to blessing extension.
+# name_to_blessing NAME
function name_to_blessing() {
- local -r CHAIN_SEPARATOR='/'
- sed -e "s,/,${CHAIN_SEPARATOR},g" <<< "$@"
+ sed -e "s,/,${BLESSING_CHAIN_SEPARATOR},g" <<< "$@"
}
export -f name_to_blessing
+# Gets first default blessing for the principal set in the environment.
+function get_blessing_root() {
+ "${JIRI_ROOT}"/release/go/bin/principal dump -s | cut -d ' ' -f 1 | cut -d ',' -f 1
+}
+export -f get_blessing_root
+
+# Starts mounttabled at IPADDR:PORT.
+# run_mounttabled NAME IPADDR:PORT
function run_mounttabled() {
- local -r BLESSNAME="$1"
- local -r NAME="$2"
- local -r IPADDR_PORT="$3"
- "${JIRI_ROOT}"/release/go/bin/vbecome -name="$(name_to_blessing "${BLESSNAME}/sl/mounttabled/${NAME}")" \
+ local -r NAME="$1"
+ local -r IPADDR_PORT="$2"
+ # TODO(ivanpi): Lock down mounttable permissions.
+ "${JIRI_ROOT}"/release/go/bin/vbecome -name="$(name_to_blessing "${NAME}/mounttabled")" \
"${JIRI_ROOT}"/release/go/bin/mounttabled -v23.tcp.address "${IPADDR_PORT}" \
&
sleep 1
}
export -f run_mounttabled
+# Starts syncbased with permissions other than resolve restricted to
+# <blessing_root>:$NAME.
+# run_syncbased MT NAME TMPDIR
function run_syncbased() {
- local -r BLESSNAME="$1"
- local -r MT="$2"
- local -r NAME="$3"
- local -r TMPDIR="$4"
- local -r DEF_BLESSING_ROOT="$("${JIRI_ROOT}"/release/go/bin/principal dump -s | cut -d ' ' -f 1 | cut -d ',' -f 1)"
- local -r DEF_BLESSING_RUNNER="$(name_to_blessing "${DEF_BLESSING_ROOT}/${BLESSNAME}/sl/${NAME}")"
- # Everyone can Resolve to be able to join the syncgroup.
- echo "$DEF_BLESSING_RUNNER"
+ local -r MT="$1"
+ local -r NAME="$2"
+ local -r TMPDIR="$3"
+ local -r DEF_BLESSING_RUNNER="$(name_to_blessing "$(get_blessing_root)/${NAME}")"
local -r PERMISSIONS_LITERAL="{\
\"Admin\":{\"In\":[\"${DEF_BLESSING_RUNNER}\"]}, \
\"Read\":{\"In\":[\"${DEF_BLESSING_RUNNER}\"]}, \
@@ -49,24 +67,28 @@
\"Debug\":{\"In\":[\"${DEF_BLESSING_RUNNER}\"]}, \
\"Resolve\":{\"In\":[\"...\"]} \
}"
- "${JIRI_ROOT}"/release/go/bin/vbecome -name="$(name_to_blessing "${BLESSNAME}/sl/syncbased/${NAME}")" \
- "${JIRI_ROOT}"/release/go/bin/syncbased -v23.namespace.root "${MT}" \
- -name "syncbased/${NAME}" -engine leveldb -root-dir "${TMPDIR}/syncbased/${NAME}" \
- -v23.permissions.literal="${PERMISSIONS_LITERAL}" \
+ "${JIRI_ROOT}"/release/go/bin/vbecome -name "$(name_to_blessing "${NAME}/syncbased")" \
+ "${JIRI_ROOT}"/release/go/bin/syncbased -v23.namespace.root "${MT}" -name "${NAME}/syncbased" \
+ -engine leveldb -root-dir "${TMPDIR}/${NAME}/syncbased" \
+ -v23.permissions.literal "${PERMISSIONS_LITERAL}" \
&
sleep 1
}
export -f run_syncbased
+# Starts measured publishing the syncgroup at the local mounttable. Expects a
+# syncbase instance to have been started at $MT with the same $NAME.
+# run_measured MT NAME DEVID ADMIN
function run_measured() {
- local -r BLESSNAME="$1"
- local -r MT="$2"
- local -r NAME="$3"
- local -r TMPDIR="$4"
- run_syncbased "${BLESSNAME}" "${MT}" "measured/${NAME}" "${TMPDIR}"
- "${JIRI_ROOT}"/release/go/bin/vbecome -name="$(name_to_blessing "${BLESSNAME}/sl/measured/${NAME}")" \
+ local -r MT="$1"
+ local -r NAME="$2"
+ local -r DEVID="$3"
+ local -r ADMIN="$4"
+ local -r DEF_BLESSING_ADMIN="$(name_to_blessing "$(get_blessing_root)/${ADMIN}")"
+ "${JIRI_ROOT}"/release/go/bin/vbecome -name="$(name_to_blessing "${NAME}")" \
"${JIRI_ROOT}"/experimental/projects/sensorlog_lite/bin/measured -v23.namespace.root "${MT}" \
- -service "syncbased/measured/${NAME}" -alsologtostderr \
+ -service "${NAME}/syncbased" -devid="${DEVID}" -admin="${DEF_BLESSING_ADMIN}" \
+ -publish-sb "${MT}/${NAME}/syncbased" -alsologtostderr \
&
sleep 1
}