blob: 8c7c708b5e0691b719a46aef8832def27f559568 [file] [log] [blame]
// 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))
}
}