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 }