Repository: threefoldtech/zos
Pull request #1563 (2022-01-17 10:27:09)

unsafe migration


Patch:
diff --git a/cmds/modules/provisiond/main.go b/cmds/modules/provisiond/main.go
index 02ab1d18..970e1266 100644
--- a/cmds/modules/provisiond/main.go
+++ b/cmds/modules/provisiond/main.go
@@ -382,6 +382,7 @@ func storageMigration(db *storage.BoltStorage, fs *fsStorage.Fs) error {
 	if err != nil {
 		return err
 	}
+	migration := db.Migration()
 	errorred := false
 	for _, twin := range twins {
 		dls, err := fs.ByTwin(twin)
@@ -402,7 +403,7 @@ func storageMigration(db *storage.BoltStorage, fs *fsStorage.Fs) error {
 				errorred = true
 				continue
 			}
-			if err := db.Migrate(deployment); err != nil {
+			if err := migration.Migrate(deployment); err != nil {
 				log.Error().Err(err).Uint32("twin", twin).Uint64("deployment", dl).Msg("failed to migrate deployment")
 				errorred = true
 				continue
diff --git a/pkg/provision/storage/storage.go b/pkg/provision/storage/storage.go
index 7046c1f1..29189739 100644
--- a/pkg/provision/storage/storage.go
+++ b/pkg/provision/storage/storage.go
@@ -27,8 +27,13 @@ const (
 	keyGlobal               = "global"
 )
 
+type MigrationStorage struct {
+	unsafe BoltStorage
+}
+
 type BoltStorage struct {
-	db *bolt.DB
+	db     *bolt.DB
+	unsafe bool
 }
 
 var _ provision.Storage = (*BoltStorage)(nil)
@@ -40,10 +45,15 @@ func New(path string) (*BoltStorage, error) {
 	}
 
 	return &BoltStorage{
-		db,
+		db, false,
 	}, nil
 }
 
+func (b BoltStorage) Migration() MigrationStorage {
+	b.unsafe = true
+	return MigrationStorage{unsafe: b}
+}
+
 func (b *BoltStorage) u32(u uint32) []byte {
 	var v [4]byte
 	binary.BigEndian.PutUint32(v[:], u)
@@ -148,8 +158,8 @@ func (b *BoltStorage) Update(twin uint32, deployment uint64, field ...provision.
 
 // Migrate deployment creates an exact copy of dl in this storage.
 // usually used to copy deployment from older storage
-func (b *BoltStorage) Migrate(dl gridtypes.Deployment) error {
-	err := b.Create(dl)
+func (b *MigrationStorage) Migrate(dl gridtypes.Deployment) error {
+	err := b.unsafe.Create(dl)
 	if errors.Is(err, provision.ErrDeploymentExists) {
 		log.Debug().Uint32("twin", dl.TwinID).Uint64("deployment", dl.ContractID).Msg("deployment already migrated")
 		return nil
@@ -158,11 +168,11 @@ func (b *BoltStorage) Migrate(dl gridtypes.Deployment) error {
 	}
 
 	for _, wl := range dl.Workloads {
-		if err := b.Transaction(dl.TwinID, dl.ContractID, wl); err != nil {
+		if err := b.unsafe.Transaction(dl.TwinID, dl.ContractID, wl); err != nil {
 			return err
 		}
 		if wl.Result.State == gridtypes.StateDeleted {
-			if err := b.Remove(dl.TwinID, dl.ContractID, wl.Name); err != nil {
+			if err := b.unsafe.Remove(dl.TwinID, dl.ContractID, wl.Name); err != nil {
 				return err
 			}
 		}
@@ -253,9 +263,11 @@ func (b *BoltStorage) add(tx *bolt.Tx, twinID uint32, dl uint64, workload gridty
 			return errors.Wrap(err, "failed to create twin global bucket")
 		}
 
-		if value := shared.Get([]byte(workload.Name)); value != nil {
-			return errors.Wrapf(
-				provision.ErrDeploymentConflict, "global workload with the same name '%s' exists", workload.Name)
+		if !b.unsafe {
+			if value := shared.Get([]byte(workload.Name)); value != nil {
+				return errors.Wrapf(
+					provision.ErrDeploymentConflict, "global workload with the same name '%s' exists", workload.Name)
+			}
 		}
 
 		if err := shared.Put([]byte(workload.Name), b.u64(dl)); err != nil {


Test patch:
diff --git a/pkg/provision/storage/storage_test.go b/pkg/provision/storage/storage_test.go
index 50a586f7..1f77a329 100644
--- a/pkg/provision/storage/storage_test.go
+++ b/pkg/provision/storage/storage_test.go
@@ -406,7 +406,8 @@ func TestMigrate(t *testing.T) {
 		},
 	}
 
-	err = db.Migrate(dl)
+	migration := db.Migration()
+	err = migration.Migrate(dl)
 	require.NoError(err)
 
 	loaded, err := db.Get(1, 10)
@@ -417,3 +418,17 @@ func TestMigrate(t *testing.T) {
 	require.NoError(err)
 	require.EqualValues(dl, loaded)
 }
+
+func TestMigrateUnsafe(t *testing.T) {
+	require := require.New(t)
+	path := filepath.Join(os.TempDir(), fmt.Sprint(rand.Int63()))
+	defer os.RemoveAll(path)
+
+	db, err := New(path)
+	require.NoError(err)
+
+	migration := db.Migration()
+
+	require.False(db.unsafe)
+	require.True(migration.unsafe.unsafe)
+}