github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/storage/provider/rootfs_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package provider_test 5 6 import ( 7 "errors" 8 "path/filepath" 9 "runtime" 10 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/storage" 16 "github.com/juju/juju/storage/provider" 17 "github.com/juju/juju/testing" 18 ) 19 20 var _ = gc.Suite(&rootfsSuite{}) 21 22 type rootfsSuite struct { 23 testing.BaseSuite 24 storageDir string 25 commands *mockRunCommand 26 mockDirFuncs *provider.MockDirFuncs 27 } 28 29 func (s *rootfsSuite) SetUpTest(c *gc.C) { 30 if runtime.GOOS == "windows" { 31 c.Skip("Tests relevant only on *nix systems") 32 } 33 s.BaseSuite.SetUpTest(c) 34 s.storageDir = c.MkDir() 35 } 36 37 func (s *rootfsSuite) TearDownTest(c *gc.C) { 38 if s.commands != nil { 39 s.commands.assertDrained() 40 } 41 s.BaseSuite.TearDownTest(c) 42 } 43 44 func (s *rootfsSuite) rootfsProvider(c *gc.C) storage.Provider { 45 s.commands = &mockRunCommand{c: c} 46 return provider.RootfsProvider(s.commands.run) 47 } 48 49 func (s *rootfsSuite) TestFilesystemSource(c *gc.C) { 50 p := s.rootfsProvider(c) 51 cfg, err := storage.NewConfig("name", provider.RootfsProviderType, map[string]interface{}{}) 52 c.Assert(err, jc.ErrorIsNil) 53 _, err = p.FilesystemSource(nil, cfg) 54 c.Assert(err, gc.ErrorMatches, "storage directory not specified") 55 cfg, err = storage.NewConfig("name", provider.RootfsProviderType, map[string]interface{}{ 56 "storage-dir": c.MkDir(), 57 }) 58 c.Assert(err, jc.ErrorIsNil) 59 _, err = p.FilesystemSource(nil, cfg) 60 c.Assert(err, jc.ErrorIsNil) 61 } 62 63 func (s *rootfsSuite) TestValidateConfig(c *gc.C) { 64 p := s.rootfsProvider(c) 65 cfg, err := storage.NewConfig("name", provider.RootfsProviderType, map[string]interface{}{}) 66 c.Assert(err, jc.ErrorIsNil) 67 err = p.ValidateConfig(cfg) 68 // The rootfs provider does not have any user 69 // configuration, so an empty map will pass. 70 c.Assert(err, jc.ErrorIsNil) 71 } 72 73 func (s *rootfsSuite) TestSupports(c *gc.C) { 74 p := s.rootfsProvider(c) 75 c.Assert(p.Supports(storage.StorageKindBlock), jc.IsFalse) 76 c.Assert(p.Supports(storage.StorageKindFilesystem), jc.IsTrue) 77 } 78 79 func (s *rootfsSuite) TestScope(c *gc.C) { 80 p := s.rootfsProvider(c) 81 c.Assert(p.Scope(), gc.Equals, storage.ScopeMachine) 82 } 83 84 func (s *rootfsSuite) rootfsFilesystemSource(c *gc.C) storage.FilesystemSource { 85 s.commands = &mockRunCommand{c: c} 86 source, d := provider.RootfsFilesystemSource(s.storageDir, s.commands.run) 87 s.mockDirFuncs = d 88 return source 89 } 90 91 func (s *rootfsSuite) TestCreateFilesystems(c *gc.C) { 92 source := s.rootfsFilesystemSource(c) 93 cmd := s.commands.expect("df", "--output=size", s.storageDir) 94 cmd.respond("1K-blocks\n2048", nil) 95 cmd = s.commands.expect("df", "--output=size", s.storageDir) 96 cmd.respond("1K-blocks\n4096", nil) 97 98 filesystems, err := source.CreateFilesystems([]storage.FilesystemParams{{ 99 Tag: names.NewFilesystemTag("6"), 100 Size: 2, 101 }, { 102 Tag: names.NewFilesystemTag("7"), 103 Size: 4, 104 }}) 105 c.Assert(err, jc.ErrorIsNil) 106 107 c.Assert(filesystems, jc.DeepEquals, []storage.Filesystem{{ 108 Tag: names.NewFilesystemTag("6"), 109 FilesystemInfo: storage.FilesystemInfo{ 110 FilesystemId: "6", 111 Size: 2, 112 }, 113 }, { 114 Tag: names.NewFilesystemTag("7"), 115 FilesystemInfo: storage.FilesystemInfo{ 116 FilesystemId: "7", 117 Size: 4, 118 }, 119 }}) 120 } 121 122 func (s *rootfsSuite) TestCreateFilesystemsIsUse(c *gc.C) { 123 source := s.rootfsFilesystemSource(c) 124 _, err := source.CreateFilesystems([]storage.FilesystemParams{{ 125 Tag: names.NewFilesystemTag("666"), // magic; see mockDirFuncs 126 Size: 1, 127 }}) 128 c.Assert(err, gc.ErrorMatches, "creating filesystem: \".*/666\" is not empty") 129 } 130 131 func (s *rootfsSuite) TestAttachFilesystemsPathNotDir(c *gc.C) { 132 source := s.rootfsFilesystemSource(c) 133 _, err := source.AttachFilesystems([]storage.FilesystemAttachmentParams{{ 134 Filesystem: names.NewFilesystemTag("6"), 135 FilesystemId: "6", 136 Path: "file", 137 }}) 138 c.Assert(err, gc.ErrorMatches, `.* path "file" must be a directory`) 139 } 140 141 func (s *rootfsSuite) TestCreateFilesystemsNotEnoughSpace(c *gc.C) { 142 source := s.rootfsFilesystemSource(c) 143 cmd := s.commands.expect("df", "--output=size", s.storageDir) 144 cmd.respond("1K-blocks\n2048", nil) 145 146 _, err := source.CreateFilesystems([]storage.FilesystemParams{{ 147 Tag: names.NewFilesystemTag("6"), 148 Size: 4, 149 }}) 150 c.Assert(err, gc.ErrorMatches, ".* filesystem is not big enough \\(2M < 4M\\)") 151 } 152 153 func (s *rootfsSuite) TestCreateFilesystemsInvalidPath(c *gc.C) { 154 source := s.rootfsFilesystemSource(c) 155 cmd := s.commands.expect("df", "--output=size", s.storageDir) 156 cmd.respond("", errors.New("error creating directory")) 157 158 _, err := source.CreateFilesystems([]storage.FilesystemParams{{ 159 Tag: names.NewFilesystemTag("6"), 160 Size: 2, 161 }}) 162 c.Assert(err, gc.ErrorMatches, ".* error creating directory") 163 } 164 165 func (s *rootfsSuite) TestAttachFilesystemsNoPathSpecified(c *gc.C) { 166 source := s.rootfsFilesystemSource(c) 167 _, err := source.AttachFilesystems([]storage.FilesystemAttachmentParams{{ 168 Filesystem: names.NewFilesystemTag("6"), 169 FilesystemId: "6", 170 }}) 171 c.Assert(err, gc.ErrorMatches, "attaching filesystem 6: filesystem mount point not specified") 172 } 173 174 func (s *rootfsSuite) TestAttachFilesystemsBind(c *gc.C) { 175 source := s.rootfsFilesystemSource(c) 176 177 cmd := s.commands.expect("df", "--output=source", "/srv") 178 cmd.respond("headers\n/src/of/root", nil) 179 180 cmd = s.commands.expect("mount", "--bind", filepath.Join(s.storageDir, "6"), "/srv") 181 cmd.respond("", nil) 182 183 info, err := source.AttachFilesystems([]storage.FilesystemAttachmentParams{{ 184 Filesystem: names.NewFilesystemTag("6"), 185 FilesystemId: "6", 186 Path: "/srv", 187 }}) 188 c.Assert(err, jc.ErrorIsNil) 189 c.Assert(info, jc.DeepEquals, []storage.FilesystemAttachment{{ 190 Filesystem: names.NewFilesystemTag("6"), 191 FilesystemAttachmentInfo: storage.FilesystemAttachmentInfo{ 192 Path: "/srv", 193 }, 194 }}) 195 } 196 197 func (s *rootfsSuite) TestAttachFilesystemsBound(c *gc.C) { 198 source := s.rootfsFilesystemSource(c) 199 200 // already bind-mounted storage-dir/6 to the target 201 cmd := s.commands.expect("df", "--output=source", "/srv") 202 cmd.respond("headers\n"+filepath.Join(s.storageDir, "6"), nil) 203 204 info, err := source.AttachFilesystems([]storage.FilesystemAttachmentParams{{ 205 Filesystem: names.NewFilesystemTag("6"), 206 FilesystemId: "6", 207 Path: "/srv", 208 }}) 209 c.Assert(err, jc.ErrorIsNil) 210 c.Assert(info, jc.DeepEquals, []storage.FilesystemAttachment{{ 211 Filesystem: names.NewFilesystemTag("6"), 212 FilesystemAttachmentInfo: storage.FilesystemAttachmentInfo{ 213 Path: "/srv", 214 }, 215 }}) 216 } 217 218 func (s *rootfsSuite) TestAttachFilesystemsBindFailsDifferentFS(c *gc.C) { 219 source := s.rootfsFilesystemSource(c) 220 221 cmd := s.commands.expect("df", "--output=source", "/srv") 222 cmd.respond("headers\n/src/of/root", nil) 223 224 cmd = s.commands.expect("mount", "--bind", filepath.Join(s.storageDir, "6"), "/srv") 225 cmd.respond("", errors.New("mount --bind fails")) 226 227 cmd = s.commands.expect("df", "--output=target", filepath.Join(s.storageDir, "6")) 228 cmd.respond("headers\n/dev", nil) 229 230 cmd = s.commands.expect("df", "--output=target", "/srv") 231 cmd.respond("headers\n/proc", nil) 232 233 _, err := source.AttachFilesystems([]storage.FilesystemAttachmentParams{{ 234 Filesystem: names.NewFilesystemTag("6"), 235 FilesystemId: "6", 236 Path: "/srv", 237 }}) 238 c.Assert(err, gc.ErrorMatches, `attaching filesystem 6: ".*/6" \("/dev"\) and "/srv" \("/proc"\) are on different filesystems`) 239 } 240 241 func (s *rootfsSuite) TestAttachFilesystemsBindSameFSEmptyDir(c *gc.C) { 242 source := s.rootfsFilesystemSource(c) 243 244 cmd := s.commands.expect("df", "--output=source", "/srv") 245 cmd.respond("headers\n/src/of/root", nil) 246 247 cmd = s.commands.expect("mount", "--bind", filepath.Join(s.storageDir, "6"), "/srv") 248 cmd.respond("", errors.New("mount --bind fails")) 249 250 cmd = s.commands.expect("df", "--output=target", filepath.Join(s.storageDir, "6")) 251 cmd.respond("headers\n/dev", nil) 252 253 cmd = s.commands.expect("df", "--output=target", "/srv") 254 cmd.respond("headers\n/dev", nil) 255 256 info, err := source.AttachFilesystems([]storage.FilesystemAttachmentParams{{ 257 Filesystem: names.NewFilesystemTag("6"), 258 FilesystemId: "6", 259 Path: "/srv", 260 }}) 261 c.Assert(err, jc.ErrorIsNil) 262 c.Assert(info, jc.DeepEquals, []storage.FilesystemAttachment{{ 263 Filesystem: names.NewFilesystemTag("6"), 264 FilesystemAttachmentInfo: storage.FilesystemAttachmentInfo{ 265 Path: "/srv", 266 }, 267 }}) 268 } 269 270 func (s *rootfsSuite) TestAttachFilesystemsBindSameFSNonEmptyDirUnclaimed(c *gc.C) { 271 source := s.rootfsFilesystemSource(c) 272 273 cmd := s.commands.expect("df", "--output=source", "/srv/666") 274 cmd.respond("headers\n/src/of/root", nil) 275 276 cmd = s.commands.expect("mount", "--bind", filepath.Join(s.storageDir, "6"), "/srv/666") 277 cmd.respond("", errors.New("mount --bind fails")) 278 279 cmd = s.commands.expect("df", "--output=target", filepath.Join(s.storageDir, "6")) 280 cmd.respond("headers\n/dev", nil) 281 282 cmd = s.commands.expect("df", "--output=target", "/srv/666") 283 cmd.respond("headers\n/dev", nil) 284 285 _, err := source.AttachFilesystems([]storage.FilesystemAttachmentParams{{ 286 Filesystem: names.NewFilesystemTag("6"), 287 FilesystemId: "6", 288 Path: "/srv/666", 289 }}) 290 c.Assert(err, gc.ErrorMatches, `attaching filesystem 6: "/srv/666" is not empty`) 291 } 292 293 func (s *rootfsSuite) TestAttachFilesystemsBindSameFSNonEmptyDirClaimed(c *gc.C) { 294 source := s.rootfsFilesystemSource(c) 295 296 cmd := s.commands.expect("df", "--output=source", "/srv/666") 297 cmd.respond("headers\n/src/of/root", nil) 298 299 cmd = s.commands.expect("mount", "--bind", filepath.Join(s.storageDir, "6"), "/srv/666") 300 cmd.respond("", errors.New("mount --bind fails")) 301 302 cmd = s.commands.expect("df", "--output=target", filepath.Join(s.storageDir, "6")) 303 cmd.respond("headers\n/dev", nil) 304 305 cmd = s.commands.expect("df", "--output=target", "/srv/666") 306 cmd.respond("headers\n/dev", nil) 307 308 s.mockDirFuncs.Dirs.Add(filepath.Join(s.storageDir, "6", "juju-target-claimed")) 309 310 info, err := source.AttachFilesystems([]storage.FilesystemAttachmentParams{{ 311 Filesystem: names.NewFilesystemTag("6"), 312 FilesystemId: "6", 313 Path: "/srv/666", 314 }}) 315 c.Assert(err, jc.ErrorIsNil) 316 c.Assert(info, jc.DeepEquals, []storage.FilesystemAttachment{{ 317 Filesystem: names.NewFilesystemTag("6"), 318 FilesystemAttachmentInfo: storage.FilesystemAttachmentInfo{ 319 Path: "/srv/666", 320 }, 321 }}) 322 } 323 324 func (s *rootfsSuite) TestDetachFilesystems(c *gc.C) { 325 source := s.rootfsFilesystemSource(c) 326 testDetachFilesystems(c, s.commands, source, true) 327 } 328 329 func (s *rootfsSuite) TestDetachFilesystemsUnattached(c *gc.C) { 330 // The "unattached" case covers both idempotency, and 331 // also the scenario where bind-mounting failed. In 332 // either case, there is no attachment-specific filesystem 333 // mount. 334 source := s.rootfsFilesystemSource(c) 335 testDetachFilesystems(c, s.commands, source, false) 336 }