github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/backups/files_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // +build !windows
     5  
     6  package backups_test
     7  
     8  import (
     9  	"os"
    10  	"path/filepath"
    11  	"sort"
    12  	"syscall"
    13  
    14  	"github.com/juju/errors"
    15  	jc "github.com/juju/testing/checkers"
    16  	"github.com/juju/utils/set"
    17  	gc "gopkg.in/check.v1"
    18  
    19  	"github.com/juju/juju/mongo"
    20  	"github.com/juju/juju/state/backups"
    21  	"github.com/juju/juju/testing"
    22  )
    23  
    24  var _ = gc.Suite(&filesSuite{})
    25  
    26  type filesSuite struct {
    27  	testing.BaseSuite
    28  	root string
    29  }
    30  
    31  func (s *filesSuite) SetUpTest(c *gc.C) {
    32  	s.BaseSuite.SetUpTest(c)
    33  
    34  	s.root = c.MkDir()
    35  }
    36  
    37  // createFiles preps the fake FS. The files are all created relative to
    38  // the given root.
    39  func (s *filesSuite) createFiles(c *gc.C, paths backups.Paths, root, machineID string) {
    40  	mkdir := func(path string) string {
    41  		dirname := filepath.Join(root, path)
    42  		os.MkdirAll(dirname, 0777)
    43  		return dirname
    44  	}
    45  	touch := func(dirname, name string) {
    46  		path := filepath.Join(dirname, name)
    47  		file, err := os.Create(path)
    48  		c.Assert(err, jc.ErrorIsNil)
    49  		file.Close()
    50  	}
    51  
    52  	dirname := mkdir(paths.DataDir)
    53  	touch(dirname, "system-identity")
    54  	touch(dirname, "nonce.txt")
    55  	touch(dirname, "server.pem")
    56  	touch(dirname, "shared-secret")
    57  	mkdir(filepath.Join(paths.DataDir, "tools"))
    58  
    59  	dirname = mkdir(filepath.Join(paths.DataDir, "agents"))
    60  	touch(dirname, "machine-"+machineID+".conf")
    61  
    62  	dirname = mkdir("/home/ubuntu/.ssh")
    63  	touch(dirname, "authorized_keys")
    64  
    65  	dirname = mkdir(filepath.Join(paths.DataDir, "init", "juju-db"))
    66  	touch(dirname, "juju-db.service")
    67  }
    68  
    69  func (s *filesSuite) checkSameStrings(c *gc.C, actual, expected []string) {
    70  	sActual := set.NewStrings(actual...)
    71  	sExpected := set.NewStrings(expected...)
    72  
    73  	sActualOnly := sActual.Difference(sExpected)
    74  	sExpectedOnly := sExpected.Difference(sActual)
    75  
    76  	if !sActualOnly.IsEmpty() || !sExpectedOnly.IsEmpty() {
    77  		c.Error("strings mismatch")
    78  		onlyActual := sActualOnly.Values()
    79  		onlyExpected := sExpectedOnly.Values()
    80  		sort.Strings(onlyActual)
    81  		sort.Strings(onlyExpected)
    82  
    83  		if !sActualOnly.IsEmpty() {
    84  			c.Log("...unexpected values:")
    85  			for _, str := range onlyActual {
    86  				c.Log(" " + str)
    87  			}
    88  		}
    89  		if !sExpectedOnly.IsEmpty() {
    90  			c.Log("...missing values:")
    91  			for _, str := range onlyExpected {
    92  				c.Log(" " + str)
    93  			}
    94  		}
    95  	}
    96  }
    97  
    98  func (s *filesSuite) TestGetFilesToBackUpMachine0(c *gc.C) {
    99  	paths := backups.Paths{
   100  		DataDir: "/var/lib/juju",
   101  		LogsDir: "/var/log/juju",
   102  	}
   103  	s.createFiles(c, paths, s.root, "0")
   104  
   105  	files, err := backups.GetFilesToBackUp(s.root, &paths, "0")
   106  	c.Assert(err, jc.ErrorIsNil)
   107  
   108  	expected := []string{
   109  		filepath.Join(s.root, "/home/ubuntu/.ssh/authorized_keys"),
   110  		filepath.Join(s.root, "/var/lib/juju/agents/machine-0.conf"),
   111  		filepath.Join(s.root, "/var/lib/juju/nonce.txt"),
   112  		filepath.Join(s.root, "/var/lib/juju/server.pem"),
   113  		filepath.Join(s.root, "/var/lib/juju/shared-secret"),
   114  		filepath.Join(s.root, "/var/lib/juju/system-identity"),
   115  		filepath.Join(s.root, "/var/lib/juju/tools"),
   116  		filepath.Join(s.root, "/var/lib/juju/init/juju-db"),
   117  	}
   118  	c.Check(files, jc.SameContents, expected)
   119  	s.checkSameStrings(c, files, expected)
   120  }
   121  
   122  func (s *filesSuite) TestDirectoriesCleaned(c *gc.C) {
   123  	recreatableFolder := filepath.Join(s.root, "recreate_me")
   124  	os.MkdirAll(recreatableFolder, os.FileMode(0755))
   125  	recreatableFolderInfo, err := os.Stat(recreatableFolder)
   126  	c.Assert(err, jc.ErrorIsNil)
   127  
   128  	recreatableFolder1 := filepath.Join(recreatableFolder, "recreate_me_too")
   129  	os.MkdirAll(recreatableFolder1, os.FileMode(0755))
   130  	recreatableFolder1Info, err := os.Stat(recreatableFolder1)
   131  	c.Assert(err, jc.ErrorIsNil)
   132  
   133  	deletableFolder := filepath.Join(recreatableFolder, "dont_recreate_me")
   134  	os.MkdirAll(deletableFolder, os.FileMode(0755))
   135  
   136  	deletableFile := filepath.Join(recreatableFolder, "delete_me")
   137  	fh, err := os.Create(deletableFile)
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	defer fh.Close()
   140  
   141  	deletableFile1 := filepath.Join(recreatableFolder1, "delete_me.too")
   142  	fhr, err := os.Create(deletableFile1)
   143  	c.Assert(err, jc.ErrorIsNil)
   144  	defer fhr.Close()
   145  
   146  	s.PatchValue(backups.ReplaceableFolders, func(_ string, _ mongo.Version) (map[string]os.FileMode, error) {
   147  		replaceables := map[string]os.FileMode{}
   148  		for _, replaceable := range []string{
   149  			recreatableFolder,
   150  			recreatableFolder1,
   151  		} {
   152  			dirStat, err := os.Stat(replaceable)
   153  			if err != nil {
   154  				return map[string]os.FileMode{}, errors.Annotatef(err, "cannot stat %q", replaceable)
   155  			}
   156  			replaceables[replaceable] = dirStat.Mode()
   157  		}
   158  		return replaceables, nil
   159  	})
   160  
   161  	err = backups.PrepareMachineForRestore(mongo.Version{})
   162  	c.Assert(err, jc.ErrorIsNil)
   163  
   164  	_, err = os.Stat(deletableFolder)
   165  	c.Assert(err, gc.Not(gc.IsNil))
   166  	c.Assert(os.IsNotExist(err), gc.Equals, true)
   167  
   168  	recreatedFolderInfo, err := os.Stat(recreatableFolder)
   169  	c.Assert(err, jc.ErrorIsNil)
   170  	c.Assert(recreatableFolderInfo.Mode(), gc.Equals, recreatedFolderInfo.Mode())
   171  	c.Assert(recreatableFolderInfo.Sys().(*syscall.Stat_t).Ino, gc.Not(gc.Equals), recreatedFolderInfo.Sys().(*syscall.Stat_t).Ino)
   172  
   173  	recreatedFolder1Info, err := os.Stat(recreatableFolder1)
   174  	c.Assert(err, jc.ErrorIsNil)
   175  	c.Assert(recreatableFolder1Info.Mode(), gc.Equals, recreatedFolder1Info.Mode())
   176  	c.Assert(recreatableFolder1Info.Sys().(*syscall.Stat_t).Ino, gc.Not(gc.Equals), recreatedFolder1Info.Sys().(*syscall.Stat_t).Ino)
   177  }
   178  
   179  func (s *filesSuite) setupReplaceableFolders(c *gc.C) string {
   180  	dataDir := c.MkDir()
   181  	c.Assert(os.Mkdir(filepath.Join(dataDir, "init"), 0640), jc.ErrorIsNil)
   182  	c.Assert(os.Mkdir(filepath.Join(dataDir, "tools"), 0660), jc.ErrorIsNil)
   183  	c.Assert(os.Mkdir(filepath.Join(dataDir, "agents"), 0600), jc.ErrorIsNil)
   184  	c.Assert(os.Mkdir(filepath.Join(dataDir, "db"), 0600), jc.ErrorIsNil)
   185  	return dataDir
   186  }
   187  
   188  func (s *filesSuite) TestReplaceableFoldersMongo2(c *gc.C) {
   189  	dataDir := s.setupReplaceableFolders(c)
   190  
   191  	result, err := (*backups.ReplaceableFolders)(dataDir, mongo.Version{Major: 2, Minor: 4})
   192  	c.Assert(err, jc.ErrorIsNil)
   193  	c.Assert(result, jc.DeepEquals, map[string]os.FileMode{
   194  		filepath.Join(dataDir, "init"):   0640 | os.ModeDir,
   195  		filepath.Join(dataDir, "tools"):  0660 | os.ModeDir,
   196  		filepath.Join(dataDir, "agents"): 0600 | os.ModeDir,
   197  		filepath.Join(dataDir, "db"):     0600 | os.ModeDir,
   198  	})
   199  }
   200  
   201  func (s *filesSuite) TestReplaceableFoldersMongo3(c *gc.C) {
   202  	dataDir := s.setupReplaceableFolders(c)
   203  
   204  	result, err := (*backups.ReplaceableFolders)(dataDir, mongo.Version{Major: 3, Minor: 2})
   205  	c.Assert(err, jc.ErrorIsNil)
   206  	c.Assert(result, jc.DeepEquals, map[string]os.FileMode{
   207  		filepath.Join(dataDir, "init"):   0640 | os.ModeDir,
   208  		filepath.Join(dataDir, "tools"):  0660 | os.ModeDir,
   209  		filepath.Join(dataDir, "agents"): 0600 | os.ModeDir,
   210  	})
   211  }
   212  
   213  func (s *filesSuite) TestGetFilesToBackUpMachine10(c *gc.C) {
   214  	paths := backups.Paths{
   215  		DataDir: "/var/lib/juju",
   216  		LogsDir: "/var/log/juju",
   217  	}
   218  	s.createFiles(c, paths, s.root, "10")
   219  
   220  	files, err := backups.GetFilesToBackUp(s.root, &paths, "10")
   221  	c.Assert(err, jc.ErrorIsNil)
   222  
   223  	expected := []string{
   224  		filepath.Join(s.root, "/home/ubuntu/.ssh/authorized_keys"),
   225  		filepath.Join(s.root, "/var/lib/juju/agents/machine-10.conf"),
   226  		filepath.Join(s.root, "/var/lib/juju/nonce.txt"),
   227  		filepath.Join(s.root, "/var/lib/juju/server.pem"),
   228  		filepath.Join(s.root, "/var/lib/juju/shared-secret"),
   229  		filepath.Join(s.root, "/var/lib/juju/system-identity"),
   230  		filepath.Join(s.root, "/var/lib/juju/tools"),
   231  		filepath.Join(s.root, "/var/lib/juju/init/juju-db"),
   232  	}
   233  	c.Check(files, jc.SameContents, expected)
   234  	s.checkSameStrings(c, files, expected)
   235  }
   236  
   237  func (s *filesSuite) TestGetFilesToBackUpMissing(c *gc.C) {
   238  	paths := backups.Paths{
   239  		DataDir: "/var/lib/juju",
   240  		LogsDir: "/var/log/juju",
   241  	}
   242  	s.createFiles(c, paths, s.root, "0")
   243  
   244  	missing := []string{
   245  		"/var/lib/juju/nonce.txt",
   246  		"/home/ubuntu/.ssh/authorized_keys",
   247  	}
   248  	for _, filename := range missing {
   249  		err := os.Remove(filepath.Join(s.root, filename))
   250  		c.Assert(err, jc.ErrorIsNil)
   251  	}
   252  
   253  	files, err := backups.GetFilesToBackUp(s.root, &paths, "0")
   254  	c.Assert(err, jc.ErrorIsNil)
   255  
   256  	expected := []string{
   257  		filepath.Join(s.root, "/var/lib/juju/agents/machine-0.conf"),
   258  		filepath.Join(s.root, "/var/lib/juju/server.pem"),
   259  		filepath.Join(s.root, "/var/lib/juju/shared-secret"),
   260  		filepath.Join(s.root, "/var/lib/juju/system-identity"),
   261  		filepath.Join(s.root, "/var/lib/juju/tools"),
   262  		filepath.Join(s.root, "/var/lib/juju/init/juju-db"),
   263  	}
   264  	// This got re-created.
   265  	expected = append(expected, filepath.Join(s.root, "/home/ubuntu/.ssh/authorized_keys"))
   266  	c.Check(files, jc.SameContents, expected)
   267  	s.checkSameStrings(c, files, expected)
   268  }