diff --git a/api/connection.go b/api/connection.go index 529777d6c..0d5caffe0 100644 --- a/api/connection.go +++ b/api/connection.go @@ -33,4 +33,7 @@ type Connection interface { GetAll(bucketName string, obj interface{}, append func(o interface{}) (interface{}, error)) error GetAllWithJsoniter(bucketName string, obj interface{}, append func(o interface{}) (interface{}, error)) error ConvertToKey(v int) []byte + + BackupMetadata() (map[string]interface{}, error) + RestoreMetadata(s map[string]interface{}) error } diff --git a/api/database/boltdb/db.go b/api/database/boltdb/db.go index 8ffe14ba5..e80b86339 100644 --- a/api/database/boltdb/db.go +++ b/api/database/boltdb/db.go @@ -376,3 +376,40 @@ func (connection *DbConnection) GetAllWithJsoniter(bucketName string, obj interf }) return err } + +func (connection *DbConnection) BackupMetadata() (map[string]interface{}, error) { + buckets := map[string]interface{}{} + + err := connection.View(func(tx *bolt.Tx) error { + err := tx.ForEach(func(name []byte, bucket *bolt.Bucket) error { + bucketName := string(name) + bucket = tx.Bucket([]byte(bucketName)) + seqId := bucket.Sequence() + buckets[bucketName] = int(seqId) + return nil + }) + + return err + }) + + return buckets, err +} + +func (connection *DbConnection) RestoreMetadata(s map[string]interface{}) error { + var err error + + for bucketName, v := range s { + id, ok := v.(float64) // JSON ints are unmarshalled to interface as float64. See: https://pkg.go.dev/encoding/json#Decoder.Decode + if !ok { + logrus.Errorf("Failed to restore metadata to bucket %s, skipped", bucketName) + continue + } + + err = connection.Batch(func(tx *bolt.Tx) error { + bucket := tx.Bucket([]byte(bucketName)) + return bucket.SetSequence(uint64(id)) + }) + } + + return err +} diff --git a/api/dataservices/fdoprofile/fdoprofile.go b/api/dataservices/fdoprofile/fdoprofile.go index d8f57aea9..4cb25e929 100644 --- a/api/dataservices/fdoprofile/fdoprofile.go +++ b/api/dataservices/fdoprofile/fdoprofile.go @@ -2,6 +2,7 @@ package fdoprofile import ( "fmt" + portainer "github.com/portainer/portainer/api" "github.com/sirupsen/logrus" ) diff --git a/api/datastore/services.go b/api/datastore/services.go index 5c0914dab..26da1ef19 100644 --- a/api/datastore/services.go +++ b/api/datastore/services.go @@ -369,6 +369,7 @@ type storeExport struct { User []portainer.User `json:"users,omitempty"` Version map[string]string `json:"version,omitempty"` Webhook []portainer.Webhook `json:"webhooks,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty"` } func (store *Store) Export(filename string) (err error) { @@ -561,6 +562,11 @@ func (store *Store) Export(filename string) (err error) { "INSTANCE_ID": instance, } + backup.Metadata, err = store.connection.BackupMetadata() + if err != nil { + logrus.WithError(err).Errorf("Exporting Metadata") + } + b, err := json.MarshalIndent(backup, "", " ") if err != nil { return err @@ -569,6 +575,7 @@ func (store *Store) Export(filename string) (err error) { } func (store *Store) Import(filename string) (err error) { + backup := storeExport{} s, err := ioutil.ReadFile(filename) @@ -669,5 +676,5 @@ func (store *Store) Import(filename string) (err error) { store.Webhook().UpdateWebhook(v.ID, &v) } - return nil + return store.connection.RestoreMetadata(backup.Metadata) }