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

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // Package storage provides an API server facade for managing
     5  // storage entities.
     6  package storage
     7  
     8  import (
     9  	"github.com/juju/collections/set"
    10  	"github.com/juju/errors"
    11  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/apiserver/common"
    14  	"github.com/juju/juju/apiserver/common/storagecommon"
    15  	"github.com/juju/juju/apiserver/facade"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/caas"
    18  	"github.com/juju/juju/core/status"
    19  	"github.com/juju/juju/environs"
    20  	"github.com/juju/juju/environs/context"
    21  	"github.com/juju/juju/environs/tags"
    22  	"github.com/juju/juju/permission"
    23  	"github.com/juju/juju/state"
    24  	"github.com/juju/juju/state/stateenvirons"
    25  	"github.com/juju/juju/storage"
    26  	"github.com/juju/juju/storage/poolmanager"
    27  )
    28  
    29  // StorageAPI implements the latest version (v5) of the Storage API which adds Update and Delete.
    30  type StorageAPI struct {
    31  	backend       backend
    32  	storageAccess storageAccess
    33  	registry      storage.ProviderRegistry
    34  	poolManager   poolmanager.PoolManager
    35  	authorizer    facade.Authorizer
    36  	callContext   context.ProviderCallContext
    37  	modelType     state.ModelType
    38  }
    39  
    40  // APIv4 implements the storage v4 API adding AddToUnit, Import and Remove (replacing Destroy)
    41  type StorageAPIv4 struct {
    42  	StorageAPI
    43  }
    44  
    45  // APIv3 implements the storage v3 API.
    46  type StorageAPIv3 struct {
    47  	StorageAPIv4
    48  }
    49  
    50  // NewStorageAPI returns a new storage API facade.
    51  func NewStorageAPI(context facade.Context) (*StorageAPI, error) {
    52  	st := context.State()
    53  	model, err := st.Model()
    54  	if err != nil {
    55  		return nil, errors.Trace(err)
    56  	}
    57  	registry, err := stateenvirons.NewStorageProviderRegistryForModel(
    58  		model,
    59  		stateenvirons.GetNewEnvironFunc(environs.New),
    60  		stateenvirons.GetNewCAASBrokerFunc(caas.New))
    61  	if err != nil {
    62  		return nil, errors.Trace(err)
    63  	}
    64  	pm := poolmanager.New(state.NewStateSettings(st), registry)
    65  
    66  	storageAccessor, err := getStorageAccessor(st)
    67  	if err != nil {
    68  		return nil, errors.Annotate(err, "getting backend")
    69  	}
    70  
    71  	authorizer := context.Auth()
    72  	if !authorizer.AuthClient() {
    73  		return nil, common.ErrPerm
    74  	}
    75  	return newStorageAPI(stateShim{st}, model.Type(), storageAccessor, registry, pm, authorizer, state.CallContext(st)), nil
    76  }
    77  
    78  func newStorageAPI(
    79  	backend backend,
    80  	modelType state.ModelType,
    81  	storageAccess storageAccess,
    82  	registry storage.ProviderRegistry,
    83  	pm poolmanager.PoolManager,
    84  	authorizer facade.Authorizer,
    85  	callContext context.ProviderCallContext,
    86  ) *StorageAPI {
    87  	return &StorageAPI{
    88  		backend:       backend,
    89  		modelType:     modelType,
    90  		storageAccess: storageAccess,
    91  		registry:      registry,
    92  		poolManager:   pm,
    93  		authorizer:    authorizer,
    94  		callContext:   callContext,
    95  	}
    96  }
    97  
    98  // NewStorageAPIV4 returns a new storage v4 API facade.
    99  func NewStorageAPIV4(context facade.Context) (*StorageAPIv4, error) {
   100  	storageAPI, err := NewStorageAPI(context)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	return &StorageAPIv4{
   105  		StorageAPI: *storageAPI,
   106  	}, nil
   107  }
   108  
   109  // NewStorageAPIV3 returns a new storage v3 API facade.
   110  func NewStorageAPIV3(context facade.Context) (*StorageAPIv3, error) {
   111  	storageAPI, err := NewStorageAPIV4(context)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	return &StorageAPIv3{
   116  		StorageAPIv4: *storageAPI,
   117  	}, nil
   118  }
   119  
   120  func (a *StorageAPI) checkCanRead() error {
   121  	canRead, err := a.authorizer.HasPermission(permission.ReadAccess, a.backend.ModelTag())
   122  	if err != nil {
   123  		return errors.Trace(err)
   124  	}
   125  	if !canRead {
   126  		return common.ErrPerm
   127  	}
   128  	return nil
   129  }
   130  
   131  func (a *StorageAPI) checkCanWrite() error {
   132  	canWrite, err := a.authorizer.HasPermission(permission.WriteAccess, a.backend.ModelTag())
   133  	if err != nil {
   134  		return errors.Trace(err)
   135  	}
   136  	if !canWrite {
   137  		return common.ErrPerm
   138  	}
   139  	return nil
   140  }
   141  
   142  // StorageDetails retrieves and returns detailed information about desired
   143  // storage identified by supplied tags. If specified storage cannot be
   144  // retrieved, individual error is returned instead of storage information.
   145  func (a *StorageAPI) StorageDetails(entities params.Entities) (params.StorageDetailsResults, error) {
   146  	if err := a.checkCanWrite(); err != nil {
   147  		return params.StorageDetailsResults{}, errors.Trace(err)
   148  	}
   149  	results := make([]params.StorageDetailsResult, len(entities.Entities))
   150  	for i, entity := range entities.Entities {
   151  		storageTag, err := names.ParseStorageTag(entity.Tag)
   152  		if err != nil {
   153  			results[i].Error = common.ServerError(err)
   154  			continue
   155  		}
   156  		storageInstance, err := a.storageAccess.StorageInstance(storageTag)
   157  		if err != nil {
   158  			results[i].Error = common.ServerError(err)
   159  			continue
   160  		}
   161  		details, err := createStorageDetails(a.backend, a.storageAccess, storageInstance)
   162  		if err != nil {
   163  			results[i].Error = common.ServerError(err)
   164  			continue
   165  		}
   166  		results[i].Result = details
   167  	}
   168  	return params.StorageDetailsResults{Results: results}, nil
   169  }
   170  
   171  // ListStorageDetails returns storage matching a filter.
   172  func (a *StorageAPI) ListStorageDetails(filters params.StorageFilters) (params.StorageDetailsListResults, error) {
   173  	if err := a.checkCanRead(); err != nil {
   174  		return params.StorageDetailsListResults{}, errors.Trace(err)
   175  	}
   176  	results := params.StorageDetailsListResults{
   177  		Results: make([]params.StorageDetailsListResult, len(filters.Filters)),
   178  	}
   179  	for i, filter := range filters.Filters {
   180  		list, err := a.listStorageDetails(filter)
   181  		if err != nil {
   182  			results.Results[i].Error = common.ServerError(err)
   183  			continue
   184  		}
   185  		results.Results[i].Result = list
   186  	}
   187  	return results, nil
   188  }
   189  
   190  func (a *StorageAPI) listStorageDetails(filter params.StorageFilter) ([]params.StorageDetails, error) {
   191  	if filter != (params.StorageFilter{}) {
   192  		// StorageFilter has no fields at the time of writing, but
   193  		// check that no fields are set in case we forget to update
   194  		// this code.
   195  		return nil, errors.NotSupportedf("storage filters")
   196  	}
   197  	stateInstances, err := a.storageAccess.AllStorageInstances()
   198  	if err != nil {
   199  		return nil, common.ServerError(err)
   200  	}
   201  	results := make([]params.StorageDetails, len(stateInstances))
   202  	for i, stateInstance := range stateInstances {
   203  		details, err := createStorageDetails(a.backend, a.storageAccess, stateInstance)
   204  		if err != nil {
   205  			return nil, errors.Annotatef(
   206  				err, "getting details for %s",
   207  				names.ReadableString(stateInstance.Tag()),
   208  			)
   209  		}
   210  		results[i] = *details
   211  	}
   212  	return results, nil
   213  }
   214  
   215  func createStorageDetails(
   216  	backend backend,
   217  	st storageAccess,
   218  	si state.StorageInstance,
   219  ) (*params.StorageDetails, error) {
   220  	// Get information from underlying volume or filesystem.
   221  	var persistent bool
   222  	var statusEntity status.StatusGetter
   223  	if si.Kind() == state.StorageKindFilesystem {
   224  		stFile := st.FilesystemAccess()
   225  		if stFile == nil {
   226  			return nil, errors.NotImplementedf("FilesystemStorage instance")
   227  		}
   228  		// TODO(axw) when we support persistent filesystems,
   229  		// e.g. CephFS, we'll need to do set "persistent"
   230  		// here too.
   231  		filesystem, err := stFile.StorageInstanceFilesystem(si.StorageTag())
   232  		if err != nil {
   233  			return nil, errors.Trace(err)
   234  		}
   235  		statusEntity = filesystem
   236  	} else {
   237  		stVolume := st.VolumeAccess()
   238  		if stVolume == nil {
   239  			return nil, errors.NotImplementedf("BlockStorage instance")
   240  		}
   241  		volume, err := stVolume.StorageInstanceVolume(si.StorageTag())
   242  		if err != nil {
   243  			return nil, errors.Trace(err)
   244  		}
   245  		if info, err := volume.Info(); err == nil {
   246  			persistent = info.Persistent
   247  		}
   248  		statusEntity = volume
   249  	}
   250  	status, err := statusEntity.Status()
   251  	if err != nil {
   252  		return nil, errors.Trace(err)
   253  	}
   254  
   255  	// Get unit storage attachments.
   256  	var storageAttachmentDetails map[string]params.StorageAttachmentDetails
   257  	storageAttachments, err := st.StorageAttachments(si.StorageTag())
   258  	if err != nil {
   259  		return nil, errors.Trace(err)
   260  	}
   261  	if len(storageAttachments) > 0 {
   262  		storageAttachmentDetails = make(map[string]params.StorageAttachmentDetails)
   263  		for _, a := range storageAttachments {
   264  			// TODO(caas) - handle attachments to units
   265  			machineTag, location, err := storageAttachmentInfo(backend, st, a)
   266  			if err != nil {
   267  				return nil, errors.Trace(err)
   268  			}
   269  			details := params.StorageAttachmentDetails{
   270  				StorageTag: a.StorageInstance().String(),
   271  				UnitTag:    a.Unit().String(),
   272  				Location:   location,
   273  				Life:       params.Life(a.Life().String()),
   274  			}
   275  			if machineTag.Id() != "" {
   276  				details.MachineTag = machineTag.String()
   277  			}
   278  			storageAttachmentDetails[a.Unit().String()] = details
   279  		}
   280  	}
   281  
   282  	var ownerTag string
   283  	if owner, ok := si.Owner(); ok {
   284  		ownerTag = owner.String()
   285  	}
   286  
   287  	return &params.StorageDetails{
   288  		StorageTag:  si.Tag().String(),
   289  		OwnerTag:    ownerTag,
   290  		Kind:        params.StorageKind(si.Kind()),
   291  		Life:        params.Life(si.Life().String()),
   292  		Status:      common.EntityStatusFromState(status),
   293  		Persistent:  persistent,
   294  		Attachments: storageAttachmentDetails,
   295  	}, nil
   296  }
   297  
   298  func storageAttachmentInfo(
   299  	backend backend,
   300  	st storageAccess,
   301  	a state.StorageAttachment,
   302  ) (_ names.MachineTag, location string, _ error) {
   303  	machineTag, err := unitAssignedMachine(backend, a.Unit())
   304  	if errors.IsNotAssigned(err) {
   305  		return names.MachineTag{}, "", nil
   306  	} else if err != nil {
   307  		return names.MachineTag{}, "", errors.Trace(err)
   308  	}
   309  	info, err := storagecommon.StorageAttachmentInfo(st, st.VolumeAccess(), st.FilesystemAccess(), a, machineTag)
   310  	if errors.IsNotProvisioned(err) {
   311  		return machineTag, "", nil
   312  	} else if err != nil {
   313  		return names.MachineTag{}, "", errors.Trace(err)
   314  	}
   315  	return machineTag, info.Location, nil
   316  }
   317  
   318  // ListPools returns a list of pools.
   319  // If filter is provided, returned list only contains pools that match
   320  // the filter.
   321  // Pools can be filtered on names and provider types.
   322  // If both names and types are provided as filter,
   323  // pools that match either are returned.
   324  // This method lists union of pools and environment provider types.
   325  // If no filter is provided, all pools are returned.
   326  func (a *StorageAPI) ListPools(
   327  	filters params.StoragePoolFilters,
   328  ) (params.StoragePoolsResults, error) {
   329  	if err := a.checkCanRead(); err != nil {
   330  		return params.StoragePoolsResults{}, errors.Trace(err)
   331  	}
   332  
   333  	results := params.StoragePoolsResults{
   334  		Results: make([]params.StoragePoolsResult, len(filters.Filters)),
   335  	}
   336  	for i, filter := range filters.Filters {
   337  		pools, err := a.listPools(a.ensureStoragePoolFilter(filter))
   338  		if err != nil {
   339  			results.Results[i].Error = common.ServerError(err)
   340  			continue
   341  		}
   342  		results.Results[i].Result = pools
   343  	}
   344  	return results, nil
   345  }
   346  
   347  func (a *StorageAPI) ensureStoragePoolFilter(filter params.StoragePoolFilter) params.StoragePoolFilter {
   348  	if a.modelType == state.ModelTypeCAAS {
   349  		filter.Providers = append(filter.Providers, "kubernetes")
   350  	}
   351  	return filter
   352  }
   353  
   354  func (a *StorageAPI) listPools(filter params.StoragePoolFilter) ([]params.StoragePool, error) {
   355  	if err := a.validatePoolListFilter(filter); err != nil {
   356  		return nil, errors.Trace(err)
   357  	}
   358  	pools, err := a.poolManager.List()
   359  	if err != nil {
   360  		return nil, errors.Trace(err)
   361  	}
   362  	providers, err := a.registry.StorageProviderTypes()
   363  	if err != nil {
   364  		return nil, errors.Trace(err)
   365  	}
   366  	matches := buildFilter(filter)
   367  	results := append(
   368  		filterPools(pools, matches),
   369  		filterProviders(providers, matches)...,
   370  	)
   371  	return results, nil
   372  }
   373  
   374  func buildFilter(filter params.StoragePoolFilter) func(n, p string) bool {
   375  	providerSet := set.NewStrings(filter.Providers...)
   376  	nameSet := set.NewStrings(filter.Names...)
   377  
   378  	matches := func(n, p string) bool {
   379  		// no filters supplied = pool matches criteria
   380  		if providerSet.IsEmpty() && nameSet.IsEmpty() {
   381  			return true
   382  		}
   383  		// if at least 1 name and type are supplied, use AND to match
   384  		if !providerSet.IsEmpty() && !nameSet.IsEmpty() {
   385  			return nameSet.Contains(n) && providerSet.Contains(p)
   386  		}
   387  		// Otherwise, if only names or types are supplied, use OR to match
   388  		return nameSet.Contains(n) || providerSet.Contains(p)
   389  	}
   390  	return matches
   391  }
   392  
   393  func filterProviders(
   394  	providers []storage.ProviderType,
   395  	matches func(n, p string) bool,
   396  ) []params.StoragePool {
   397  	if len(providers) == 0 {
   398  		return nil
   399  	}
   400  	all := make([]params.StoragePool, 0, len(providers))
   401  	for _, p := range providers {
   402  		ps := string(p)
   403  		if matches(ps, ps) {
   404  			all = append(all, params.StoragePool{Name: ps, Provider: ps})
   405  		}
   406  	}
   407  	return all
   408  }
   409  
   410  func filterPools(
   411  	pools []*storage.Config,
   412  	matches func(n, p string) bool,
   413  ) []params.StoragePool {
   414  	if len(pools) == 0 {
   415  		return nil
   416  	}
   417  	all := make([]params.StoragePool, 0, len(pools))
   418  	for _, p := range pools {
   419  		if matches(p.Name(), string(p.Provider())) {
   420  			all = append(all, params.StoragePool{
   421  				Name:     p.Name(),
   422  				Provider: string(p.Provider()),
   423  				Attrs:    p.Attrs(),
   424  			})
   425  		}
   426  	}
   427  	return all
   428  }
   429  
   430  func (a *StorageAPI) validatePoolListFilter(filter params.StoragePoolFilter) error {
   431  	if err := a.validateProviderCriteria(filter.Providers); err != nil {
   432  		return errors.Trace(err)
   433  	}
   434  	if err := a.validateNameCriteria(filter.Names); err != nil {
   435  		return errors.Trace(err)
   436  	}
   437  	return nil
   438  }
   439  
   440  func (a *StorageAPI) validateNameCriteria(names []string) error {
   441  	for _, n := range names {
   442  		if !storage.IsValidPoolName(n) {
   443  			return errors.NotValidf("pool name %q", n)
   444  		}
   445  	}
   446  	return nil
   447  }
   448  
   449  func (a *StorageAPI) validateProviderCriteria(providers []string) error {
   450  	for _, p := range providers {
   451  		_, err := a.registry.StorageProvider(storage.ProviderType(p))
   452  		if err != nil {
   453  			return errors.Trace(err)
   454  		}
   455  	}
   456  	return nil
   457  }
   458  
   459  // CreatePool creates a new pool with specified parameters.
   460  func (a *StorageAPIv4) CreatePool(p params.StoragePool) error {
   461  	_, err := a.poolManager.Create(
   462  		p.Name,
   463  		storage.ProviderType(p.Provider),
   464  		p.Attrs)
   465  	return err
   466  }
   467  
   468  // CreatePool creates a new pool with specified parameters.
   469  func (a *StorageAPI) CreatePool(p params.StoragePoolArgs) (params.ErrorResults, error) {
   470  	results := params.ErrorResults{
   471  		Results: make([]params.ErrorResult, len(p.Pools)),
   472  	}
   473  	for i, pool := range p.Pools {
   474  		_, err := a.poolManager.Create(
   475  			pool.Name,
   476  			storage.ProviderType(pool.Provider),
   477  			pool.Attrs)
   478  		results.Results[i].Error = common.ServerError(err)
   479  	}
   480  	return results, nil
   481  }
   482  
   483  // ListVolumes lists volumes with the given filters. Each filter produces
   484  // an independent list of volumes, or an error if the filter is invalid
   485  // or the volumes could not be listed.
   486  func (a *StorageAPI) ListVolumes(filters params.VolumeFilters) (params.VolumeDetailsListResults, error) {
   487  	if err := a.checkCanRead(); err != nil {
   488  		return params.VolumeDetailsListResults{}, errors.Trace(err)
   489  	}
   490  	results := params.VolumeDetailsListResults{
   491  		Results: make([]params.VolumeDetailsListResult, len(filters.Filters)),
   492  	}
   493  	stVolumeAccess := a.storageAccess.VolumeAccess()
   494  	for i, filter := range filters.Filters {
   495  		volumes, volumeAttachments, err := filterVolumes(stVolumeAccess, filter)
   496  		if err != nil {
   497  			results.Results[i].Error = common.ServerError(err)
   498  			continue
   499  		}
   500  		details, err := createVolumeDetailsList(
   501  			a.backend, a.storageAccess, volumes, volumeAttachments,
   502  		)
   503  		if err != nil {
   504  			results.Results[i].Error = common.ServerError(err)
   505  			continue
   506  		}
   507  		results.Results[i].Result = details
   508  	}
   509  	return results, nil
   510  }
   511  
   512  func filterVolumes(
   513  	stVolume storageVolume,
   514  	f params.VolumeFilter,
   515  ) ([]state.Volume, map[names.VolumeTag][]state.VolumeAttachment, error) {
   516  	// Exit early if there's no volume support.
   517  	if stVolume == nil {
   518  		return nil, nil, nil
   519  	}
   520  	if f.IsEmpty() {
   521  		// No filter was specified: get all volumes, and all attachments.
   522  		volumes, err := stVolume.AllVolumes()
   523  		if err != nil {
   524  			return nil, nil, errors.Trace(err)
   525  		}
   526  		volumeAttachments := make(map[names.VolumeTag][]state.VolumeAttachment)
   527  		for _, v := range volumes {
   528  			attachments, err := stVolume.VolumeAttachments(v.VolumeTag())
   529  			if err != nil {
   530  				return nil, nil, errors.Trace(err)
   531  			}
   532  			volumeAttachments[v.VolumeTag()] = attachments
   533  		}
   534  		return volumes, volumeAttachments, nil
   535  	}
   536  	volumesByTag := make(map[names.VolumeTag]state.Volume)
   537  	volumeAttachments := make(map[names.VolumeTag][]state.VolumeAttachment)
   538  	for _, machine := range f.Machines {
   539  		machineTag, err := names.ParseMachineTag(machine)
   540  		if err != nil {
   541  			return nil, nil, errors.Trace(err)
   542  		}
   543  		attachments, err := stVolume.MachineVolumeAttachments(machineTag)
   544  		if err != nil {
   545  			return nil, nil, errors.Trace(err)
   546  		}
   547  		for _, attachment := range attachments {
   548  			volumeTag := attachment.Volume()
   549  			volumesByTag[volumeTag] = nil
   550  			volumeAttachments[volumeTag] = append(volumeAttachments[volumeTag], attachment)
   551  		}
   552  	}
   553  	for volumeTag := range volumesByTag {
   554  		volume, err := stVolume.Volume(volumeTag)
   555  		if err != nil {
   556  			return nil, nil, errors.Trace(err)
   557  		}
   558  		volumesByTag[volumeTag] = volume
   559  	}
   560  	volumes := make([]state.Volume, 0, len(volumesByTag))
   561  	for _, volume := range volumesByTag {
   562  		volumes = append(volumes, volume)
   563  	}
   564  	return volumes, volumeAttachments, nil
   565  }
   566  
   567  func createVolumeDetailsList(
   568  	backend backend,
   569  	st storageAccess,
   570  	volumes []state.Volume,
   571  	attachments map[names.VolumeTag][]state.VolumeAttachment,
   572  ) ([]params.VolumeDetails, error) {
   573  
   574  	if len(volumes) == 0 {
   575  		return nil, nil
   576  	}
   577  	results := make([]params.VolumeDetails, len(volumes))
   578  	for i, v := range volumes {
   579  		details, err := createVolumeDetails(backend, st, v, attachments[v.VolumeTag()])
   580  		if err != nil {
   581  			return nil, errors.Annotatef(
   582  				err, "getting details for %s",
   583  				names.ReadableString(v.VolumeTag()),
   584  			)
   585  		}
   586  		results[i] = *details
   587  	}
   588  	return results, nil
   589  }
   590  
   591  func createVolumeDetails(
   592  	backend backend,
   593  	st storageAccess,
   594  	v state.Volume,
   595  	attachments []state.VolumeAttachment,
   596  ) (*params.VolumeDetails, error) {
   597  
   598  	details := &params.VolumeDetails{
   599  		VolumeTag: v.VolumeTag().String(),
   600  		Life:      params.Life(v.Life().String()),
   601  	}
   602  
   603  	if info, err := v.Info(); err == nil {
   604  		details.Info = storagecommon.VolumeInfoFromState(info)
   605  	}
   606  
   607  	if len(attachments) > 0 {
   608  		details.MachineAttachments = make(map[string]params.VolumeAttachmentDetails, len(attachments))
   609  		details.UnitAttachments = make(map[string]params.VolumeAttachmentDetails, len(attachments))
   610  		for _, attachment := range attachments {
   611  			attDetails := params.VolumeAttachmentDetails{
   612  				Life: params.Life(attachment.Life().String()),
   613  			}
   614  			if stateInfo, err := attachment.Info(); err == nil {
   615  				attDetails.VolumeAttachmentInfo = storagecommon.VolumeAttachmentInfoFromState(
   616  					stateInfo,
   617  				)
   618  			}
   619  			if attachment.Host().Kind() == names.MachineTagKind {
   620  				details.MachineAttachments[attachment.Host().String()] = attDetails
   621  			} else {
   622  				details.UnitAttachments[attachment.Host().String()] = attDetails
   623  			}
   624  		}
   625  	}
   626  
   627  	status, err := v.Status()
   628  	if err != nil {
   629  		return nil, errors.Trace(err)
   630  	}
   631  	details.Status = common.EntityStatusFromState(status)
   632  
   633  	if storageTag, err := v.StorageInstance(); err == nil {
   634  		storageInstance, err := st.StorageInstance(storageTag)
   635  		if err != nil {
   636  			return nil, errors.Trace(err)
   637  		}
   638  		storageDetails, err := createStorageDetails(backend, st, storageInstance)
   639  		if err != nil {
   640  			return nil, errors.Trace(err)
   641  		}
   642  		details.Storage = storageDetails
   643  	}
   644  
   645  	return details, nil
   646  }
   647  
   648  // ListFilesystems returns a list of filesystems in the environment matching
   649  // the provided filter. Each result describes a filesystem in detail, including
   650  // the filesystem's attachments.
   651  func (a *StorageAPI) ListFilesystems(filters params.FilesystemFilters) (params.FilesystemDetailsListResults, error) {
   652  	results := params.FilesystemDetailsListResults{
   653  		Results: make([]params.FilesystemDetailsListResult, len(filters.Filters)),
   654  	}
   655  	if err := a.checkCanRead(); err != nil {
   656  		return results, errors.Trace(err)
   657  	}
   658  
   659  	stFileAccess := a.storageAccess.FilesystemAccess()
   660  	for i, filter := range filters.Filters {
   661  		filesystems, filesystemAttachments, err := filterFilesystems(stFileAccess, filter)
   662  		if err != nil {
   663  			results.Results[i].Error = common.ServerError(err)
   664  			continue
   665  		}
   666  		details, err := createFilesystemDetailsList(
   667  			a.backend, a.storageAccess, filesystems, filesystemAttachments,
   668  		)
   669  		if err != nil {
   670  			results.Results[i].Error = common.ServerError(err)
   671  			continue
   672  		}
   673  		results.Results[i].Result = details
   674  	}
   675  	return results, nil
   676  }
   677  
   678  func filterFilesystems(
   679  	stFile storageFile,
   680  	f params.FilesystemFilter,
   681  ) ([]state.Filesystem, map[names.FilesystemTag][]state.FilesystemAttachment, error) {
   682  	if f.IsEmpty() {
   683  		// No filter was specified: get all filesystems, and all attachments.
   684  		filesystems, err := stFile.AllFilesystems()
   685  		if err != nil {
   686  			return nil, nil, errors.Trace(err)
   687  		}
   688  		filesystemAttachments := make(map[names.FilesystemTag][]state.FilesystemAttachment)
   689  		for _, f := range filesystems {
   690  			attachments, err := stFile.FilesystemAttachments(f.FilesystemTag())
   691  			if err != nil {
   692  				return nil, nil, errors.Trace(err)
   693  			}
   694  			filesystemAttachments[f.FilesystemTag()] = attachments
   695  		}
   696  		return filesystems, filesystemAttachments, nil
   697  	}
   698  	filesystemsByTag := make(map[names.FilesystemTag]state.Filesystem)
   699  	filesystemAttachments := make(map[names.FilesystemTag][]state.FilesystemAttachment)
   700  	for _, machine := range f.Machines {
   701  		machineTag, err := names.ParseMachineTag(machine)
   702  		if err != nil {
   703  			return nil, nil, errors.Trace(err)
   704  		}
   705  		attachments, err := stFile.MachineFilesystemAttachments(machineTag)
   706  		if err != nil {
   707  			return nil, nil, errors.Trace(err)
   708  		}
   709  		for _, attachment := range attachments {
   710  			filesystemTag := attachment.Filesystem()
   711  			filesystemsByTag[filesystemTag] = nil
   712  			filesystemAttachments[filesystemTag] = append(filesystemAttachments[filesystemTag], attachment)
   713  		}
   714  	}
   715  	for filesystemTag := range filesystemsByTag {
   716  		filesystem, err := stFile.Filesystem(filesystemTag)
   717  		if err != nil {
   718  			return nil, nil, errors.Trace(err)
   719  		}
   720  		filesystemsByTag[filesystemTag] = filesystem
   721  	}
   722  	filesystems := make([]state.Filesystem, 0, len(filesystemsByTag))
   723  	for _, filesystem := range filesystemsByTag {
   724  		filesystems = append(filesystems, filesystem)
   725  	}
   726  	return filesystems, filesystemAttachments, nil
   727  }
   728  
   729  func createFilesystemDetailsList(
   730  	backend backend,
   731  	st storageAccess,
   732  	filesystems []state.Filesystem,
   733  	attachments map[names.FilesystemTag][]state.FilesystemAttachment,
   734  ) ([]params.FilesystemDetails, error) {
   735  
   736  	if len(filesystems) == 0 {
   737  		return nil, nil
   738  	}
   739  	results := make([]params.FilesystemDetails, len(filesystems))
   740  	for i, f := range filesystems {
   741  		details, err := createFilesystemDetails(backend, st, f, attachments[f.FilesystemTag()])
   742  		if err != nil {
   743  			return nil, errors.Annotatef(
   744  				err, "getting details for %s",
   745  				names.ReadableString(f.FilesystemTag()),
   746  			)
   747  		}
   748  		results[i] = *details
   749  	}
   750  	return results, nil
   751  }
   752  
   753  func createFilesystemDetails(
   754  	backend backend,
   755  	st storageAccess,
   756  	f state.Filesystem,
   757  	attachments []state.FilesystemAttachment,
   758  ) (*params.FilesystemDetails, error) {
   759  
   760  	details := &params.FilesystemDetails{
   761  		FilesystemTag: f.FilesystemTag().String(),
   762  		Life:          params.Life(f.Life().String()),
   763  	}
   764  
   765  	if volumeTag, err := f.Volume(); err == nil {
   766  		details.VolumeTag = volumeTag.String()
   767  	}
   768  
   769  	if info, err := f.Info(); err == nil {
   770  		details.Info = storagecommon.FilesystemInfoFromState(info)
   771  	}
   772  
   773  	if len(attachments) > 0 {
   774  		details.MachineAttachments = make(map[string]params.FilesystemAttachmentDetails, len(attachments))
   775  		details.UnitAttachments = make(map[string]params.FilesystemAttachmentDetails, len(attachments))
   776  		for _, attachment := range attachments {
   777  			attDetails := params.FilesystemAttachmentDetails{
   778  				Life: params.Life(attachment.Life().String()),
   779  			}
   780  			if stateInfo, err := attachment.Info(); err == nil {
   781  				attDetails.FilesystemAttachmentInfo = storagecommon.FilesystemAttachmentInfoFromState(
   782  					stateInfo,
   783  				)
   784  			}
   785  			if attachment.Host().Kind() == names.MachineTagKind {
   786  				details.MachineAttachments[attachment.Host().String()] = attDetails
   787  			} else {
   788  				details.UnitAttachments[attachment.Host().String()] = attDetails
   789  			}
   790  		}
   791  	}
   792  
   793  	status, err := f.Status()
   794  	if err != nil {
   795  		return nil, errors.Trace(err)
   796  	}
   797  	details.Status = common.EntityStatusFromState(status)
   798  
   799  	if storageTag, err := f.Storage(); err == nil {
   800  		storageInstance, err := st.StorageInstance(storageTag)
   801  		if err != nil {
   802  			return nil, errors.Trace(err)
   803  		}
   804  		storageDetails, err := createStorageDetails(backend, st, storageInstance)
   805  		if err != nil {
   806  			return nil, errors.Trace(err)
   807  		}
   808  		details.Storage = storageDetails
   809  	}
   810  
   811  	return details, nil
   812  }
   813  
   814  // AddToUnit validates and creates additional storage instances for units.
   815  // A "CHANGE" block can block this operation.
   816  func (a *StorageAPIv3) AddToUnit(args params.StoragesAddParams) (params.ErrorResults, error) {
   817  	v4results, err := a.addToUnit(args)
   818  	if err != nil {
   819  		return params.ErrorResults{}, err
   820  	}
   821  	v3results := make([]params.ErrorResult, len(v4results.Results))
   822  	for i, result := range v4results.Results {
   823  		v3results[i].Error = result.Error
   824  	}
   825  	return params.ErrorResults{v3results}, nil
   826  }
   827  
   828  // AddToUnit validates and creates additional storage instances for units.
   829  // A "CHANGE" block can block this operation.
   830  func (a *StorageAPI) AddToUnit(args params.StoragesAddParams) (params.AddStorageResults, error) {
   831  	return a.addToUnit(args)
   832  }
   833  
   834  func (a *StorageAPI) addToUnit(args params.StoragesAddParams) (params.AddStorageResults, error) {
   835  	if err := a.checkCanWrite(); err != nil {
   836  		return params.AddStorageResults{}, errors.Trace(err)
   837  	}
   838  
   839  	// Check if changes are allowed and the operation may proceed.
   840  	blockChecker := common.NewBlockChecker(a.backend)
   841  	if err := blockChecker.ChangeAllowed(); err != nil {
   842  		return params.AddStorageResults{}, errors.Trace(err)
   843  	}
   844  
   845  	paramsToState := func(p params.StorageConstraints) state.StorageConstraints {
   846  		s := state.StorageConstraints{Pool: p.Pool}
   847  		if p.Size != nil {
   848  			s.Size = *p.Size
   849  		}
   850  		if p.Count != nil {
   851  			s.Count = *p.Count
   852  		}
   853  		return s
   854  	}
   855  
   856  	result := make([]params.AddStorageResult, len(args.Storages))
   857  	for i, one := range args.Storages {
   858  		u, err := names.ParseUnitTag(one.UnitTag)
   859  		if err != nil {
   860  			result[i].Error = common.ServerError(err)
   861  			continue
   862  		}
   863  
   864  		tags, err := a.storageAccess.AddStorageForUnit(
   865  			u, one.StorageName, paramsToState(one.Constraints),
   866  		)
   867  		if err != nil {
   868  			result[i].Error = common.ServerError(err)
   869  		}
   870  		tagStrings := make([]string, len(tags))
   871  		for i, tag := range tags {
   872  			tagStrings[i] = tag.String()
   873  		}
   874  		result[i].Result = &params.AddStorageDetails{
   875  			StorageTags: tagStrings,
   876  		}
   877  	}
   878  	return params.AddStorageResults{Results: result}, nil
   879  }
   880  
   881  // Remove sets the specified storage entities to Dying, unless they are
   882  // already Dying or Dead, such that the storage will eventually be removed
   883  // from the model. If the arguments specify that the storage should be
   884  // destroyed, then the associated cloud storage will be destroyed first;
   885  // otherwise it will only be released from Juju's control.
   886  func (a *StorageAPI) Remove(args params.RemoveStorage) (params.ErrorResults, error) {
   887  	return a.remove(args)
   888  }
   889  
   890  func (a *StorageAPI) remove(args params.RemoveStorage) (params.ErrorResults, error) {
   891  	if err := a.checkCanWrite(); err != nil {
   892  		return params.ErrorResults{}, errors.Trace(err)
   893  	}
   894  
   895  	blockChecker := common.NewBlockChecker(a.backend)
   896  	if err := blockChecker.RemoveAllowed(); err != nil {
   897  		return params.ErrorResults{}, errors.Trace(err)
   898  	}
   899  
   900  	result := make([]params.ErrorResult, len(args.Storage))
   901  	for i, arg := range args.Storage {
   902  		tag, err := names.ParseStorageTag(arg.Tag)
   903  		if err != nil {
   904  			result[i].Error = common.ServerError(err)
   905  			continue
   906  		}
   907  		remove := a.storageAccess.DestroyStorageInstance
   908  		if !arg.DestroyStorage {
   909  			remove = a.storageAccess.ReleaseStorageInstance
   910  		}
   911  		result[i].Error = common.ServerError(
   912  			remove(tag, arg.DestroyAttachments),
   913  		)
   914  	}
   915  	return params.ErrorResults{result}, nil
   916  }
   917  
   918  // Detach sets the specified storage attachments to Dying, unless they are
   919  // already Dying or Dead. Any associated, persistent storage will remain
   920  // alive.
   921  func (a *StorageAPI) Detach(args params.StorageAttachmentIds) (params.ErrorResults, error) {
   922  	if err := a.checkCanWrite(); err != nil {
   923  		return params.ErrorResults{}, errors.Trace(err)
   924  	}
   925  
   926  	blockChecker := common.NewBlockChecker(a.backend)
   927  	if err := blockChecker.ChangeAllowed(); err != nil {
   928  		return params.ErrorResults{}, errors.Trace(err)
   929  	}
   930  
   931  	detachOne := func(arg params.StorageAttachmentId) error {
   932  		storageTag, err := names.ParseStorageTag(arg.StorageTag)
   933  		if err != nil {
   934  			return err
   935  		}
   936  		var unitTag names.UnitTag
   937  		if arg.UnitTag != "" {
   938  			var err error
   939  			unitTag, err = names.ParseUnitTag(arg.UnitTag)
   940  			if err != nil {
   941  				return err
   942  			}
   943  		}
   944  		return a.detachStorage(storageTag, unitTag)
   945  	}
   946  
   947  	result := make([]params.ErrorResult, len(args.Ids))
   948  	for i, arg := range args.Ids {
   949  		result[i].Error = common.ServerError(detachOne(arg))
   950  	}
   951  	return params.ErrorResults{result}, nil
   952  }
   953  
   954  func (a *StorageAPI) detachStorage(storageTag names.StorageTag, unitTag names.UnitTag) error {
   955  	if unitTag != (names.UnitTag{}) {
   956  		// The caller has specified a unit explicitly. Do
   957  		// not filter out "not found" errors in this case.
   958  		return a.storageAccess.DetachStorage(storageTag, unitTag)
   959  	}
   960  	attachments, err := a.storageAccess.StorageAttachments(storageTag)
   961  	if err != nil {
   962  		return errors.Trace(err)
   963  	}
   964  	if len(attachments) == 0 {
   965  		// No attachments: check if the storage exists at all.
   966  		if _, err := a.storageAccess.StorageInstance(storageTag); err != nil {
   967  			return errors.Trace(err)
   968  		}
   969  	}
   970  	for _, att := range attachments {
   971  		if att.Life() != state.Alive {
   972  			continue
   973  		}
   974  		err := a.storageAccess.DetachStorage(storageTag, att.Unit())
   975  		if err != nil && !errors.IsNotFound(err) {
   976  			// We only care about NotFound errors if
   977  			// the user specified a unit explicitly.
   978  			return errors.Trace(err)
   979  		}
   980  	}
   981  	return nil
   982  }
   983  
   984  // Attach attaches existing storage instances to units.
   985  // A "CHANGE" block can block this operation.
   986  func (a *StorageAPI) Attach(args params.StorageAttachmentIds) (params.ErrorResults, error) {
   987  	if err := a.checkCanWrite(); err != nil {
   988  		return params.ErrorResults{}, errors.Trace(err)
   989  	}
   990  
   991  	blockChecker := common.NewBlockChecker(a.backend)
   992  	if err := blockChecker.ChangeAllowed(); err != nil {
   993  		return params.ErrorResults{}, errors.Trace(err)
   994  	}
   995  
   996  	attachOne := func(arg params.StorageAttachmentId) error {
   997  		storageTag, err := names.ParseStorageTag(arg.StorageTag)
   998  		if err != nil {
   999  			return err
  1000  		}
  1001  		unitTag, err := names.ParseUnitTag(arg.UnitTag)
  1002  		if err != nil {
  1003  			return err
  1004  		}
  1005  		return a.attachStorage(storageTag, unitTag)
  1006  	}
  1007  
  1008  	result := make([]params.ErrorResult, len(args.Ids))
  1009  	for i, arg := range args.Ids {
  1010  		result[i].Error = common.ServerError(attachOne(arg))
  1011  	}
  1012  	return params.ErrorResults{Results: result}, nil
  1013  }
  1014  
  1015  func (a *StorageAPI) attachStorage(storageTag names.StorageTag, unitTag names.UnitTag) error {
  1016  	return a.storageAccess.AttachStorage(storageTag, unitTag)
  1017  }
  1018  
  1019  // Import imports existing storage into the model.
  1020  // A "CHANGE" block can block this operation.
  1021  func (a *StorageAPI) Import(args params.BulkImportStorageParams) (params.ImportStorageResults, error) {
  1022  	if err := a.checkCanWrite(); err != nil {
  1023  		return params.ImportStorageResults{}, errors.Trace(err)
  1024  	}
  1025  
  1026  	blockChecker := common.NewBlockChecker(a.backend)
  1027  	if err := blockChecker.ChangeAllowed(); err != nil {
  1028  		return params.ImportStorageResults{}, errors.Trace(err)
  1029  	}
  1030  
  1031  	results := make([]params.ImportStorageResult, len(args.Storage))
  1032  	for i, arg := range args.Storage {
  1033  		details, err := a.importStorage(arg)
  1034  		if err != nil {
  1035  			results[i].Error = common.ServerError(err)
  1036  			continue
  1037  		}
  1038  		results[i].Result = details
  1039  	}
  1040  	return params.ImportStorageResults{Results: results}, nil
  1041  }
  1042  
  1043  func (a *StorageAPI) importStorage(arg params.ImportStorageParams) (*params.ImportStorageDetails, error) {
  1044  	if arg.Kind != params.StorageKindFilesystem {
  1045  		// TODO(axw) implement support for volumes.
  1046  		return nil, errors.NotSupportedf("storage kind %q", arg.Kind.String())
  1047  	}
  1048  	if !storage.IsValidPoolName(arg.Pool) {
  1049  		return nil, errors.NotValidf("pool name %q", arg.Pool)
  1050  	}
  1051  
  1052  	cfg, err := a.poolManager.Get(arg.Pool)
  1053  	if errors.IsNotFound(err) {
  1054  		cfg, err = storage.NewConfig(
  1055  			arg.Pool,
  1056  			storage.ProviderType(arg.Pool),
  1057  			map[string]interface{}{},
  1058  		)
  1059  		if err != nil {
  1060  			return nil, errors.Trace(err)
  1061  		}
  1062  	} else if err != nil {
  1063  		return nil, errors.Trace(err)
  1064  	}
  1065  	provider, err := a.registry.StorageProvider(cfg.Provider())
  1066  	if err != nil {
  1067  		return nil, errors.Trace(err)
  1068  	}
  1069  	return a.importFilesystem(arg, provider, cfg)
  1070  }
  1071  
  1072  func (a *StorageAPI) importFilesystem(
  1073  	arg params.ImportStorageParams,
  1074  	provider storage.Provider,
  1075  	cfg *storage.Config,
  1076  ) (*params.ImportStorageDetails, error) {
  1077  	resourceTags := map[string]string{
  1078  		tags.JujuModel:      a.backend.ModelTag().Id(),
  1079  		tags.JujuController: a.backend.ControllerTag().Id(),
  1080  	}
  1081  	var volumeInfo *state.VolumeInfo
  1082  	filesystemInfo := state.FilesystemInfo{Pool: arg.Pool}
  1083  
  1084  	// If the storage provider supports filesystems, import the filesystem,
  1085  	// otherwise import a volume which will back a filesystem.
  1086  	if provider.Supports(storage.StorageKindFilesystem) {
  1087  		filesystemSource, err := provider.FilesystemSource(cfg)
  1088  		if err != nil {
  1089  			return nil, errors.Trace(err)
  1090  		}
  1091  		filesystemImporter, ok := filesystemSource.(storage.FilesystemImporter)
  1092  		if !ok {
  1093  			return nil, errors.NotSupportedf(
  1094  				"importing filesystem with storage provider %q",
  1095  				cfg.Provider(),
  1096  			)
  1097  		}
  1098  		info, err := filesystemImporter.ImportFilesystem(a.callContext, arg.ProviderId, resourceTags)
  1099  		if err != nil {
  1100  			return nil, errors.Annotate(err, "importing filesystem")
  1101  		}
  1102  		filesystemInfo.FilesystemId = arg.ProviderId
  1103  		filesystemInfo.Size = info.Size
  1104  	} else {
  1105  		volumeSource, err := provider.VolumeSource(cfg)
  1106  		if err != nil {
  1107  			return nil, errors.Trace(err)
  1108  		}
  1109  		volumeImporter, ok := volumeSource.(storage.VolumeImporter)
  1110  		if !ok {
  1111  			return nil, errors.NotSupportedf(
  1112  				"importing volume with storage provider %q",
  1113  				cfg.Provider(),
  1114  			)
  1115  		}
  1116  		info, err := volumeImporter.ImportVolume(a.callContext, arg.ProviderId, resourceTags)
  1117  		if err != nil {
  1118  			return nil, errors.Annotate(err, "importing volume")
  1119  		}
  1120  		volumeInfo = &state.VolumeInfo{
  1121  			HardwareId: info.HardwareId,
  1122  			WWN:        info.WWN,
  1123  			Size:       info.Size,
  1124  			Pool:       arg.Pool,
  1125  			VolumeId:   info.VolumeId,
  1126  			Persistent: info.Persistent,
  1127  		}
  1128  		filesystemInfo.Size = info.Size
  1129  	}
  1130  
  1131  	storageTag, err := a.storageAccess.FilesystemAccess().AddExistingFilesystem(filesystemInfo, volumeInfo, arg.StorageName)
  1132  	if err != nil {
  1133  		return nil, errors.Trace(err)
  1134  	}
  1135  	return &params.ImportStorageDetails{
  1136  		StorageTag: storageTag.String(),
  1137  	}, nil
  1138  }
  1139  
  1140  // RemovePool deletes the named pool
  1141  func (a *StorageAPI) RemovePool(p params.StoragePoolDeleteArgs) (params.ErrorResults, error) {
  1142  	results := params.ErrorResults{
  1143  		Results: make([]params.ErrorResult, len(p.Pools)),
  1144  	}
  1145  	if err := a.checkCanWrite(); err != nil {
  1146  		return results, errors.Trace(err)
  1147  	}
  1148  	for i, pool := range p.Pools {
  1149  		err := a.poolManager.Delete(pool.Name)
  1150  		if err != nil {
  1151  			results.Results[i].Error = common.ServerError(err)
  1152  		}
  1153  
  1154  	}
  1155  	return results, nil
  1156  }
  1157  
  1158  // UpdatePool deletes the named pool
  1159  func (a *StorageAPI) UpdatePool(p params.StoragePoolArgs) (params.ErrorResults, error) {
  1160  	results := params.ErrorResults{
  1161  		Results: make([]params.ErrorResult, len(p.Pools)),
  1162  	}
  1163  	if err := a.checkCanWrite(); err != nil {
  1164  		return results, errors.Trace(err)
  1165  	}
  1166  	for i, pool := range p.Pools {
  1167  		err := a.poolManager.Replace(pool.Name, pool.Provider, pool.Attrs)
  1168  		if err != nil {
  1169  			results.Results[i].Error = common.ServerError(err)
  1170  		}
  1171  	}
  1172  	return results, nil
  1173  }
  1174  
  1175  // Mask out old methods from the new API versions. The API reflection
  1176  // code in rpc/rpcreflect/type.go:newMethod skips 2-argument methods,
  1177  // so this removes the method as far as the RPC machinery is concerned.
  1178  
  1179  // Added in current api version
  1180  func (*StorageAPIv4) RemovePool(_, _ struct{}) {}
  1181  func (*StorageAPIv4) UpdatePool(_, _ struct{}) {}
  1182  
  1183  // Added in v4
  1184  // Destroy was dropped in V4, replaced with Remove.
  1185  func (*StorageAPIv3) Remove(_, _ struct{})           {}
  1186  func (*StorageAPIv3) Import(_, _ struct{})           {}
  1187  func (*StorageAPIv3) importStorage(_, _ struct{})    {}
  1188  func (*StorageAPIv3) importFilesystem(_, _ struct{}) {}
  1189  
  1190  // Destroy sets the specified storage entities to Dying, unless they are
  1191  // already Dying or Dead.
  1192  func (a *StorageAPIv3) Destroy(args params.Entities) (params.ErrorResults, error) {
  1193  	v4Args := params.RemoveStorage{
  1194  		Storage: make([]params.RemoveStorageInstance, len(args.Entities)),
  1195  	}
  1196  	for i, arg := range args.Entities {
  1197  		v4Args.Storage[i] = params.RemoveStorageInstance{
  1198  			Tag: arg.Tag,
  1199  			// The v3 behaviour was to detach the storage
  1200  			// at the same time as marking the storage Dying.
  1201  			DestroyAttachments: true,
  1202  			DestroyStorage:     true,
  1203  		}
  1204  	}
  1205  	return a.remove(v4Args)
  1206  }