2016-12-18 05:21:29 +00:00
|
|
|
package bolt
|
|
|
|
|
|
|
|
import (
|
2017-03-12 16:24:15 +00:00
|
|
|
"log"
|
2018-06-19 11:15:10 +00:00
|
|
|
"path"
|
2016-12-18 05:21:29 +00:00
|
|
|
"time"
|
2016-12-25 20:34:02 +00:00
|
|
|
|
|
|
|
"github.com/boltdb/bolt"
|
2019-03-21 01:20:14 +00:00
|
|
|
"github.com/portainer/portainer/api"
|
|
|
|
"github.com/portainer/portainer/api/bolt/dockerhub"
|
2020-04-16 00:22:08 +00:00
|
|
|
"github.com/portainer/portainer/api/bolt/edgegroup"
|
|
|
|
"github.com/portainer/portainer/api/bolt/edgestack"
|
2019-03-21 01:20:14 +00:00
|
|
|
"github.com/portainer/portainer/api/bolt/endpoint"
|
|
|
|
"github.com/portainer/portainer/api/bolt/endpointgroup"
|
2020-04-16 00:22:08 +00:00
|
|
|
"github.com/portainer/portainer/api/bolt/endpointrelation"
|
2019-03-21 01:20:14 +00:00
|
|
|
"github.com/portainer/portainer/api/bolt/extension"
|
|
|
|
"github.com/portainer/portainer/api/bolt/migrator"
|
|
|
|
"github.com/portainer/portainer/api/bolt/registry"
|
|
|
|
"github.com/portainer/portainer/api/bolt/resourcecontrol"
|
2019-05-24 06:04:58 +00:00
|
|
|
"github.com/portainer/portainer/api/bolt/role"
|
2019-03-21 01:20:14 +00:00
|
|
|
"github.com/portainer/portainer/api/bolt/schedule"
|
|
|
|
"github.com/portainer/portainer/api/bolt/settings"
|
|
|
|
"github.com/portainer/portainer/api/bolt/stack"
|
|
|
|
"github.com/portainer/portainer/api/bolt/tag"
|
|
|
|
"github.com/portainer/portainer/api/bolt/team"
|
|
|
|
"github.com/portainer/portainer/api/bolt/teammembership"
|
2020-04-16 00:22:08 +00:00
|
|
|
"github.com/portainer/portainer/api/bolt/tunnelserver"
|
2019-03-21 01:20:14 +00:00
|
|
|
"github.com/portainer/portainer/api/bolt/user"
|
|
|
|
"github.com/portainer/portainer/api/bolt/version"
|
|
|
|
"github.com/portainer/portainer/api/bolt/webhook"
|
2020-06-16 07:58:16 +00:00
|
|
|
"github.com/portainer/portainer/api/internal/authorization"
|
2018-06-19 11:15:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
databaseFileName = "portainer.db"
|
2016-12-18 05:21:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Store defines the implementation of portainer.DataStore using
|
|
|
|
// BoltDB as the storage system.
|
|
|
|
type Store struct {
|
2020-05-14 02:14:28 +00:00
|
|
|
path string
|
|
|
|
db *bolt.DB
|
2020-04-16 00:22:08 +00:00
|
|
|
isNew bool
|
2020-05-14 02:14:28 +00:00
|
|
|
fileService portainer.FileService
|
|
|
|
DockerHubService *dockerhub.Service
|
|
|
|
EdgeGroupService *edgegroup.Service
|
|
|
|
EdgeStackService *edgestack.Service
|
|
|
|
EndpointGroupService *endpointgroup.Service
|
|
|
|
EndpointService *endpoint.Service
|
|
|
|
EndpointRelationService *endpointrelation.Service
|
|
|
|
ExtensionService *extension.Service
|
|
|
|
RegistryService *registry.Service
|
|
|
|
ResourceControlService *resourcecontrol.Service
|
2020-05-20 05:23:15 +00:00
|
|
|
RoleService *role.Service
|
|
|
|
ScheduleService *schedule.Service
|
2020-05-14 02:14:28 +00:00
|
|
|
SettingsService *settings.Service
|
|
|
|
StackService *stack.Service
|
|
|
|
TagService *tag.Service
|
|
|
|
TeamMembershipService *teammembership.Service
|
|
|
|
TeamService *team.Service
|
|
|
|
TunnelServerService *tunnelserver.Service
|
|
|
|
UserService *user.Service
|
|
|
|
VersionService *version.Service
|
|
|
|
WebhookService *webhook.Service
|
2016-12-18 05:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewStore initializes a new Store and the associated services
|
2018-06-18 10:07:56 +00:00
|
|
|
func NewStore(storePath string, fileService portainer.FileService) (*Store, error) {
|
2016-12-18 05:21:29 +00:00
|
|
|
store := &Store{
|
2018-06-19 11:15:10 +00:00
|
|
|
path: storePath,
|
|
|
|
fileService: fileService,
|
2020-04-16 00:22:08 +00:00
|
|
|
isNew: true,
|
2018-06-19 11:15:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
databasePath := path.Join(storePath, databaseFileName)
|
|
|
|
databaseFileExists, err := fileService.FileExists(databasePath)
|
|
|
|
if err != nil {
|
2017-03-12 16:24:15 +00:00
|
|
|
return nil, err
|
2018-06-19 11:15:10 +00:00
|
|
|
}
|
|
|
|
|
2020-04-16 00:22:08 +00:00
|
|
|
if databaseFileExists {
|
|
|
|
store.isNew = false
|
2017-03-12 16:24:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return store, nil
|
2016-12-18 05:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Open opens and initializes the BoltDB database.
|
|
|
|
func (store *Store) Open() error {
|
2018-06-19 11:15:10 +00:00
|
|
|
databasePath := path.Join(store.path, databaseFileName)
|
|
|
|
db, err := bolt.Open(databasePath, 0600, &bolt.Options{Timeout: 1 * time.Second})
|
2016-12-18 05:21:29 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.db = db
|
2017-06-20 11:00:32 +00:00
|
|
|
|
2018-06-19 11:15:10 +00:00
|
|
|
return store.initServices()
|
2016-12-18 05:21:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
2020-04-16 00:22:08 +00:00
|
|
|
// IsNew returns true if the database was just created and false if it is re-using
|
|
|
|
// existing data.
|
|
|
|
func (store *Store) IsNew() bool {
|
|
|
|
return store.isNew
|
|
|
|
}
|
|
|
|
|
2017-03-12 16:24:15 +00:00
|
|
|
// MigrateData automatically migrate the data based on the DBVersion.
|
2020-04-16 00:22:08 +00:00
|
|
|
// This process is only triggered on an existing database, not if the database was just created.
|
2017-03-12 16:24:15 +00:00
|
|
|
func (store *Store) MigrateData() error {
|
2020-04-16 00:22:08 +00:00
|
|
|
if store.isNew {
|
2018-06-19 11:15:10 +00:00
|
|
|
return store.VersionService.StoreDBVersion(portainer.DBVersion)
|
2017-03-12 16:24:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
version, err := store.VersionService.DBVersion()
|
2018-06-19 11:15:10 +00:00
|
|
|
if err == portainer.ErrObjectNotFound {
|
2017-03-12 16:24:15 +00:00
|
|
|
version = 0
|
|
|
|
} else if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if version < portainer.DBVersion {
|
2018-06-19 11:15:10 +00:00
|
|
|
migratorParams := &migrator.Parameters{
|
2020-05-14 02:14:28 +00:00
|
|
|
DB: store.db,
|
|
|
|
DatabaseVersion: version,
|
|
|
|
EndpointGroupService: store.EndpointGroupService,
|
|
|
|
EndpointService: store.EndpointService,
|
|
|
|
EndpointRelationService: store.EndpointRelationService,
|
|
|
|
ExtensionService: store.ExtensionService,
|
|
|
|
RegistryService: store.RegistryService,
|
|
|
|
ResourceControlService: store.ResourceControlService,
|
|
|
|
RoleService: store.RoleService,
|
|
|
|
ScheduleService: store.ScheduleService,
|
|
|
|
SettingsService: store.SettingsService,
|
|
|
|
StackService: store.StackService,
|
|
|
|
TagService: store.TagService,
|
|
|
|
TeamMembershipService: store.TeamMembershipService,
|
|
|
|
UserService: store.UserService,
|
|
|
|
VersionService: store.VersionService,
|
|
|
|
FileService: store.fileService,
|
2020-06-16 07:58:16 +00:00
|
|
|
AuthorizationService: authorization.NewService(store),
|
2018-06-19 11:15:10 +00:00
|
|
|
}
|
|
|
|
migrator := migrator.NewMigrator(migratorParams)
|
|
|
|
|
2017-03-12 16:24:15 +00:00
|
|
|
log.Printf("Migrating database from version %v to %v.\n", version, portainer.DBVersion)
|
|
|
|
err = migrator.Migrate()
|
|
|
|
if err != nil {
|
2018-06-19 11:15:10 +00:00
|
|
|
log.Printf("An error occurred during database migration: %s\n", err)
|
2017-03-12 16:24:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2018-06-19 11:15:10 +00:00
|
|
|
|
|
|
|
func (store *Store) initServices() error {
|
2019-05-24 06:04:58 +00:00
|
|
|
authorizationsetService, err := role.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.RoleService = authorizationsetService
|
|
|
|
|
2018-06-19 11:15:10 +00:00
|
|
|
dockerhubService, err := dockerhub.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.DockerHubService = dockerhubService
|
|
|
|
|
2020-05-14 02:14:28 +00:00
|
|
|
edgeStackService, err := edgestack.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.EdgeStackService = edgeStackService
|
|
|
|
|
|
|
|
edgeGroupService, err := edgegroup.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.EdgeGroupService = edgeGroupService
|
|
|
|
|
2018-06-19 11:15:10 +00:00
|
|
|
endpointgroupService, err := endpointgroup.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.EndpointGroupService = endpointgroupService
|
|
|
|
|
|
|
|
endpointService, err := endpoint.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.EndpointService = endpointService
|
|
|
|
|
2020-05-14 02:14:28 +00:00
|
|
|
endpointRelationService, err := endpointrelation.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.EndpointRelationService = endpointRelationService
|
|
|
|
|
2018-12-09 03:49:27 +00:00
|
|
|
extensionService, err := extension.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.ExtensionService = extensionService
|
|
|
|
|
2018-06-19 11:15:10 +00:00
|
|
|
registryService, err := registry.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.RegistryService = registryService
|
|
|
|
|
|
|
|
resourcecontrolService, err := resourcecontrol.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.ResourceControlService = resourcecontrolService
|
|
|
|
|
|
|
|
settingsService, err := settings.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.SettingsService = settingsService
|
|
|
|
|
|
|
|
stackService, err := stack.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.StackService = stackService
|
|
|
|
|
|
|
|
tagService, err := tag.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.TagService = tagService
|
|
|
|
|
|
|
|
teammembershipService, err := teammembership.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.TeamMembershipService = teammembershipService
|
|
|
|
|
|
|
|
teamService, err := team.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.TeamService = teamService
|
|
|
|
|
2019-07-25 22:38:07 +00:00
|
|
|
tunnelServerService, err := tunnelserver.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.TunnelServerService = tunnelServerService
|
|
|
|
|
2018-06-19 11:15:10 +00:00
|
|
|
userService, err := user.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.UserService = userService
|
|
|
|
|
|
|
|
versionService, err := version.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.VersionService = versionService
|
|
|
|
|
2018-09-03 10:08:03 +00:00
|
|
|
webhookService, err := webhook.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.WebhookService = webhookService
|
|
|
|
|
2018-11-05 20:58:15 +00:00
|
|
|
scheduleService, err := schedule.NewService(store.db)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
store.ScheduleService = scheduleService
|
|
|
|
|
2018-06-19 11:15:10 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-05-20 05:23:15 +00:00
|
|
|
|
|
|
|
// DockerHub gives access to the DockerHub data management layer
|
|
|
|
func (store *Store) DockerHub() portainer.DockerHubService {
|
|
|
|
return store.DockerHubService
|
|
|
|
}
|
|
|
|
|
|
|
|
// EdgeGroup gives access to the EdgeGroup data management layer
|
|
|
|
func (store *Store) EdgeGroup() portainer.EdgeGroupService {
|
|
|
|
return store.EdgeGroupService
|
|
|
|
}
|
|
|
|
|
|
|
|
// EdgeStack gives access to the EdgeStack data management layer
|
|
|
|
func (store *Store) EdgeStack() portainer.EdgeStackService {
|
|
|
|
return store.EdgeStackService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Endpoint gives access to the Endpoint data management layer
|
|
|
|
func (store *Store) Endpoint() portainer.EndpointService {
|
|
|
|
return store.EndpointService
|
|
|
|
}
|
|
|
|
|
|
|
|
// EndpointGroup gives access to the EndpointGroup data management layer
|
|
|
|
func (store *Store) EndpointGroup() portainer.EndpointGroupService {
|
|
|
|
return store.EndpointGroupService
|
|
|
|
}
|
|
|
|
|
|
|
|
// EndpointRelation gives access to the EndpointRelation data management layer
|
|
|
|
func (store *Store) EndpointRelation() portainer.EndpointRelationService {
|
|
|
|
return store.EndpointRelationService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extension gives access to the Extension data management layer
|
|
|
|
func (store *Store) Extension() portainer.ExtensionService {
|
|
|
|
return store.ExtensionService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Registry gives access to the Registry data management layer
|
|
|
|
func (store *Store) Registry() portainer.RegistryService {
|
|
|
|
return store.RegistryService
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResourceControl gives access to the ResourceControl data management layer
|
|
|
|
func (store *Store) ResourceControl() portainer.ResourceControlService {
|
|
|
|
return store.ResourceControlService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Role gives access to the Role data management layer
|
|
|
|
func (store *Store) Role() portainer.RoleService {
|
|
|
|
return store.RoleService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Schedule gives access to the Schedule data management layer
|
|
|
|
func (store *Store) Schedule() portainer.ScheduleService {
|
|
|
|
return store.ScheduleService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Settings gives access to the Settings data management layer
|
|
|
|
func (store *Store) Settings() portainer.SettingsService {
|
|
|
|
return store.SettingsService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stack gives access to the Stack data management layer
|
|
|
|
func (store *Store) Stack() portainer.StackService {
|
|
|
|
return store.StackService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tag gives access to the Tag data management layer
|
|
|
|
func (store *Store) Tag() portainer.TagService {
|
|
|
|
return store.TagService
|
|
|
|
}
|
|
|
|
|
|
|
|
// TeamMembership gives access to the TeamMembership data management layer
|
|
|
|
func (store *Store) TeamMembership() portainer.TeamMembershipService {
|
|
|
|
return store.TeamMembershipService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Team gives access to the Team data management layer
|
|
|
|
func (store *Store) Team() portainer.TeamService {
|
|
|
|
return store.TeamService
|
|
|
|
}
|
|
|
|
|
|
|
|
// TunnelServer gives access to the TunnelServer data management layer
|
|
|
|
func (store *Store) TunnelServer() portainer.TunnelServerService {
|
|
|
|
return store.TunnelServerService
|
|
|
|
}
|
|
|
|
|
|
|
|
// User gives access to the User data management layer
|
|
|
|
func (store *Store) User() portainer.UserService {
|
|
|
|
return store.UserService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Version gives access to the Version data management layer
|
|
|
|
func (store *Store) Version() portainer.VersionService {
|
|
|
|
return store.VersionService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Webhook gives access to the Webhook data management layer
|
|
|
|
func (store *Store) Webhook() portainer.WebhookService {
|
|
|
|
return store.WebhookService
|
|
|
|
}
|