github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/storage/storage_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storage_test
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  	"gopkg.in/juju/names.v2"
    14  
    15  	"github.com/juju/juju/apiserver/params"
    16  	"github.com/juju/juju/core/status"
    17  	"github.com/juju/juju/environs/context"
    18  	"github.com/juju/juju/state"
    19  	"github.com/juju/juju/storage"
    20  	"github.com/juju/juju/storage/provider/dummy"
    21  	coretesting "github.com/juju/juju/testing"
    22  )
    23  
    24  type storageSuite struct {
    25  	baseStorageSuite
    26  }
    27  
    28  var _ = gc.Suite(&storageSuite{})
    29  
    30  func (s *storageSuite) TestStorageListEmpty(c *gc.C) {
    31  	s.storageAccessor.allStorageInstances = func() ([]state.StorageInstance, error) {
    32  		s.stub.AddCall(allStorageInstancesCall)
    33  		return []state.StorageInstance{}, nil
    34  	}
    35  
    36  	found, err := s.api.ListStorageDetails(
    37  		params.StorageFilters{[]params.StorageFilter{{}}},
    38  	)
    39  	c.Assert(err, jc.ErrorIsNil)
    40  	c.Assert(found.Results, gc.HasLen, 1)
    41  	c.Assert(found.Results[0].Error, gc.IsNil)
    42  	c.Assert(found.Results[0].Result, gc.HasLen, 0)
    43  	s.assertCalls(c, []string{allStorageInstancesCall})
    44  }
    45  
    46  func (s *storageSuite) TestStorageListFilesystem(c *gc.C) {
    47  	found, err := s.api.ListStorageDetails(
    48  		params.StorageFilters{[]params.StorageFilter{{}}},
    49  	)
    50  	c.Assert(err, jc.ErrorIsNil)
    51  
    52  	expectedCalls := []string{
    53  		allStorageInstancesCall,
    54  		storageInstanceFilesystemCall,
    55  		storageInstanceAttachmentsCall,
    56  		storageInstanceCall,
    57  		storageInstanceFilesystemCall,
    58  		storageInstanceFilesystemAttachmentCall,
    59  	}
    60  	s.assertCalls(c, expectedCalls)
    61  
    62  	c.Assert(found.Results, gc.HasLen, 1)
    63  	c.Assert(found.Results[0].Error, gc.IsNil)
    64  	c.Assert(found.Results[0].Result, gc.HasLen, 1)
    65  	wantedDetails := s.createTestStorageDetails()
    66  	c.Assert(found.Results[0].Result[0], jc.DeepEquals, wantedDetails)
    67  }
    68  
    69  func (s *storageSuite) TestStorageListVolume(c *gc.C) {
    70  	s.storageInstance.kind = state.StorageKindBlock
    71  	found, err := s.api.ListStorageDetails(
    72  		params.StorageFilters{[]params.StorageFilter{{}}},
    73  	)
    74  	c.Assert(err, jc.ErrorIsNil)
    75  
    76  	expectedCalls := []string{
    77  		allStorageInstancesCall,
    78  		storageInstanceVolumeCall,
    79  		storageInstanceAttachmentsCall,
    80  		storageInstanceCall,
    81  		storageInstanceVolumeCall,
    82  	}
    83  	s.assertCalls(c, expectedCalls)
    84  
    85  	c.Assert(found.Results, gc.HasLen, 1)
    86  	c.Assert(found.Results[0].Error, gc.IsNil)
    87  	c.Assert(found.Results[0].Result, gc.HasLen, 1)
    88  	wantedDetails := s.createTestStorageDetails()
    89  	wantedDetails.Kind = params.StorageKindBlock
    90  	wantedDetails.Status.Status = status.Attached
    91  	c.Assert(found.Results[0].Result[0], jc.DeepEquals, wantedDetails)
    92  }
    93  
    94  func (s *storageSuite) TestStorageListError(c *gc.C) {
    95  	msg := "list test error"
    96  	s.storageAccessor.allStorageInstances = func() ([]state.StorageInstance, error) {
    97  		s.stub.AddCall(allStorageInstancesCall)
    98  		return []state.StorageInstance{}, errors.Errorf(msg)
    99  	}
   100  
   101  	found, err := s.api.ListStorageDetails(
   102  		params.StorageFilters{[]params.StorageFilter{{}}},
   103  	)
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	c.Assert(found.Results, gc.HasLen, 1)
   106  	c.Assert(found.Results[0].Error, gc.ErrorMatches, msg)
   107  
   108  	expectedCalls := []string{allStorageInstancesCall}
   109  	s.assertCalls(c, expectedCalls)
   110  }
   111  
   112  func (s *storageSuite) TestStorageListInstanceError(c *gc.C) {
   113  	msg := "list test error"
   114  	s.storageAccessor.storageInstance = func(sTag names.StorageTag) (state.StorageInstance, error) {
   115  		s.stub.AddCall(storageInstanceCall)
   116  		c.Assert(sTag, jc.DeepEquals, s.storageTag)
   117  		return nil, errors.Errorf(msg)
   118  	}
   119  
   120  	found, err := s.api.ListStorageDetails(
   121  		params.StorageFilters{[]params.StorageFilter{{}}},
   122  	)
   123  	c.Assert(err, jc.ErrorIsNil)
   124  
   125  	expectedCalls := []string{
   126  		allStorageInstancesCall,
   127  		storageInstanceFilesystemCall,
   128  		storageInstanceAttachmentsCall,
   129  		storageInstanceCall,
   130  	}
   131  	s.assertCalls(c, expectedCalls)
   132  	c.Assert(found.Results, gc.HasLen, 1)
   133  	c.Assert(found.Results[0].Error, gc.ErrorMatches,
   134  		fmt.Sprintf("getting details for storage data/0: getting storage instance: %v", msg),
   135  	)
   136  }
   137  
   138  func (s *storageSuite) TestStorageListAttachmentError(c *gc.C) {
   139  	s.storageAccessor.storageInstanceAttachments = func(tag names.StorageTag) ([]state.StorageAttachment, error) {
   140  		s.stub.AddCall(storageInstanceAttachmentsCall)
   141  		c.Assert(tag, jc.DeepEquals, s.storageTag)
   142  		return []state.StorageAttachment{}, errors.Errorf("list test error")
   143  	}
   144  
   145  	found, err := s.api.ListStorageDetails(
   146  		params.StorageFilters{[]params.StorageFilter{{}}},
   147  	)
   148  	c.Assert(err, jc.ErrorIsNil)
   149  
   150  	expectedCalls := []string{
   151  		allStorageInstancesCall,
   152  		storageInstanceFilesystemCall,
   153  		storageInstanceAttachmentsCall,
   154  	}
   155  	s.assertCalls(c, expectedCalls)
   156  	c.Assert(found.Results, gc.HasLen, 1)
   157  	c.Assert(found.Results[0].Error, gc.ErrorMatches,
   158  		"getting details for storage data/0: list test error")
   159  }
   160  
   161  func (s *storageSuite) TestStorageListMachineError(c *gc.C) {
   162  	msg := "list test error"
   163  	s.state.unitErr = msg
   164  	found, err := s.api.ListStorageDetails(
   165  		params.StorageFilters{[]params.StorageFilter{{}}},
   166  	)
   167  	c.Assert(err, jc.ErrorIsNil)
   168  
   169  	expectedCalls := []string{
   170  		allStorageInstancesCall,
   171  		storageInstanceFilesystemCall,
   172  		storageInstanceAttachmentsCall,
   173  	}
   174  	s.assertCalls(c, expectedCalls)
   175  	c.Assert(found.Results, gc.HasLen, 1)
   176  	c.Assert(found.Results[0].Error, gc.ErrorMatches,
   177  		fmt.Sprintf("getting details for storage data/0: %v", msg),
   178  	)
   179  }
   180  
   181  func (s *storageSuite) TestStorageListFilesystemError(c *gc.C) {
   182  	msg := "list test error"
   183  	s.storageAccessor.storageInstanceFilesystem = func(sTag names.StorageTag) (state.Filesystem, error) {
   184  		s.stub.AddCall(storageInstanceFilesystemCall)
   185  		c.Assert(sTag, jc.DeepEquals, s.storageTag)
   186  		return nil, errors.Errorf(msg)
   187  	}
   188  
   189  	found, err := s.api.ListStorageDetails(
   190  		params.StorageFilters{[]params.StorageFilter{{}}},
   191  	)
   192  	c.Assert(err, jc.ErrorIsNil)
   193  
   194  	expectedCalls := []string{
   195  		allStorageInstancesCall,
   196  		storageInstanceFilesystemCall,
   197  	}
   198  	s.assertCalls(c, expectedCalls)
   199  	c.Assert(found.Results, gc.HasLen, 1)
   200  	c.Assert(found.Results[0].Error, gc.ErrorMatches,
   201  		fmt.Sprintf("getting details for storage data/0: %v", msg),
   202  	)
   203  }
   204  
   205  func (s *storageSuite) TestStorageListFilesystemAttachmentError(c *gc.C) {
   206  	msg := "list test error"
   207  	s.state.unitErr = msg
   208  
   209  	found, err := s.api.ListStorageDetails(
   210  		params.StorageFilters{[]params.StorageFilter{{}}},
   211  	)
   212  	c.Assert(err, jc.ErrorIsNil)
   213  
   214  	expectedCalls := []string{
   215  		allStorageInstancesCall,
   216  		storageInstanceFilesystemCall,
   217  		storageInstanceAttachmentsCall,
   218  	}
   219  	s.assertCalls(c, expectedCalls)
   220  	c.Assert(found.Results, gc.HasLen, 1)
   221  	c.Assert(found.Results[0].Error, gc.ErrorMatches,
   222  		fmt.Sprintf("getting details for storage data/0: %v", msg),
   223  	)
   224  }
   225  
   226  func (s *storageSuite) createTestStorageDetails() params.StorageDetails {
   227  	return params.StorageDetails{
   228  		StorageTag: s.storageTag.String(),
   229  		OwnerTag:   s.unitTag.String(),
   230  		Kind:       params.StorageKindFilesystem,
   231  		Life:       "dying",
   232  		Status: params.EntityStatus{
   233  			Status: "attached",
   234  		},
   235  		Attachments: map[string]params.StorageAttachmentDetails{
   236  			s.unitTag.String(): {
   237  				s.storageTag.String(),
   238  				s.unitTag.String(),
   239  				s.machineTag.String(),
   240  				"", // location
   241  				"alive",
   242  			},
   243  		},
   244  	}
   245  }
   246  
   247  func (s *storageSuite) assertInstanceInfoError(c *gc.C, obtained params.StorageDetailsResult, wanted params.StorageDetailsResult, expected string) {
   248  	if expected != "" {
   249  		c.Assert(errors.Cause(obtained.Error), gc.ErrorMatches, fmt.Sprintf(".*%v.*", expected))
   250  		c.Assert(obtained.Result, gc.IsNil)
   251  	} else {
   252  		c.Assert(obtained.Error, gc.IsNil)
   253  		c.Assert(obtained, jc.DeepEquals, wanted)
   254  	}
   255  }
   256  
   257  func (s *storageSuite) TestShowStorageEmpty(c *gc.C) {
   258  	found, err := s.api.StorageDetails(params.Entities{})
   259  	c.Assert(err, jc.ErrorIsNil)
   260  	c.Assert(found.Results, gc.HasLen, 0)
   261  }
   262  
   263  func (s *storageSuite) TestShowStorageInvalidTag(c *gc.C) {
   264  	// Only storage tags are permitted
   265  	found, err := s.api.StorageDetails(params.Entities{
   266  		Entities: []params.Entity{{Tag: "machine-1"}},
   267  	})
   268  	c.Assert(err, jc.ErrorIsNil)
   269  	c.Assert(found.Results, gc.HasLen, 1)
   270  	c.Assert(found.Results[0].Error, gc.ErrorMatches, `"machine-1" is not a valid storage tag`)
   271  }
   272  
   273  func (s *storageSuite) TestShowStorage(c *gc.C) {
   274  	entity := params.Entity{Tag: s.storageTag.String()}
   275  
   276  	found, err := s.api.StorageDetails(
   277  		params.Entities{Entities: []params.Entity{entity}},
   278  	)
   279  	c.Assert(err, jc.ErrorIsNil)
   280  	c.Assert(found.Results, gc.HasLen, 1)
   281  
   282  	one := found.Results[0]
   283  	c.Assert(one.Error, gc.IsNil)
   284  
   285  	expected := params.StorageDetails{
   286  		StorageTag: s.storageTag.String(),
   287  		OwnerTag:   s.unitTag.String(),
   288  		Kind:       params.StorageKindFilesystem,
   289  		Life:       "dying",
   290  		Status: params.EntityStatus{
   291  			Status: "attached",
   292  		},
   293  		Attachments: map[string]params.StorageAttachmentDetails{
   294  			s.unitTag.String(): {
   295  				s.storageTag.String(),
   296  				s.unitTag.String(),
   297  				s.machineTag.String(),
   298  				"",
   299  				"alive",
   300  			},
   301  		},
   302  	}
   303  	c.Assert(one.Result, jc.DeepEquals, &expected)
   304  }
   305  
   306  func (s *storageSuite) TestShowStorageInvalidId(c *gc.C) {
   307  	storageTag := "foo"
   308  	entity := params.Entity{Tag: storageTag}
   309  
   310  	found, err := s.api.StorageDetails(params.Entities{Entities: []params.Entity{entity}})
   311  	c.Assert(err, jc.ErrorIsNil)
   312  	c.Assert(found.Results, gc.HasLen, 1)
   313  	s.assertInstanceInfoError(c, found.Results[0], params.StorageDetailsResult{}, `"foo" is not a valid tag`)
   314  }
   315  
   316  func (s *storageSuite) TestRemove(c *gc.C) {
   317  	results, err := s.api.Remove(params.RemoveStorage{[]params.RemoveStorageInstance{
   318  		{Tag: "storage-foo-0", DestroyStorage: true},
   319  		{Tag: "storage-foo-1", DestroyAttachments: true, DestroyStorage: true},
   320  		{Tag: "storage-foo-1", DestroyAttachments: true, DestroyStorage: false},
   321  		{Tag: "volume-0"},
   322  		{Tag: "filesystem-1-2"},
   323  		{Tag: "machine-0"},
   324  	}})
   325  	c.Assert(err, jc.ErrorIsNil)
   326  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{
   327  		{Error: &params.Error{Message: "cannae do it"}},
   328  		{Error: &params.Error{Message: "cannae do it"}},
   329  		{Error: &params.Error{Message: "cannae do it"}},
   330  		{Error: &params.Error{Message: `"volume-0" is not a valid storage tag`}},
   331  		{Error: &params.Error{Message: `"filesystem-1-2" is not a valid storage tag`}},
   332  		{Error: &params.Error{Message: `"machine-0" is not a valid storage tag`}},
   333  	})
   334  	s.stub.CheckCallNames(c,
   335  		getBlockForTypeCall, // Remove
   336  		getBlockForTypeCall, // Change
   337  		destroyStorageInstanceCall,
   338  		destroyStorageInstanceCall,
   339  		releaseStorageInstanceCall,
   340  	)
   341  	s.stub.CheckCall(c, 2, destroyStorageInstanceCall, names.NewStorageTag("foo/0"), false)
   342  	s.stub.CheckCall(c, 3, destroyStorageInstanceCall, names.NewStorageTag("foo/1"), true)
   343  	s.stub.CheckCall(c, 4, releaseStorageInstanceCall, names.NewStorageTag("foo/1"), true)
   344  }
   345  
   346  func (s *storageSuite) TestDestroyV3(c *gc.C) {
   347  	results, err := s.apiv3.Destroy(params.Entities{[]params.Entity{
   348  		{Tag: "storage-foo-0"},
   349  		{Tag: "volume-0"},
   350  		{Tag: "filesystem-1-2"},
   351  		{Tag: "machine-0"},
   352  	}})
   353  	c.Assert(err, jc.ErrorIsNil)
   354  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{
   355  		{Error: &params.Error{Message: "cannae do it"}},
   356  		{Error: &params.Error{Message: `"volume-0" is not a valid storage tag`}},
   357  		{Error: &params.Error{Message: `"filesystem-1-2" is not a valid storage tag`}},
   358  		{Error: &params.Error{Message: `"machine-0" is not a valid storage tag`}},
   359  	})
   360  	s.stub.CheckCallNames(c,
   361  		getBlockForTypeCall, // Remove
   362  		getBlockForTypeCall, // Change
   363  		destroyStorageInstanceCall,
   364  	)
   365  	s.stub.CheckCall(c, 2, destroyStorageInstanceCall, names.NewStorageTag("foo/0"), true)
   366  }
   367  
   368  func (s *storageSuite) TestDetach(c *gc.C) {
   369  	results, err := s.api.Detach(params.StorageAttachmentIds{[]params.StorageAttachmentId{
   370  		{StorageTag: "storage-data-0", UnitTag: "unit-mysql-0"},
   371  		{StorageTag: "storage-data-0", UnitTag: ""},
   372  		{StorageTag: "volume-0", UnitTag: "unit-bar-0"},
   373  		{StorageTag: "filesystem-1-2", UnitTag: "unit-bar-0"},
   374  		{StorageTag: "machine-0", UnitTag: "unit-bar-0"},
   375  		{StorageTag: "storage-foo-0", UnitTag: "application-bar"},
   376  	}})
   377  	c.Assert(err, jc.ErrorIsNil)
   378  	c.Assert(results.Results, gc.HasLen, 6)
   379  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{
   380  		{Error: nil},
   381  		{Error: nil},
   382  		{Error: &params.Error{Message: `"volume-0" is not a valid storage tag`}},
   383  		{Error: &params.Error{Message: `"filesystem-1-2" is not a valid storage tag`}},
   384  		{Error: &params.Error{Message: `"machine-0" is not a valid storage tag`}},
   385  		{Error: &params.Error{Message: `"application-bar" is not a valid unit tag`}},
   386  	})
   387  	s.assertCalls(c, []string{
   388  		getBlockForTypeCall, // Change
   389  		detachStorageCall,
   390  		storageInstanceAttachmentsCall,
   391  		detachStorageCall,
   392  	})
   393  	s.stub.CheckCalls(c, []testing.StubCall{
   394  		{getBlockForTypeCall, []interface{}{state.ChangeBlock}},
   395  		{detachStorageCall, []interface{}{s.storageTag, s.unitTag}},
   396  		{storageInstanceAttachmentsCall, []interface{}{s.storageTag}},
   397  		{detachStorageCall, []interface{}{s.storageTag, s.unitTag}},
   398  	})
   399  }
   400  
   401  func (s *storageSuite) TestDetachSpecifiedNotFound(c *gc.C) {
   402  	results, err := s.api.Detach(params.StorageAttachmentIds{[]params.StorageAttachmentId{
   403  		{StorageTag: "storage-data-0", UnitTag: "unit-foo-42"},
   404  	}})
   405  	c.Assert(err, jc.ErrorIsNil)
   406  	c.Assert(results.Results, gc.HasLen, 1)
   407  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{
   408  		{Error: &params.Error{
   409  			Code:    params.CodeNotFound,
   410  			Message: "attachment of storage data/0 to unit foo/42 not found",
   411  		}},
   412  	})
   413  	s.assertCalls(c, []string{
   414  		getBlockForTypeCall, // Change
   415  		detachStorageCall,
   416  	})
   417  	s.stub.CheckCalls(c, []testing.StubCall{
   418  		{getBlockForTypeCall, []interface{}{state.ChangeBlock}},
   419  		{detachStorageCall, []interface{}{
   420  			s.storageTag,
   421  			names.NewUnitTag("foo/42"),
   422  		}},
   423  	})
   424  }
   425  
   426  func (s *storageSuite) TestDetachAttachmentNotFoundConcurrent(c *gc.C) {
   427  	// Simulate:
   428  	//  1. call StorageAttachments, and receive
   429  	//     a list of alive attachments
   430  	//  2. attachment is concurrently destroyed
   431  	//     and removed by another process
   432  	s.storageAccessor.detachStorage = func(sTag names.StorageTag, uTag names.UnitTag) error {
   433  		s.stub.AddCall(detachStorageCall, sTag, uTag)
   434  		return errors.NotFoundf(
   435  			"attachment of %s to %s",
   436  			names.ReadableString(sTag),
   437  			names.ReadableString(uTag),
   438  		)
   439  	}
   440  	results, err := s.api.Detach(params.StorageAttachmentIds{[]params.StorageAttachmentId{
   441  		{StorageTag: "storage-data-0"},
   442  	}})
   443  	c.Assert(err, jc.ErrorIsNil)
   444  	c.Assert(results.Results, gc.HasLen, 1)
   445  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{{}})
   446  	s.assertCalls(c, []string{
   447  		getBlockForTypeCall, // Change
   448  		storageInstanceAttachmentsCall,
   449  		detachStorageCall,
   450  	})
   451  	s.stub.CheckCalls(c, []testing.StubCall{
   452  		{getBlockForTypeCall, []interface{}{state.ChangeBlock}},
   453  		{storageInstanceAttachmentsCall, []interface{}{s.storageTag}},
   454  		{detachStorageCall, []interface{}{s.storageTag, s.unitTag}},
   455  	})
   456  }
   457  
   458  func (s *storageSuite) TestDetachNoAttachmentsStorageNotFound(c *gc.C) {
   459  	results, err := s.api.Detach(params.StorageAttachmentIds{[]params.StorageAttachmentId{
   460  		{StorageTag: "storage-foo-42"},
   461  	}})
   462  	c.Assert(err, jc.ErrorIsNil)
   463  	c.Assert(results.Results, gc.HasLen, 1)
   464  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{
   465  		{Error: &params.Error{
   466  			Code:    params.CodeNotFound,
   467  			Message: "storage foo/42 not found",
   468  		}},
   469  	})
   470  	s.stub.CheckCalls(c, []testing.StubCall{
   471  		{getBlockForTypeCall, []interface{}{state.ChangeBlock}},
   472  		{storageInstanceAttachmentsCall, []interface{}{names.NewStorageTag("foo/42")}},
   473  		{storageInstanceCall, []interface{}{names.NewStorageTag("foo/42")}},
   474  	})
   475  }
   476  
   477  func (s *storageSuite) TestAttach(c *gc.C) {
   478  	results, err := s.api.Attach(params.StorageAttachmentIds{[]params.StorageAttachmentId{
   479  		{StorageTag: "storage-data-0", UnitTag: "unit-mysql-0"},
   480  		{StorageTag: "storage-data-0", UnitTag: "machine-0"},
   481  		{StorageTag: "volume-0", UnitTag: "unit-mysql-0"},
   482  	}})
   483  	c.Assert(err, jc.ErrorIsNil)
   484  	c.Assert(results.Results, gc.HasLen, 3)
   485  	c.Assert(results.Results, jc.DeepEquals, []params.ErrorResult{
   486  		{Error: nil},
   487  		{Error: &params.Error{Message: `"machine-0" is not a valid unit tag`}},
   488  		{Error: &params.Error{Message: `"volume-0" is not a valid storage tag`}},
   489  	})
   490  	s.stub.CheckCalls(c, []testing.StubCall{
   491  		{getBlockForTypeCall, []interface{}{state.ChangeBlock}},
   492  		{attachStorageCall, []interface{}{s.storageTag, s.unitTag}},
   493  	})
   494  }
   495  
   496  func (s *storageSuite) TestImportFilesystem(c *gc.C) {
   497  	s.state.modelTag = coretesting.ModelTag
   498  	filesystemSource := filesystemImporter{&dummy.FilesystemSource{}}
   499  	dummyStorageProvider := &dummy.StorageProvider{
   500  		StorageScope: storage.ScopeEnviron,
   501  		IsDynamic:    true,
   502  		FilesystemSourceFunc: func(*storage.Config) (storage.FilesystemSource, error) {
   503  			return filesystemSource, nil
   504  		},
   505  	}
   506  	s.registry.Providers["radiance"] = dummyStorageProvider
   507  
   508  	results, err := s.api.Import(params.BulkImportStorageParams{[]params.ImportStorageParams{{
   509  		Kind:        params.StorageKindFilesystem,
   510  		Pool:        "radiance",
   511  		ProviderId:  "foo",
   512  		StorageName: "pgdata",
   513  	}}})
   514  	c.Assert(err, jc.ErrorIsNil)
   515  	c.Assert(results.Results, jc.DeepEquals, []params.ImportStorageResult{{
   516  		Result: &params.ImportStorageDetails{
   517  			StorageTag: "storage-data-0",
   518  		},
   519  	}})
   520  	filesystemSource.CheckCalls(c, []testing.StubCall{
   521  		{"ImportFilesystem", []interface{}{
   522  			s.callContext,
   523  			"foo", map[string]string{
   524  				"juju-model-uuid":      "deadbeef-0bad-400d-8000-4b1d0d06f00d",
   525  				"juju-controller-uuid": "deadbeef-1bad-500d-9000-4b1d0d06f00d",
   526  			},
   527  		}},
   528  	})
   529  	s.stub.CheckCalls(c, []testing.StubCall{
   530  		{getBlockForTypeCall, []interface{}{state.ChangeBlock}},
   531  		{addExistingFilesystemCall, []interface{}{
   532  			state.FilesystemInfo{
   533  				FilesystemId: "foo",
   534  				Pool:         "radiance",
   535  				Size:         123,
   536  			},
   537  			(*state.VolumeInfo)(nil),
   538  			"pgdata",
   539  		}},
   540  	})
   541  }
   542  
   543  func (s *storageSuite) TestImportFilesystemVolumeBacked(c *gc.C) {
   544  	s.state.modelTag = coretesting.ModelTag
   545  	volumeSource := volumeImporter{&dummy.VolumeSource{}}
   546  	dummyStorageProvider := &dummy.StorageProvider{
   547  		StorageScope: storage.ScopeEnviron,
   548  		IsDynamic:    true,
   549  		SupportsFunc: func(kind storage.StorageKind) bool {
   550  			return kind == storage.StorageKindBlock
   551  		},
   552  		VolumeSourceFunc: func(*storage.Config) (storage.VolumeSource, error) {
   553  			return volumeSource, nil
   554  		},
   555  	}
   556  	s.registry.Providers["radiance"] = dummyStorageProvider
   557  
   558  	results, err := s.api.Import(params.BulkImportStorageParams{[]params.ImportStorageParams{{
   559  		Kind:        params.StorageKindFilesystem,
   560  		Pool:        "radiance",
   561  		ProviderId:  "foo",
   562  		StorageName: "pgdata",
   563  	}}})
   564  	c.Assert(err, jc.ErrorIsNil)
   565  	c.Assert(results.Results, jc.DeepEquals, []params.ImportStorageResult{{
   566  		Result: &params.ImportStorageDetails{
   567  			StorageTag: "storage-data-0",
   568  		},
   569  	}})
   570  	volumeSource.CheckCalls(c, []testing.StubCall{
   571  		{"ImportVolume", []interface{}{
   572  			s.callContext,
   573  			"foo", map[string]string{
   574  				"juju-model-uuid":      "deadbeef-0bad-400d-8000-4b1d0d06f00d",
   575  				"juju-controller-uuid": "deadbeef-1bad-500d-9000-4b1d0d06f00d",
   576  			},
   577  		}},
   578  	})
   579  	s.stub.CheckCalls(c, []testing.StubCall{
   580  		{getBlockForTypeCall, []interface{}{state.ChangeBlock}},
   581  		{addExistingFilesystemCall, []interface{}{
   582  			state.FilesystemInfo{
   583  				Pool: "radiance",
   584  				Size: 123,
   585  			},
   586  			&state.VolumeInfo{
   587  				VolumeId:   "foo",
   588  				Pool:       "radiance",
   589  				Size:       123,
   590  				HardwareId: "hw",
   591  			},
   592  			"pgdata",
   593  		}},
   594  	})
   595  }
   596  
   597  func (s *storageSuite) TestImportFilesystemError(c *gc.C) {
   598  	filesystemSource := filesystemImporter{&dummy.FilesystemSource{}}
   599  	dummyStorageProvider := &dummy.StorageProvider{
   600  		StorageScope: storage.ScopeEnviron,
   601  		IsDynamic:    true,
   602  		FilesystemSourceFunc: func(*storage.Config) (storage.FilesystemSource, error) {
   603  			return filesystemSource, nil
   604  		},
   605  	}
   606  	s.registry.Providers["radiance"] = dummyStorageProvider
   607  
   608  	filesystemSource.SetErrors(errors.New("nope"))
   609  	results, err := s.api.Import(params.BulkImportStorageParams{[]params.ImportStorageParams{{
   610  		Kind:        params.StorageKindFilesystem,
   611  		Pool:        "radiance",
   612  		ProviderId:  "foo",
   613  		StorageName: "pgdata",
   614  	}}})
   615  	c.Assert(err, jc.ErrorIsNil)
   616  	c.Assert(results.Results, jc.DeepEquals, []params.ImportStorageResult{
   617  		{Error: &params.Error{Message: `importing filesystem: nope`}},
   618  	})
   619  	filesystemSource.CheckCallNames(c, "ImportFilesystem")
   620  	s.stub.CheckCallNames(c, getBlockForTypeCall)
   621  }
   622  
   623  func (s *storageSuite) TestImportFilesystemNotSupported(c *gc.C) {
   624  	filesystemSource := &dummy.FilesystemSource{}
   625  	dummyStorageProvider := &dummy.StorageProvider{
   626  		StorageScope: storage.ScopeEnviron,
   627  		IsDynamic:    true,
   628  		FilesystemSourceFunc: func(*storage.Config) (storage.FilesystemSource, error) {
   629  			return filesystemSource, nil
   630  		},
   631  	}
   632  	s.registry.Providers["radiance"] = dummyStorageProvider
   633  
   634  	results, err := s.api.Import(params.BulkImportStorageParams{[]params.ImportStorageParams{{
   635  		Kind:        params.StorageKindFilesystem,
   636  		Pool:        "radiance",
   637  		ProviderId:  "foo",
   638  		StorageName: "pgdata",
   639  	}}})
   640  	c.Assert(err, jc.ErrorIsNil)
   641  	c.Assert(results.Results, jc.DeepEquals, []params.ImportStorageResult{
   642  		{Error: &params.Error{
   643  			Message: `importing filesystem with storage provider "radiance" not supported`,
   644  			Code:    "not supported",
   645  		}},
   646  	})
   647  	filesystemSource.CheckNoCalls(c)
   648  	s.stub.CheckCallNames(c, getBlockForTypeCall)
   649  }
   650  
   651  func (s *storageSuite) TestImportFilesystemVolumeBackedNotSupported(c *gc.C) {
   652  	volumeSource := &dummy.VolumeSource{}
   653  	dummyStorageProvider := &dummy.StorageProvider{
   654  		StorageScope: storage.ScopeEnviron,
   655  		IsDynamic:    true,
   656  		SupportsFunc: func(kind storage.StorageKind) bool {
   657  			return kind == storage.StorageKindBlock
   658  		},
   659  		VolumeSourceFunc: func(*storage.Config) (storage.VolumeSource, error) {
   660  			return volumeSource, nil
   661  		},
   662  	}
   663  	s.registry.Providers["radiance"] = dummyStorageProvider
   664  
   665  	results, err := s.api.Import(params.BulkImportStorageParams{[]params.ImportStorageParams{{
   666  		Kind:        params.StorageKindFilesystem,
   667  		Pool:        "radiance",
   668  		ProviderId:  "foo",
   669  		StorageName: "pgdata",
   670  	}}})
   671  	c.Assert(err, jc.ErrorIsNil)
   672  	c.Assert(results.Results, jc.DeepEquals, []params.ImportStorageResult{
   673  		{Error: &params.Error{
   674  			Message: `importing volume with storage provider "radiance" not supported`,
   675  			Code:    "not supported",
   676  		}},
   677  	})
   678  	volumeSource.CheckNoCalls(c)
   679  	s.stub.CheckCallNames(c, getBlockForTypeCall)
   680  }
   681  
   682  func (s *storageSuite) TestImportValidationErrors(c *gc.C) {
   683  	results, err := s.api.Import(params.BulkImportStorageParams{[]params.ImportStorageParams{{
   684  		Kind:        params.StorageKindBlock,
   685  		Pool:        "radiance",
   686  		ProviderId:  "foo",
   687  		StorageName: "pgdata",
   688  	}, {
   689  		Kind:        params.StorageKindFilesystem,
   690  		Pool:        "123",
   691  		ProviderId:  "foo",
   692  		StorageName: "pgdata",
   693  	}}})
   694  	c.Assert(err, jc.ErrorIsNil)
   695  	c.Assert(results.Results, jc.DeepEquals, []params.ImportStorageResult{
   696  		{Error: &params.Error{Message: `storage kind "block" not supported`, Code: "not supported"}},
   697  		{Error: &params.Error{Message: `pool name "123" not valid`}},
   698  	})
   699  }
   700  
   701  type filesystemImporter struct {
   702  	*dummy.FilesystemSource
   703  }
   704  
   705  // ImportFilesystem is part of the storage.FilesystemImporter interface.
   706  func (f filesystemImporter) ImportFilesystem(ctx context.ProviderCallContext, providerId string, tags map[string]string) (storage.FilesystemInfo, error) {
   707  	f.MethodCall(f, "ImportFilesystem", ctx, providerId, tags)
   708  	return storage.FilesystemInfo{
   709  		FilesystemId: providerId,
   710  		Size:         123,
   711  	}, f.NextErr()
   712  }
   713  
   714  type volumeImporter struct {
   715  	*dummy.VolumeSource
   716  }
   717  
   718  // ImportVolume is part of the storage.VolumeImporter interface.
   719  func (v volumeImporter) ImportVolume(ctx context.ProviderCallContext, providerId string, tags map[string]string) (storage.VolumeInfo, error) {
   720  	v.MethodCall(v, "ImportVolume", ctx, providerId, tags)
   721  	return storage.VolumeInfo{
   722  		VolumeId:   providerId,
   723  		Size:       123,
   724  		HardwareId: "hw",
   725  	}, v.NextErr()
   726  }