github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/storage/provider/tmpfs_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 "runtime" 9 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/names.v2" 13 14 "github.com/juju/juju/environs/context" 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(&tmpfsSuite{}) 21 22 type tmpfsSuite struct { 23 testing.BaseSuite 24 storageDir string 25 commands *mockRunCommand 26 fakeEtcDir string 27 28 callCtx context.ProviderCallContext 29 } 30 31 func (s *tmpfsSuite) SetUpTest(c *gc.C) { 32 if runtime.GOOS == "windows" { 33 c.Skip("Tests relevant only on *nix systems") 34 } 35 s.BaseSuite.SetUpTest(c) 36 s.storageDir = c.MkDir() 37 s.fakeEtcDir = c.MkDir() 38 s.callCtx = context.NewCloudCallContext() 39 } 40 41 func (s *tmpfsSuite) TearDownTest(c *gc.C) { 42 if s.commands != nil { 43 s.commands.assertDrained() 44 } 45 s.BaseSuite.TearDownTest(c) 46 } 47 48 func (s *tmpfsSuite) tmpfsProvider(c *gc.C) storage.Provider { 49 s.commands = &mockRunCommand{c: c} 50 return provider.TmpfsProvider(s.commands.run) 51 } 52 53 func (s *tmpfsSuite) TestFilesystemSource(c *gc.C) { 54 p := s.tmpfsProvider(c) 55 cfg, err := storage.NewConfig("name", provider.TmpfsProviderType, map[string]interface{}{}) 56 c.Assert(err, jc.ErrorIsNil) 57 _, err = p.FilesystemSource(cfg) 58 c.Assert(err, gc.ErrorMatches, "storage directory not specified") 59 cfg, err = storage.NewConfig("name", provider.TmpfsProviderType, map[string]interface{}{ 60 "storage-dir": c.MkDir(), 61 }) 62 c.Assert(err, jc.ErrorIsNil) 63 _, err = p.FilesystemSource(cfg) 64 c.Assert(err, jc.ErrorIsNil) 65 } 66 67 func (s *tmpfsSuite) TestValidateConfig(c *gc.C) { 68 p := s.tmpfsProvider(c) 69 cfg, err := storage.NewConfig("name", provider.TmpfsProviderType, map[string]interface{}{}) 70 c.Assert(err, jc.ErrorIsNil) 71 err = p.ValidateConfig(cfg) 72 // The tmpfs provider does not have any user 73 // configuration, so an empty map will pass. 74 c.Assert(err, jc.ErrorIsNil) 75 } 76 77 func (s *tmpfsSuite) TestSupports(c *gc.C) { 78 p := s.tmpfsProvider(c) 79 c.Assert(p.Supports(storage.StorageKindBlock), jc.IsFalse) 80 c.Assert(p.Supports(storage.StorageKindFilesystem), jc.IsTrue) 81 } 82 83 func (s *tmpfsSuite) TestScope(c *gc.C) { 84 p := s.tmpfsProvider(c) 85 c.Assert(p.Scope(), gc.Equals, storage.ScopeMachine) 86 } 87 88 func (s *tmpfsSuite) tmpfsFilesystemSource(c *gc.C) storage.FilesystemSource { 89 s.commands = &mockRunCommand{c: c} 90 return provider.TmpfsFilesystemSource( 91 s.fakeEtcDir, 92 s.storageDir, 93 s.commands.run, 94 ) 95 } 96 97 func (s *tmpfsSuite) TestCreateFilesystems(c *gc.C) { 98 source := s.tmpfsFilesystemSource(c) 99 100 results, err := source.CreateFilesystems(s.callCtx, []storage.FilesystemParams{{ 101 Tag: names.NewFilesystemTag("6"), 102 Size: 2, 103 }}) 104 c.Assert(err, jc.ErrorIsNil) 105 c.Assert(results, jc.DeepEquals, []storage.CreateFilesystemsResult{{ 106 Filesystem: &storage.Filesystem{ 107 Tag: names.NewFilesystemTag("6"), 108 FilesystemInfo: storage.FilesystemInfo{ 109 FilesystemId: "filesystem-6", 110 Size: 2, 111 }, 112 }, 113 }}) 114 } 115 116 func (s *tmpfsSuite) TestCreateFilesystemsHugePages(c *gc.C) { 117 source := s.tmpfsFilesystemSource(c) 118 119 // Set page size to 16MiB. 120 s.PatchValue(provider.Getpagesize, func() int { return 16 * 1024 * 1024 }) 121 122 results, err := source.CreateFilesystems(s.callCtx, []storage.FilesystemParams{{ 123 Tag: names.NewFilesystemTag("1"), 124 Size: 17, 125 }, { 126 Tag: names.NewFilesystemTag("2"), 127 Size: 16, 128 }}) 129 c.Assert(err, jc.ErrorIsNil) 130 c.Assert(results, jc.DeepEquals, []storage.CreateFilesystemsResult{{ 131 Filesystem: &storage.Filesystem{ 132 Tag: names.NewFilesystemTag("1"), 133 FilesystemInfo: storage.FilesystemInfo{ 134 FilesystemId: "filesystem-1", 135 Size: 32, 136 }, 137 }, 138 }, { 139 Filesystem: &storage.Filesystem{ 140 Tag: names.NewFilesystemTag("2"), 141 FilesystemInfo: storage.FilesystemInfo{ 142 FilesystemId: "filesystem-2", 143 Size: 16, 144 }, 145 }, 146 }}) 147 } 148 149 func (s *tmpfsSuite) TestCreateFilesystemsIsUse(c *gc.C) { 150 source := s.tmpfsFilesystemSource(c) 151 results, err := source.CreateFilesystems(s.callCtx, []storage.FilesystemParams{{ 152 Tag: names.NewFilesystemTag("1"), 153 Size: 1, 154 }, { 155 Tag: names.NewFilesystemTag("1"), 156 Size: 2, 157 }}) 158 c.Assert(err, jc.ErrorIsNil) 159 c.Assert(results, gc.HasLen, 2) 160 c.Assert(results[0].Error, jc.ErrorIsNil) 161 c.Assert(results[1].Error, gc.ErrorMatches, "filesystem 1 already exists") 162 } 163 164 func (s *tmpfsSuite) TestAttachFilesystemsPathNotDir(c *gc.C) { 165 source := s.tmpfsFilesystemSource(c) 166 _, err := source.CreateFilesystems(s.callCtx, []storage.FilesystemParams{{ 167 Tag: names.NewFilesystemTag("1"), 168 Size: 1, 169 }}) 170 c.Assert(err, jc.ErrorIsNil) 171 results, err := source.AttachFilesystems(s.callCtx, []storage.FilesystemAttachmentParams{{ 172 Filesystem: names.NewFilesystemTag("1"), 173 Path: "file", 174 }}) 175 c.Assert(err, jc.ErrorIsNil) 176 c.Assert(results[0].Error, gc.ErrorMatches, `path "file" must be a directory`) 177 } 178 179 func (s *tmpfsSuite) TestAttachFilesystemsAlreadyMounted(c *gc.C) { 180 source := s.tmpfsFilesystemSource(c) 181 cmd := s.commands.expect("df", "--output=source", "exists") 182 cmd.respond("header\nfilesystem-123", nil) 183 _, err := source.CreateFilesystems(s.callCtx, []storage.FilesystemParams{{ 184 Tag: names.NewFilesystemTag("123"), 185 Size: 1, 186 }}) 187 c.Assert(err, jc.ErrorIsNil) 188 results, err := source.AttachFilesystems(s.callCtx, []storage.FilesystemAttachmentParams{{ 189 Filesystem: names.NewFilesystemTag("123"), 190 Path: "exists", 191 }}) 192 c.Assert(results, jc.DeepEquals, []storage.AttachFilesystemsResult{{ 193 FilesystemAttachment: &storage.FilesystemAttachment{ 194 Filesystem: names.NewFilesystemTag("123"), 195 FilesystemAttachmentInfo: storage.FilesystemAttachmentInfo{ 196 Path: "exists", 197 }, 198 }, 199 }}) 200 } 201 202 func (s *tmpfsSuite) TestAttachFilesystemsMountReadOnly(c *gc.C) { 203 source := s.tmpfsFilesystemSource(c) 204 _, err := source.CreateFilesystems(s.callCtx, []storage.FilesystemParams{{ 205 Tag: names.NewFilesystemTag("1"), 206 Size: 1024, 207 }}) 208 c.Assert(err, jc.ErrorIsNil) 209 210 cmd := s.commands.expect("df", "--output=source", "/var/lib/juju/storage/fs/foo") 211 cmd.respond("header\nvalue", nil) 212 s.commands.expect("mount", "-t", "tmpfs", "filesystem-1", "/var/lib/juju/storage/fs/foo", "-o", "size=1024m,ro") 213 214 results, err := source.AttachFilesystems(s.callCtx, []storage.FilesystemAttachmentParams{{ 215 Filesystem: names.NewFilesystemTag("1"), 216 Path: "/var/lib/juju/storage/fs/foo", 217 AttachmentParams: storage.AttachmentParams{ 218 Machine: names.NewMachineTag("2"), 219 ReadOnly: true, 220 }, 221 }}) 222 c.Assert(err, jc.ErrorIsNil) 223 c.Assert(results, jc.DeepEquals, []storage.AttachFilesystemsResult{{ 224 FilesystemAttachment: &storage.FilesystemAttachment{ 225 Filesystem: names.NewFilesystemTag("1"), 226 Machine: names.NewMachineTag("2"), 227 FilesystemAttachmentInfo: storage.FilesystemAttachmentInfo{ 228 Path: "/var/lib/juju/storage/fs/foo", 229 ReadOnly: true, 230 }, 231 }, 232 }}) 233 } 234 235 func (s *tmpfsSuite) TestAttachFilesystemsMountFails(c *gc.C) { 236 source := s.tmpfsFilesystemSource(c) 237 _, err := source.CreateFilesystems(s.callCtx, []storage.FilesystemParams{{ 238 Tag: names.NewFilesystemTag("1"), 239 Size: 1024, 240 }}) 241 c.Assert(err, jc.ErrorIsNil) 242 243 cmd := s.commands.expect("df", "--output=source", "/var/lib/juju/storage/fs/foo") 244 cmd.respond("header\nvalue", nil) 245 cmd = s.commands.expect("mount", "-t", "tmpfs", "filesystem-1", "/var/lib/juju/storage/fs/foo", "-o", "size=1024m") 246 cmd.respond("", errors.New("mount failed")) 247 248 results, err := source.AttachFilesystems(s.callCtx, []storage.FilesystemAttachmentParams{{ 249 Filesystem: names.NewFilesystemTag("1"), 250 Path: "/var/lib/juju/storage/fs/foo", 251 }}) 252 c.Assert(err, jc.ErrorIsNil) 253 c.Assert(results[0].Error, gc.ErrorMatches, "cannot mount tmpfs: mount failed") 254 } 255 256 func (s *tmpfsSuite) TestAttachFilesystemsNoPathSpecified(c *gc.C) { 257 source := s.tmpfsFilesystemSource(c) 258 _, err := source.CreateFilesystems(s.callCtx, []storage.FilesystemParams{{ 259 Tag: names.NewFilesystemTag("1"), 260 Size: 1024, 261 }}) 262 c.Assert(err, jc.ErrorIsNil) 263 results, err := source.AttachFilesystems(s.callCtx, []storage.FilesystemAttachmentParams{{ 264 Filesystem: names.NewFilesystemTag("6"), 265 }}) 266 c.Assert(err, jc.ErrorIsNil) 267 c.Assert(results[0].Error, gc.ErrorMatches, "filesystem mount point not specified") 268 } 269 270 func (s *tmpfsSuite) TestAttachFilesystemsNoFilesystem(c *gc.C) { 271 source := s.tmpfsFilesystemSource(c) 272 results, err := source.AttachFilesystems(s.callCtx, []storage.FilesystemAttachmentParams{{ 273 Filesystem: names.NewFilesystemTag("6"), 274 Path: "/mnt", 275 }}) 276 c.Assert(err, jc.ErrorIsNil) 277 c.Assert(results[0].Error, gc.ErrorMatches, "reading filesystem info from disk: open .*/6.info: no such file or directory") 278 } 279 280 func (s *tmpfsSuite) TestDetachFilesystems(c *gc.C) { 281 source := s.tmpfsFilesystemSource(c) 282 testDetachFilesystems(c, s.commands, source, s.callCtx, true, s.fakeEtcDir, "") 283 } 284 285 func (s *tmpfsSuite) TestDetachFilesystemsUnattached(c *gc.C) { 286 source := s.tmpfsFilesystemSource(c) 287 testDetachFilesystems(c, s.commands, source, s.callCtx, false, s.fakeEtcDir, "") 288 }