github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/client/state/upgrade_int_test.go (about)

     1  package state_test
     2  
     3  import (
     4  	"compress/gzip"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/hashicorp/nomad/client/allocrunner"
    14  	"github.com/hashicorp/nomad/client/allocwatcher"
    15  	clientconfig "github.com/hashicorp/nomad/client/config"
    16  	"github.com/hashicorp/nomad/client/consul"
    17  	"github.com/hashicorp/nomad/client/devicemanager"
    18  	dmstate "github.com/hashicorp/nomad/client/devicemanager/state"
    19  	"github.com/hashicorp/nomad/client/pluginmanager/drivermanager"
    20  	. "github.com/hashicorp/nomad/client/state"
    21  	"github.com/hashicorp/nomad/client/vaultclient"
    22  	"github.com/hashicorp/nomad/helper/boltdd"
    23  	"github.com/hashicorp/nomad/helper/testlog"
    24  	"github.com/hashicorp/nomad/nomad/structs"
    25  	pstructs "github.com/hashicorp/nomad/plugins/shared/structs"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  // TestBoltStateDB_Upgrade_Ok asserts upgading an old state db does not error
    31  // during upgrade and restore.
    32  func TestBoltStateDB_UpgradeOld_Ok(t *testing.T) {
    33  	t.Parallel()
    34  
    35  	files, err := filepath.Glob("testdata/*.db*")
    36  	require.NoError(t, err)
    37  
    38  	for _, fn := range files {
    39  		t.Run(fn, func(t *testing.T) {
    40  			dir, err := ioutil.TempDir("", "nomadtest")
    41  			require.NoError(t, err)
    42  			defer os.RemoveAll(dir)
    43  
    44  			var src io.ReadCloser
    45  			src, err = os.Open(fn)
    46  			require.NoError(t, err)
    47  			defer src.Close()
    48  
    49  			// testdata may be gzip'd; decode on copy
    50  			if strings.HasSuffix(fn, ".gz") {
    51  				src, err = gzip.NewReader(src)
    52  				require.NoError(t, err)
    53  			}
    54  
    55  			dst, err := os.Create(filepath.Join(dir, "state.db"))
    56  			require.NoError(t, err)
    57  
    58  			// Copy test files before testing them for safety
    59  			_, err = io.Copy(dst, src)
    60  			require.NoError(t, err)
    61  
    62  			require.NoError(t, src.Close())
    63  
    64  			dbI, err := NewBoltStateDB(testlog.HCLogger(t), dir)
    65  			require.NoError(t, err)
    66  			defer dbI.Close()
    67  
    68  			db := dbI.(*BoltStateDB)
    69  
    70  			// Simply opening old files should *not* alter them
    71  			require.NoError(t, db.DB().View(func(tx *boltdd.Tx) error {
    72  				b := tx.Bucket([]byte("meta"))
    73  				if b != nil {
    74  					return fmt.Errorf("meta bucket found but should not exist yet!")
    75  				}
    76  				return nil
    77  			}))
    78  
    79  			needsUpgrade, err := NeedsUpgrade(db.DB().BoltDB())
    80  			require.NoError(t, err)
    81  			require.True(t, needsUpgrade)
    82  
    83  			// Attept the upgrade
    84  			require.NoError(t, db.Upgrade())
    85  
    86  			needsUpgrade, err = NeedsUpgrade(db.DB().BoltDB())
    87  			require.NoError(t, err)
    88  			require.False(t, needsUpgrade)
    89  
    90  			// Ensure Allocations can be restored and
    91  			// NewAR/AR.Restore do not error.
    92  			allocs, errs, err := db.GetAllAllocations()
    93  			require.NoError(t, err)
    94  			assert.Len(t, errs, 0)
    95  
    96  			for _, alloc := range allocs {
    97  				checkUpgradedAlloc(t, dir, db, alloc)
    98  			}
    99  
   100  			// Should be nil for all upgrades
   101  			ps, err := db.GetDevicePluginState()
   102  			require.NoError(t, err)
   103  			require.Nil(t, ps)
   104  
   105  			ps = &dmstate.PluginState{
   106  				ReattachConfigs: map[string]*pstructs.ReattachConfig{
   107  					"test": {Pid: 1},
   108  				},
   109  			}
   110  			require.NoError(t, db.PutDevicePluginState(ps))
   111  
   112  			require.NoError(t, db.Close())
   113  		})
   114  	}
   115  }
   116  
   117  // checkUpgradedAlloc creates and restores an AllocRunner from an upgraded
   118  // database.
   119  //
   120  // It does not call AR.Run as its intended to be used against a wide test
   121  // corpus in testdata that may be expensive to run and require unavailable
   122  // dependencies.
   123  func checkUpgradedAlloc(t *testing.T, path string, db StateDB, alloc *structs.Allocation) {
   124  	_, err := db.GetDeploymentStatus(alloc.ID)
   125  	assert.NoError(t, err)
   126  
   127  	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
   128  	for _, task := range tg.Tasks {
   129  		_, _, err := db.GetTaskRunnerState(alloc.ID, task.Name)
   130  		require.NoError(t, err)
   131  	}
   132  
   133  	clientConf, cleanup := clientconfig.TestClientConfig(t)
   134  
   135  	// Does *not* cleanup overridden StateDir below. That's left alone for
   136  	// the caller to cleanup.
   137  	defer cleanup()
   138  
   139  	clientConf.StateDir = path
   140  
   141  	conf := &allocrunner.Config{
   142  		Alloc:             alloc,
   143  		Logger:            clientConf.Logger,
   144  		ClientConfig:      clientConf,
   145  		StateDB:           db,
   146  		Consul:            consul.NewMockConsulServiceClient(t, clientConf.Logger),
   147  		Vault:             vaultclient.NewMockVaultClient(),
   148  		StateUpdater:      &allocrunner.MockStateUpdater{},
   149  		PrevAllocWatcher:  allocwatcher.NoopPrevAlloc{},
   150  		PrevAllocMigrator: allocwatcher.NoopPrevAlloc{},
   151  		DeviceManager:     devicemanager.NoopMockManager(),
   152  		DriverManager:     drivermanager.TestDriverManager(t),
   153  	}
   154  	ar, err := allocrunner.NewAllocRunner(conf)
   155  	require.NoError(t, err)
   156  
   157  	// AllocRunner.Restore should not error
   158  	require.NoError(t, ar.Restore())
   159  }