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  }