2016-12-18 05:21:29 +00:00
|
|
|
package bolt
|
|
|
|
|
|
|
|
import (
|
2017-03-12 16:24:15 +00:00
|
|
|
"log"
|
|
|
|
"os"
|
2016-12-18 05:21:29 +00:00
|
|
|
"time"
|
2016-12-25 20:34:02 +00:00
|
|
|
|
|
|
|
"github.com/boltdb/bolt"
|
2017-03-12 16:24:15 +00:00
|
|
|
"github.com/portainer/portainer"
|
2016-12-18 05:21:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Store defines the implementation of portainer.DataStore using
|
|
|
|
// BoltDB as the storage system.
|
|
|
|
type Store struct {
|
|
|
|
// Path where is stored the BoltDB database.
|
|
|
|
Path string
|
|
|
|
|
|
|
|
// Services
|
2017-03-12 16:24:15 +00:00
|
|
|
UserService *UserService
|
2017-05-23 18:56:10 +00:00
|
|
|
TeamService *TeamService
|
|
|
|
TeamMembershipService *TeamMembershipService
|
2017-03-12 16:24:15 +00:00
|
|
|
EndpointService *EndpointService
|
|
|
|
ResourceControlService *ResourceControlService
|
|
|
|
VersionService *VersionService
|
2016-12-18 05:21:29 +00:00
|
|
|
|
2017-03-12 16:24:15 +00:00
|
|
|
db *bolt.DB
|
|
|
|
checkForDataMigration bool
|
2016-12-18 05:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2017-05-23 18:56:10 +00:00
|
|
|
databaseFileName = "portainer.db"
|
|
|
|
versionBucketName = "version"
|
|
|
|
userBucketName = "users"
|
|
|
|
teamBucketName = "teams"
|
|
|
|
teamMembershipBucketName = "team_membership"
|
|
|
|
endpointBucketName = "endpoints"
|
|
|
|
resourceControlBucketName = "resource_control"
|
2016-12-18 05:21:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// NewStore initializes a new Store and the associated services
|
2017-03-12 16:24:15 +00:00
|
|
|
func NewStore(storePath string) (*Store, error) {
|
2016-12-18 05:21:29 +00:00
|
|
|
store := &Store{
|
2017-03-12 16:24:15 +00:00
|
|
|
Path: storePath,
|
|
|
|
UserService: &UserService{},
|
2017-05-23 18:56:10 +00:00
|
|
|
TeamService: &TeamService{},
|
|
|
|
TeamMembershipService: &TeamMembershipService{},
|
2017-03-12 16:24:15 +00:00
|
|
|
EndpointService: &EndpointService{},
|
|
|
|
ResourceControlService: &ResourceControlService{},
|
|
|
|
VersionService: &VersionService{},
|
2016-12-18 05:21:29 +00:00
|
|
|
}
|
|
|
|
store.UserService.store = store
|
2017-05-23 18:56:10 +00:00
|
|
|
store.TeamService.store = store
|
|
|
|
store.TeamMembershipService.store = store
|
2016-12-25 20:34:02 +00:00
|
|
|
store.EndpointService.store = store
|
2017-03-12 16:24:15 +00:00
|
|
|
store.ResourceControlService.store = store
|
|
|
|
store.VersionService.store = store
|
|
|
|
|
2017-03-16 10:23:01 +00:00
|
|
|
_, err := os.Stat(storePath + "/" + databaseFileName)
|
2017-03-12 16:24:15 +00:00
|
|
|
if err != nil && os.IsNotExist(err) {
|
|
|
|
store.checkForDataMigration = false
|
|
|
|
} else if err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
store.checkForDataMigration = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return store, nil
|
2016-12-18 05:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Open opens and initializes the BoltDB database.
|
|
|
|
func (store *Store) Open() error {
|
|
|
|
path := store.Path + "/" + databaseFileName
|
|
|
|
db, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 1 * time.Second})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.db = db
|
|
|
|
return db.Update(func(tx *bolt.Tx) error {
|
2017-03-12 16:24:15 +00:00
|
|
|
_, err := tx.CreateBucketIfNotExists([]byte(versionBucketName))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = tx.CreateBucketIfNotExists([]byte(userBucketName))
|
2016-12-18 05:21:29 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-05-23 18:56:10 +00:00
|
|
|
_, err = tx.CreateBucketIfNotExists([]byte(teamBucketName))
|
2016-12-25 20:34:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-05-23 18:56:10 +00:00
|
|
|
_, err = tx.CreateBucketIfNotExists([]byte(endpointBucketName))
|
2017-03-12 16:24:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-05-23 18:56:10 +00:00
|
|
|
_, err = tx.CreateBucketIfNotExists([]byte(resourceControlBucketName))
|
2017-03-12 16:24:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-05-23 18:56:10 +00:00
|
|
|
_, err = tx.CreateBucketIfNotExists([]byte(teamMembershipBucketName))
|
2016-12-25 20:34:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2016-12-18 05:21:29 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close closes the BoltDB database.
|
|
|
|
func (store *Store) Close() error {
|
|
|
|
if store.db != nil {
|
|
|
|
return store.db.Close()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2017-03-12 16:24:15 +00:00
|
|
|
|
|
|
|
// MigrateData automatically migrate the data based on the DBVersion.
|
|
|
|
func (store *Store) MigrateData() error {
|
|
|
|
if !store.checkForDataMigration {
|
|
|
|
err := store.VersionService.StoreDBVersion(portainer.DBVersion)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
version, err := store.VersionService.DBVersion()
|
|
|
|
if err == portainer.ErrDBVersionNotFound {
|
|
|
|
version = 0
|
|
|
|
} else if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if version < portainer.DBVersion {
|
|
|
|
log.Printf("Migrating database from version %v to %v.\n", version, portainer.DBVersion)
|
|
|
|
migrator := NewMigrator(store, version)
|
|
|
|
err = migrator.Migrate()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|