github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/state/raft/storage/snapwrap_test.go (about)

     1  package storage
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/coreos/etcd/raft/raftpb"
    11  	"github.com/docker/swarmkit/api"
    12  	"github.com/docker/swarmkit/manager/encryption"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  var _ SnapFactory = snapCryptor{}
    17  
    18  var fakeSnapshotData = raftpb.Snapshot{
    19  	Data: []byte("snapshotdata"),
    20  	Metadata: raftpb.SnapshotMetadata{
    21  		ConfState: raftpb.ConfState{Nodes: []uint64{3}},
    22  		Index:     6,
    23  		Term:      2,
    24  	},
    25  }
    26  
    27  func getSnapshotFile(t *testing.T, tempdir string) string {
    28  	var filepaths []string
    29  	err := filepath.Walk(tempdir, func(path string, fi os.FileInfo, err error) error {
    30  		require.NoError(t, err)
    31  		if !fi.IsDir() {
    32  			filepaths = append(filepaths, path)
    33  		}
    34  		return nil
    35  	})
    36  	require.NoError(t, err)
    37  	require.Len(t, filepaths, 1)
    38  	return filepaths[0]
    39  }
    40  
    41  // Snapshotter can read snapshots that are wrapped, but not encrypted
    42  func TestSnapshotterLoadNotEncryptedSnapshot(t *testing.T) {
    43  	tempdir, err := ioutil.TempDir("", "snapwrap")
    44  	require.NoError(t, err)
    45  	defer os.RemoveAll(tempdir)
    46  
    47  	ogSnap := OriginalSnap.New(tempdir)
    48  	r := api.MaybeEncryptedRecord{
    49  		Data: fakeSnapshotData.Data,
    50  	}
    51  	data, err := r.Marshal()
    52  	require.NoError(t, err)
    53  
    54  	emptyEncryptionFakeData := fakeSnapshotData
    55  	emptyEncryptionFakeData.Data = data
    56  
    57  	require.NoError(t, ogSnap.SaveSnap(emptyEncryptionFakeData))
    58  
    59  	c := NewSnapFactory(encryption.NoopCrypter, encryption.NoopCrypter)
    60  	wrapped := c.New(tempdir)
    61  
    62  	readSnap, err := wrapped.Load()
    63  	require.NoError(t, err)
    64  	require.Equal(t, fakeSnapshotData, *readSnap)
    65  }
    66  
    67  // If there is no decrypter for a snapshot, decrypting fails
    68  func TestSnapshotterLoadNoDecrypter(t *testing.T) {
    69  	tempdir, err := ioutil.TempDir("", "snapwrap")
    70  	require.NoError(t, err)
    71  	defer os.RemoveAll(tempdir)
    72  
    73  	ogSnap := OriginalSnap.New(tempdir)
    74  	r := api.MaybeEncryptedRecord{
    75  		Data:      fakeSnapshotData.Data,
    76  		Algorithm: meowCrypter{}.Algorithm(),
    77  	}
    78  	data, err := r.Marshal()
    79  	require.NoError(t, err)
    80  
    81  	emptyEncryptionFakeData := fakeSnapshotData
    82  	emptyEncryptionFakeData.Data = data
    83  
    84  	require.NoError(t, ogSnap.SaveSnap(emptyEncryptionFakeData))
    85  
    86  	c := NewSnapFactory(encryption.NoopCrypter, encryption.NoopCrypter)
    87  	wrapped := c.New(tempdir)
    88  
    89  	_, err = wrapped.Load()
    90  	require.Error(t, err)
    91  }
    92  
    93  // If decrypting a snapshot fails, the error is propagated
    94  func TestSnapshotterLoadDecryptingFail(t *testing.T) {
    95  	tempdir, err := ioutil.TempDir("", "snapwrap")
    96  	require.NoError(t, err)
    97  	defer os.RemoveAll(tempdir)
    98  
    99  	crypter := &meowCrypter{}
   100  
   101  	ogSnap := OriginalSnap.New(tempdir)
   102  	r := api.MaybeEncryptedRecord{
   103  		Data:      fakeSnapshotData.Data,
   104  		Algorithm: crypter.Algorithm(),
   105  	}
   106  	data, err := r.Marshal()
   107  	require.NoError(t, err)
   108  
   109  	emptyEncryptionFakeData := fakeSnapshotData
   110  	emptyEncryptionFakeData.Data = data
   111  
   112  	require.NoError(t, ogSnap.SaveSnap(emptyEncryptionFakeData))
   113  
   114  	c := NewSnapFactory(encryption.NoopCrypter, crypter)
   115  	wrapped := c.New(tempdir)
   116  
   117  	_, err = wrapped.Load()
   118  	require.Error(t, err)
   119  	require.Contains(t, err.Error(), "not meowcoded")
   120  }
   121  
   122  // The snapshot data (but not metadata or anything else) is encryptd before being
   123  // passed to the wrapped Snapshotter.
   124  func TestSnapshotterSavesSnapshotWithEncryption(t *testing.T) {
   125  	tempdir, err := ioutil.TempDir("", "snapwrap")
   126  	require.NoError(t, err)
   127  	defer os.RemoveAll(tempdir)
   128  
   129  	c := NewSnapFactory(meowCrypter{}, encryption.NoopCrypter)
   130  	wrapped := c.New(tempdir)
   131  	require.NoError(t, wrapped.SaveSnap(fakeSnapshotData))
   132  
   133  	ogSnap := OriginalSnap.New(tempdir)
   134  	readSnap, err := ogSnap.Load()
   135  	require.NoError(t, err)
   136  
   137  	r := api.MaybeEncryptedRecord{}
   138  	require.NoError(t, r.Unmarshal(readSnap.Data))
   139  	require.NotEqual(t, fakeSnapshotData.Data, r.Data)
   140  	require.Equal(t, fakeSnapshotData.Metadata, readSnap.Metadata)
   141  }
   142  
   143  // If an encrypter is passed to Snapshotter, but encrypting the data fails, the
   144  // error is propagated up
   145  func TestSnapshotterSavesSnapshotEncryptionFails(t *testing.T) {
   146  	tempdir, err := ioutil.TempDir("", "snapwrap")
   147  	require.NoError(t, err)
   148  	defer os.RemoveAll(tempdir)
   149  
   150  	c := NewSnapFactory(&meowCrypter{encryptFailures: map[string]struct{}{
   151  		"snapshotdata": {},
   152  	}}, encryption.NoopCrypter)
   153  	wrapped := c.New(tempdir)
   154  	err = wrapped.SaveSnap(fakeSnapshotData)
   155  	require.Error(t, err)
   156  	require.Contains(t, err.Error(), "refusing to encrypt")
   157  
   158  	// nothing there to read
   159  	ogSnap := OriginalSnap.New(tempdir)
   160  	_, err = ogSnap.Load()
   161  	require.Error(t, err)
   162  }
   163  
   164  // Snapshotter can read what it wrote so long as it has the same decrypter
   165  func TestSaveAndLoad(t *testing.T) {
   166  	crypter := &meowCrypter{}
   167  	tempdir, err := ioutil.TempDir("", "waltests")
   168  	require.NoError(t, err)
   169  	defer os.RemoveAll(tempdir)
   170  
   171  	c := NewSnapFactory(crypter, crypter)
   172  	wrapped := c.New(tempdir)
   173  	require.NoError(t, wrapped.SaveSnap(fakeSnapshotData))
   174  	readSnap, err := wrapped.Load()
   175  	require.NoError(t, err)
   176  	require.Equal(t, fakeSnapshotData, *readSnap)
   177  }
   178  
   179  func TestMigrateSnapshot(t *testing.T) {
   180  	crypter := &meowCrypter{}
   181  	c := NewSnapFactory(crypter, crypter)
   182  	var (
   183  		err  error
   184  		dirs = make([]string, 3)
   185  	)
   186  
   187  	tempDir, err := ioutil.TempDir("", "test-migrate")
   188  	require.NoError(t, err)
   189  	defer os.RemoveAll(tempDir)
   190  
   191  	for i := range dirs {
   192  		dirs[i] = filepath.Join(tempDir, fmt.Sprintf("snapDir%d", i))
   193  	}
   194  	require.NoError(t, os.Mkdir(dirs[0], 0755))
   195  	require.NoError(t, OriginalSnap.New(dirs[0]).SaveSnap(fakeSnapshotData))
   196  
   197  	// original to new
   198  	oldDir := dirs[0]
   199  	newDir := dirs[1]
   200  
   201  	err = MigrateSnapshot(oldDir, newDir, OriginalSnap, c)
   202  	require.NoError(t, err)
   203  
   204  	readSnap, err := c.New(newDir).Load()
   205  	require.NoError(t, err)
   206  	require.Equal(t, fakeSnapshotData, *readSnap)
   207  
   208  	// new to original
   209  	oldDir = dirs[1]
   210  	newDir = dirs[2]
   211  
   212  	err = MigrateSnapshot(oldDir, newDir, c, OriginalSnap)
   213  	require.NoError(t, err)
   214  
   215  	readSnap, err = OriginalSnap.New(newDir).Load()
   216  	require.NoError(t, err)
   217  	require.Equal(t, fakeSnapshotData, *readSnap)
   218  
   219  	// We can migrate from empty directory without error
   220  	for _, dir := range dirs {
   221  		require.NoError(t, os.RemoveAll(dir))
   222  	}
   223  	require.NoError(t, os.Mkdir(dirs[0], 0755))
   224  	oldDir = dirs[0]
   225  	newDir = dirs[1]
   226  
   227  	err = MigrateSnapshot(oldDir, newDir, OriginalSnap, c)
   228  	require.NoError(t, err)
   229  
   230  	subdirs, err := ioutil.ReadDir(tempDir)
   231  	require.NoError(t, err)
   232  	require.Len(t, subdirs, 1)
   233  }