| // 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/verror" |
| "v.io/x/sensorlog/internal/config" |
| "v.io/x/sensorlog/internal/sbmodel" |
| ) |
| |
| // CreateOrOpenDB opens the Sensor Log database hosted on specified Syncbase |
| // instance, creating it if missing, initializing specified collections. |
| func CreateOrOpenDB(ctx *context.T, sbService string, collections []sbmodel.CollectionSpec) (syncbase.Database, error) { |
| aclFull := access.Permissions{} |
| // Allow everyone to resolve 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) |
| |
| aclReadOnly := access.Permissions{} |
| // Allow everyone to resolve to allow joining syncgroups. |
| AddPermsForPattern(&aclReadOnly, string(security.AllPrincipals), access.Resolve) |
| // Restrict other permissions to self, except Write. |
| AddPermsForPrincipal(&aclReadOnly, v23.GetPrincipal(ctx), access.Read, access.Admin) |
| |
| 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.Database(config.DBName, nil) |
| if err := createIfMissing(ctx, db, aclFull); err != nil { |
| return nil, err |
| } |
| |
| // TODO(ivanpi): Add schemas when available. |
| for _, ts := range collections { |
| tb := db.Collection(ts.Prototype.Collection()) |
| acl := aclReadOnly |
| if !ts.ReadOnly { |
| acl = aclFull |
| } |
| if err := createIfMissing(ctx, tb, acl); err != nil { |
| return nil, err |
| } |
| } |
| |
| return db, nil |
| } |
| |
| // creatable is satisfied by Syncbase hierarchy layers (app, db, collection) |
| // 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)) |
| } |
| } |