github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/apiserver/storageprovisioner/storageprovisioner.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storageprovisioner
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/names"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/state"
    14  	"github.com/juju/juju/state/watcher"
    15  	"github.com/juju/juju/storage"
    16  	"github.com/juju/juju/storage/poolmanager"
    17  )
    18  
    19  var logger = loggo.GetLogger("juju.apiserver.storageprovisioner")
    20  
    21  func init() {
    22  	common.RegisterStandardFacade("StorageProvisioner", 1, NewStorageProvisionerAPI)
    23  }
    24  
    25  // StorageProvisionerAPI provides access to the Provisioner API facade.
    26  type StorageProvisionerAPI struct {
    27  	*common.LifeGetter
    28  	*common.DeadEnsurer
    29  	*common.EnvironWatcher
    30  	*common.InstanceIdGetter
    31  
    32  	st                       provisionerState
    33  	settings                 poolmanager.SettingsManager
    34  	resources                *common.Resources
    35  	authorizer               common.Authorizer
    36  	getScopeAuthFunc         common.GetAuthFunc
    37  	getStorageEntityAuthFunc common.GetAuthFunc
    38  	getMachineAuthFunc       common.GetAuthFunc
    39  	getBlockDevicesAuthFunc  common.GetAuthFunc
    40  	getAttachmentAuthFunc    func() (func(names.MachineTag, names.Tag) bool, error)
    41  }
    42  
    43  var getState = func(st *state.State) provisionerState {
    44  	return stateShim{st}
    45  }
    46  
    47  var getSettingsManager = func(st *state.State) poolmanager.SettingsManager {
    48  	return state.NewStateSettings(st)
    49  }
    50  
    51  // NewStorageProvisionerAPI creates a new server-side StorageProvisionerAPI facade.
    52  func NewStorageProvisionerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*StorageProvisionerAPI, error) {
    53  	if !authorizer.AuthMachineAgent() {
    54  		return nil, common.ErrPerm
    55  	}
    56  	canAccessStorageMachine := func(tag names.MachineTag, allowEnvironManager bool) bool {
    57  		authEntityTag := authorizer.GetAuthTag()
    58  		if tag == authEntityTag {
    59  			// Machine agents can access volumes
    60  			// scoped to their own machine.
    61  			return true
    62  		}
    63  		parentId := state.ParentId(tag.Id())
    64  		if parentId == "" {
    65  			return allowEnvironManager && authorizer.AuthEnvironManager()
    66  		}
    67  		// All containers with the authenticated
    68  		// machine as a parent are accessible by it.
    69  		return names.NewMachineTag(parentId) == authEntityTag
    70  	}
    71  	getScopeAuthFunc := func() (common.AuthFunc, error) {
    72  		return func(tag names.Tag) bool {
    73  			switch tag := tag.(type) {
    74  			case names.EnvironTag:
    75  				// Environment managers can access all volumes
    76  				// and filesystems scoped to the environment.
    77  				isEnvironManager := authorizer.AuthEnvironManager()
    78  				return isEnvironManager && tag == st.EnvironTag()
    79  			case names.MachineTag:
    80  				return canAccessStorageMachine(tag, false)
    81  			default:
    82  				return false
    83  			}
    84  		}, nil
    85  	}
    86  	canAccessStorageEntity := func(tag names.Tag, allowMachines bool) bool {
    87  		switch tag := tag.(type) {
    88  		case names.VolumeTag:
    89  			machineTag, ok := names.VolumeMachine(tag)
    90  			if ok {
    91  				return canAccessStorageMachine(machineTag, false)
    92  			}
    93  			return authorizer.AuthEnvironManager()
    94  		case names.FilesystemTag:
    95  			machineTag, ok := names.FilesystemMachine(tag)
    96  			if ok {
    97  				return canAccessStorageMachine(machineTag, false)
    98  			}
    99  			return authorizer.AuthEnvironManager()
   100  		case names.MachineTag:
   101  			return allowMachines && canAccessStorageMachine(tag, true)
   102  		default:
   103  			return false
   104  		}
   105  	}
   106  	getStorageEntityAuthFunc := func() (common.AuthFunc, error) {
   107  		return func(tag names.Tag) bool {
   108  			return canAccessStorageEntity(tag, false)
   109  		}, nil
   110  	}
   111  	getLifeAuthFunc := func() (common.AuthFunc, error) {
   112  		return func(tag names.Tag) bool {
   113  			return canAccessStorageEntity(tag, true)
   114  		}, nil
   115  	}
   116  	getAttachmentAuthFunc := func() (func(names.MachineTag, names.Tag) bool, error) {
   117  		// getAttachmentAuthFunc returns a function that validates
   118  		// access by the authenticated user to an attachment.
   119  		return func(machineTag names.MachineTag, attachmentTag names.Tag) bool {
   120  			// Machine agents can access their own machine, and
   121  			// machines contained. Environment managers can access
   122  			// top-level machines.
   123  			if !canAccessStorageMachine(machineTag, true) {
   124  				return false
   125  			}
   126  			// Environment managers can access environment-scoped
   127  			// volumes and volumes scoped to their own machines.
   128  			// Other machine agents can access volumes regardless
   129  			// of their scope.
   130  			if !authorizer.AuthEnvironManager() {
   131  				return true
   132  			}
   133  			var machineScope names.MachineTag
   134  			var hasMachineScope bool
   135  			switch attachmentTag := attachmentTag.(type) {
   136  			case names.VolumeTag:
   137  				machineScope, hasMachineScope = names.VolumeMachine(attachmentTag)
   138  			case names.FilesystemTag:
   139  				machineScope, hasMachineScope = names.FilesystemMachine(attachmentTag)
   140  			}
   141  			return !hasMachineScope || machineScope == authorizer.GetAuthTag()
   142  		}, nil
   143  	}
   144  	getMachineAuthFunc := func() (common.AuthFunc, error) {
   145  		return func(tag names.Tag) bool {
   146  			if tag, ok := tag.(names.MachineTag); ok {
   147  				return canAccessStorageMachine(tag, true)
   148  			}
   149  			return false
   150  		}, nil
   151  	}
   152  	getBlockDevicesAuthFunc := func() (common.AuthFunc, error) {
   153  		return func(tag names.Tag) bool {
   154  			if tag, ok := tag.(names.MachineTag); ok {
   155  				return canAccessStorageMachine(tag, false)
   156  			}
   157  			return false
   158  		}, nil
   159  	}
   160  	stateInterface := getState(st)
   161  	settings := getSettingsManager(st)
   162  	return &StorageProvisionerAPI{
   163  		LifeGetter:       common.NewLifeGetter(stateInterface, getLifeAuthFunc),
   164  		DeadEnsurer:      common.NewDeadEnsurer(stateInterface, getStorageEntityAuthFunc),
   165  		EnvironWatcher:   common.NewEnvironWatcher(stateInterface, resources, authorizer),
   166  		InstanceIdGetter: common.NewInstanceIdGetter(st, getMachineAuthFunc),
   167  
   168  		st:                       stateInterface,
   169  		settings:                 settings,
   170  		resources:                resources,
   171  		authorizer:               authorizer,
   172  		getScopeAuthFunc:         getScopeAuthFunc,
   173  		getStorageEntityAuthFunc: getStorageEntityAuthFunc,
   174  		getAttachmentAuthFunc:    getAttachmentAuthFunc,
   175  		getMachineAuthFunc:       getMachineAuthFunc,
   176  		getBlockDevicesAuthFunc:  getBlockDevicesAuthFunc,
   177  	}, nil
   178  }
   179  
   180  // WatchBlockDevices watches for changes to the specified machines' block devices.
   181  func (s *StorageProvisionerAPI) WatchBlockDevices(args params.Entities) (params.NotifyWatchResults, error) {
   182  	canAccess, err := s.getBlockDevicesAuthFunc()
   183  	if err != nil {
   184  		return params.NotifyWatchResults{}, common.ServerError(common.ErrPerm)
   185  	}
   186  	results := params.NotifyWatchResults{
   187  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   188  	}
   189  	one := func(arg params.Entity) (string, error) {
   190  		machineTag, err := names.ParseMachineTag(arg.Tag)
   191  		if err != nil {
   192  			return "", err
   193  		}
   194  		if !canAccess(machineTag) {
   195  			return "", common.ErrPerm
   196  		}
   197  		w := s.st.WatchBlockDevices(machineTag)
   198  		if _, ok := <-w.Changes(); ok {
   199  			return s.resources.Register(w), nil
   200  		}
   201  		return "", watcher.EnsureErr(w)
   202  	}
   203  	for i, arg := range args.Entities {
   204  		var result params.NotifyWatchResult
   205  		id, err := one(arg)
   206  		if err != nil {
   207  			result.Error = common.ServerError(err)
   208  		} else {
   209  			result.NotifyWatcherId = id
   210  		}
   211  		results.Results[i] = result
   212  	}
   213  	return results, nil
   214  }
   215  
   216  // WatchMachines watches for changes to the specified machines.
   217  func (s *StorageProvisionerAPI) WatchMachines(args params.Entities) (params.NotifyWatchResults, error) {
   218  	canAccess, err := s.getMachineAuthFunc()
   219  	if err != nil {
   220  		return params.NotifyWatchResults{}, common.ServerError(common.ErrPerm)
   221  	}
   222  	results := params.NotifyWatchResults{
   223  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   224  	}
   225  	one := func(arg params.Entity) (string, error) {
   226  		machineTag, err := names.ParseMachineTag(arg.Tag)
   227  		if err != nil {
   228  			return "", err
   229  		}
   230  		if !canAccess(machineTag) {
   231  			return "", common.ErrPerm
   232  		}
   233  		w, err := s.st.WatchMachine(machineTag)
   234  		if err != nil {
   235  			return "", errors.Trace(err)
   236  		}
   237  		if _, ok := <-w.Changes(); ok {
   238  			return s.resources.Register(w), nil
   239  		}
   240  		return "", watcher.EnsureErr(w)
   241  	}
   242  	for i, arg := range args.Entities {
   243  		var result params.NotifyWatchResult
   244  		id, err := one(arg)
   245  		if err != nil {
   246  			result.Error = common.ServerError(err)
   247  		} else {
   248  			result.NotifyWatcherId = id
   249  		}
   250  		results.Results[i] = result
   251  	}
   252  	return results, nil
   253  }
   254  
   255  // WatchVolumes watches for changes to volumes scoped to the
   256  // entity with the tag passed to NewState.
   257  func (s *StorageProvisionerAPI) WatchVolumes(args params.Entities) (params.StringsWatchResults, error) {
   258  	return s.watchStorageEntities(args, s.st.WatchEnvironVolumes, s.st.WatchMachineVolumes)
   259  }
   260  
   261  // WatchFilesystems watches for changes to filesystems scoped
   262  // to the entity with the tag passed to NewState.
   263  func (s *StorageProvisionerAPI) WatchFilesystems(args params.Entities) (params.StringsWatchResults, error) {
   264  	return s.watchStorageEntities(args, s.st.WatchEnvironFilesystems, s.st.WatchMachineFilesystems)
   265  }
   266  
   267  func (s *StorageProvisionerAPI) watchStorageEntities(
   268  	args params.Entities,
   269  	watchEnvironStorage func() state.StringsWatcher,
   270  	watchMachineStorage func(names.MachineTag) state.StringsWatcher,
   271  ) (params.StringsWatchResults, error) {
   272  	canAccess, err := s.getScopeAuthFunc()
   273  	if err != nil {
   274  		return params.StringsWatchResults{}, common.ServerError(common.ErrPerm)
   275  	}
   276  	results := params.StringsWatchResults{
   277  		Results: make([]params.StringsWatchResult, len(args.Entities)),
   278  	}
   279  	one := func(arg params.Entity) (string, []string, error) {
   280  		tag, err := names.ParseTag(arg.Tag)
   281  		if err != nil || !canAccess(tag) {
   282  			return "", nil, common.ErrPerm
   283  		}
   284  		var w state.StringsWatcher
   285  		if tag, ok := tag.(names.MachineTag); ok {
   286  			w = watchMachineStorage(tag)
   287  		} else {
   288  			w = watchEnvironStorage()
   289  		}
   290  		if changes, ok := <-w.Changes(); ok {
   291  			return s.resources.Register(w), changes, nil
   292  		}
   293  		return "", nil, watcher.EnsureErr(w)
   294  	}
   295  	for i, arg := range args.Entities {
   296  		var result params.StringsWatchResult
   297  		id, changes, err := one(arg)
   298  		if err != nil {
   299  			result.Error = common.ServerError(err)
   300  		} else {
   301  			result.StringsWatcherId = id
   302  			result.Changes = changes
   303  		}
   304  		results.Results[i] = result
   305  	}
   306  	return results, nil
   307  }
   308  
   309  // WatchVolumeAttachments watches for changes to volume attachments scoped to
   310  // the entity with the tag passed to NewState.
   311  func (s *StorageProvisionerAPI) WatchVolumeAttachments(args params.Entities) (params.MachineStorageIdsWatchResults, error) {
   312  	return s.watchAttachments(
   313  		args,
   314  		s.st.WatchEnvironVolumeAttachments,
   315  		s.st.WatchMachineVolumeAttachments,
   316  		common.ParseVolumeAttachmentIds,
   317  	)
   318  }
   319  
   320  // WatchFilesystemAttachments watches for changes to filesystem attachments
   321  // scoped to the entity with the tag passed to NewState.
   322  func (s *StorageProvisionerAPI) WatchFilesystemAttachments(args params.Entities) (params.MachineStorageIdsWatchResults, error) {
   323  	return s.watchAttachments(
   324  		args,
   325  		s.st.WatchEnvironFilesystemAttachments,
   326  		s.st.WatchMachineFilesystemAttachments,
   327  		common.ParseFilesystemAttachmentIds,
   328  	)
   329  }
   330  
   331  func (s *StorageProvisionerAPI) watchAttachments(
   332  	args params.Entities,
   333  	watchEnvironAttachments func() state.StringsWatcher,
   334  	watchMachineAttachments func(names.MachineTag) state.StringsWatcher,
   335  	parseAttachmentIds func([]string) ([]params.MachineStorageId, error),
   336  ) (params.MachineStorageIdsWatchResults, error) {
   337  	canAccess, err := s.getScopeAuthFunc()
   338  	if err != nil {
   339  		return params.MachineStorageIdsWatchResults{}, common.ServerError(common.ErrPerm)
   340  	}
   341  	results := params.MachineStorageIdsWatchResults{
   342  		Results: make([]params.MachineStorageIdsWatchResult, len(args.Entities)),
   343  	}
   344  	one := func(arg params.Entity) (string, []params.MachineStorageId, error) {
   345  		tag, err := names.ParseTag(arg.Tag)
   346  		if err != nil || !canAccess(tag) {
   347  			return "", nil, common.ErrPerm
   348  		}
   349  		var w state.StringsWatcher
   350  		if tag, ok := tag.(names.MachineTag); ok {
   351  			w = watchMachineAttachments(tag)
   352  		} else {
   353  			w = watchEnvironAttachments()
   354  		}
   355  		if stringChanges, ok := <-w.Changes(); ok {
   356  			changes, err := parseAttachmentIds(stringChanges)
   357  			if err != nil {
   358  				w.Stop()
   359  				return "", nil, err
   360  			}
   361  			return s.resources.Register(w), changes, nil
   362  		}
   363  		return "", nil, watcher.EnsureErr(w)
   364  	}
   365  	for i, arg := range args.Entities {
   366  		var result params.MachineStorageIdsWatchResult
   367  		id, changes, err := one(arg)
   368  		if err != nil {
   369  			result.Error = common.ServerError(err)
   370  		} else {
   371  			result.MachineStorageIdsWatcherId = id
   372  			result.Changes = changes
   373  		}
   374  		results.Results[i] = result
   375  	}
   376  	return results, nil
   377  }
   378  
   379  // Volumes returns details of volumes with the specified tags.
   380  func (s *StorageProvisionerAPI) Volumes(args params.Entities) (params.VolumeResults, error) {
   381  	canAccess, err := s.getStorageEntityAuthFunc()
   382  	if err != nil {
   383  		return params.VolumeResults{}, common.ServerError(common.ErrPerm)
   384  	}
   385  	results := params.VolumeResults{
   386  		Results: make([]params.VolumeResult, len(args.Entities)),
   387  	}
   388  	one := func(arg params.Entity) (params.Volume, error) {
   389  		tag, err := names.ParseVolumeTag(arg.Tag)
   390  		if err != nil || !canAccess(tag) {
   391  			return params.Volume{}, common.ErrPerm
   392  		}
   393  		volume, err := s.st.Volume(tag)
   394  		if errors.IsNotFound(err) {
   395  			return params.Volume{}, common.ErrPerm
   396  		} else if err != nil {
   397  			return params.Volume{}, err
   398  		}
   399  		return common.VolumeFromState(volume)
   400  	}
   401  	for i, arg := range args.Entities {
   402  		var result params.VolumeResult
   403  		volume, err := one(arg)
   404  		if err != nil {
   405  			result.Error = common.ServerError(err)
   406  		} else {
   407  			result.Result = volume
   408  		}
   409  		results.Results[i] = result
   410  	}
   411  	return results, nil
   412  }
   413  
   414  // Filesystems returns details of filesystems with the specified tags.
   415  func (s *StorageProvisionerAPI) Filesystems(args params.Entities) (params.FilesystemResults, error) {
   416  	canAccess, err := s.getStorageEntityAuthFunc()
   417  	if err != nil {
   418  		return params.FilesystemResults{}, common.ServerError(common.ErrPerm)
   419  	}
   420  	results := params.FilesystemResults{
   421  		Results: make([]params.FilesystemResult, len(args.Entities)),
   422  	}
   423  	one := func(arg params.Entity) (params.Filesystem, error) {
   424  		tag, err := names.ParseFilesystemTag(arg.Tag)
   425  		if err != nil || !canAccess(tag) {
   426  			return params.Filesystem{}, common.ErrPerm
   427  		}
   428  		filesystem, err := s.st.Filesystem(tag)
   429  		if errors.IsNotFound(err) {
   430  			return params.Filesystem{}, common.ErrPerm
   431  		} else if err != nil {
   432  			return params.Filesystem{}, err
   433  		}
   434  		return common.FilesystemFromState(filesystem)
   435  	}
   436  	for i, arg := range args.Entities {
   437  		var result params.FilesystemResult
   438  		filesystem, err := one(arg)
   439  		if err != nil {
   440  			result.Error = common.ServerError(err)
   441  		} else {
   442  			result.Result = filesystem
   443  		}
   444  		results.Results[i] = result
   445  	}
   446  	return results, nil
   447  }
   448  
   449  // VolumeAttachments returns details of volume attachments with the specified IDs.
   450  func (s *StorageProvisionerAPI) VolumeAttachments(args params.MachineStorageIds) (params.VolumeAttachmentResults, error) {
   451  	canAccess, err := s.getAttachmentAuthFunc()
   452  	if err != nil {
   453  		return params.VolumeAttachmentResults{}, common.ServerError(common.ErrPerm)
   454  	}
   455  	results := params.VolumeAttachmentResults{
   456  		Results: make([]params.VolumeAttachmentResult, len(args.Ids)),
   457  	}
   458  	one := func(arg params.MachineStorageId) (params.VolumeAttachment, error) {
   459  		volumeAttachment, err := s.oneVolumeAttachment(arg, canAccess)
   460  		if err != nil {
   461  			return params.VolumeAttachment{}, err
   462  		}
   463  		return common.VolumeAttachmentFromState(volumeAttachment)
   464  	}
   465  	for i, arg := range args.Ids {
   466  		var result params.VolumeAttachmentResult
   467  		volumeAttachment, err := one(arg)
   468  		if err != nil {
   469  			result.Error = common.ServerError(err)
   470  		} else {
   471  			result.Result = volumeAttachment
   472  		}
   473  		results.Results[i] = result
   474  	}
   475  	return results, nil
   476  }
   477  
   478  // VolumeBlockDevices returns details of the block devices corresponding to the
   479  // volume attachments with the specified IDs.
   480  func (s *StorageProvisionerAPI) VolumeBlockDevices(args params.MachineStorageIds) (params.BlockDeviceResults, error) {
   481  	canAccess, err := s.getAttachmentAuthFunc()
   482  	if err != nil {
   483  		return params.BlockDeviceResults{}, common.ServerError(common.ErrPerm)
   484  	}
   485  	results := params.BlockDeviceResults{
   486  		Results: make([]params.BlockDeviceResult, len(args.Ids)),
   487  	}
   488  	one := func(arg params.MachineStorageId) (storage.BlockDevice, error) {
   489  		stateBlockDevice, err := s.oneVolumeBlockDevice(arg, canAccess)
   490  		if err != nil {
   491  			return storage.BlockDevice{}, err
   492  		}
   493  		return common.BlockDeviceFromState(stateBlockDevice), nil
   494  	}
   495  	for i, arg := range args.Ids {
   496  		var result params.BlockDeviceResult
   497  		blockDevice, err := one(arg)
   498  		if err != nil {
   499  			result.Error = common.ServerError(err)
   500  		} else {
   501  			result.Result = blockDevice
   502  		}
   503  		results.Results[i] = result
   504  	}
   505  	return results, nil
   506  }
   507  
   508  // FilesystemAttachments returns details of filesystem attachments with the specified IDs.
   509  func (s *StorageProvisionerAPI) FilesystemAttachments(args params.MachineStorageIds) (params.FilesystemAttachmentResults, error) {
   510  	canAccess, err := s.getAttachmentAuthFunc()
   511  	if err != nil {
   512  		return params.FilesystemAttachmentResults{}, common.ServerError(common.ErrPerm)
   513  	}
   514  	results := params.FilesystemAttachmentResults{
   515  		Results: make([]params.FilesystemAttachmentResult, len(args.Ids)),
   516  	}
   517  	one := func(arg params.MachineStorageId) (params.FilesystemAttachment, error) {
   518  		filesystemAttachment, err := s.oneFilesystemAttachment(arg, canAccess)
   519  		if err != nil {
   520  			return params.FilesystemAttachment{}, err
   521  		}
   522  		return common.FilesystemAttachmentFromState(filesystemAttachment)
   523  	}
   524  	for i, arg := range args.Ids {
   525  		var result params.FilesystemAttachmentResult
   526  		filesystemAttachment, err := one(arg)
   527  		if err != nil {
   528  			result.Error = common.ServerError(err)
   529  		} else {
   530  			result.Result = filesystemAttachment
   531  		}
   532  		results.Results[i] = result
   533  	}
   534  	return results, nil
   535  }
   536  
   537  // VolumeParams returns the parameters for creating or destroying
   538  // the volumes with the specified tags.
   539  func (s *StorageProvisionerAPI) VolumeParams(args params.Entities) (params.VolumeParamsResults, error) {
   540  	canAccess, err := s.getStorageEntityAuthFunc()
   541  	if err != nil {
   542  		return params.VolumeParamsResults{}, err
   543  	}
   544  	envConfig, err := s.st.EnvironConfig()
   545  	if err != nil {
   546  		return params.VolumeParamsResults{}, err
   547  	}
   548  	results := params.VolumeParamsResults{
   549  		Results: make([]params.VolumeParamsResult, len(args.Entities)),
   550  	}
   551  	poolManager := poolmanager.New(s.settings)
   552  	one := func(arg params.Entity) (params.VolumeParams, error) {
   553  		tag, err := names.ParseVolumeTag(arg.Tag)
   554  		if err != nil || !canAccess(tag) {
   555  			return params.VolumeParams{}, common.ErrPerm
   556  		}
   557  		volume, err := s.st.Volume(tag)
   558  		if errors.IsNotFound(err) {
   559  			return params.VolumeParams{}, common.ErrPerm
   560  		} else if err != nil {
   561  			return params.VolumeParams{}, err
   562  		}
   563  		volumeAttachments, err := s.st.VolumeAttachments(tag)
   564  		if err != nil {
   565  			return params.VolumeParams{}, err
   566  		}
   567  		storageInstance, err := common.MaybeAssignedStorageInstance(
   568  			volume.StorageInstance,
   569  			s.st.StorageInstance,
   570  		)
   571  		if err != nil {
   572  			return params.VolumeParams{}, err
   573  		}
   574  		volumeParams, err := common.VolumeParams(volume, storageInstance, envConfig, poolManager)
   575  		if err != nil {
   576  			return params.VolumeParams{}, err
   577  		}
   578  		if len(volumeAttachments) == 1 {
   579  			// There is exactly one attachment to be made, so make
   580  			// it immediately. Otherwise we will defer attachments
   581  			// until later.
   582  			volumeAttachment := volumeAttachments[0]
   583  			volumeAttachmentParams, ok := volumeAttachment.Params()
   584  			if !ok {
   585  				return params.VolumeParams{}, errors.Errorf(
   586  					"volume %q is already attached to machine %q",
   587  					volumeAttachment.Volume().Id(),
   588  					volumeAttachment.Machine().Id(),
   589  				)
   590  			}
   591  			machineTag := volumeAttachment.Machine()
   592  			instanceId, err := s.st.MachineInstanceId(machineTag)
   593  			if errors.IsNotProvisioned(err) {
   594  				// Leave the attachment until later.
   595  				instanceId = ""
   596  			} else if err != nil {
   597  				return params.VolumeParams{}, err
   598  			}
   599  			volumeParams.Attachment = &params.VolumeAttachmentParams{
   600  				tag.String(),
   601  				machineTag.String(),
   602  				"", // volume ID
   603  				string(instanceId),
   604  				volumeParams.Provider,
   605  				volumeAttachmentParams.ReadOnly,
   606  			}
   607  		}
   608  		return volumeParams, nil
   609  	}
   610  	for i, arg := range args.Entities {
   611  		var result params.VolumeParamsResult
   612  		volumeParams, err := one(arg)
   613  		if err != nil {
   614  			result.Error = common.ServerError(err)
   615  		} else {
   616  			result.Result = volumeParams
   617  		}
   618  		results.Results[i] = result
   619  	}
   620  	return results, nil
   621  }
   622  
   623  // FilesystemParams returns the parameters for creating the filesystems
   624  // with the specified tags.
   625  func (s *StorageProvisionerAPI) FilesystemParams(args params.Entities) (params.FilesystemParamsResults, error) {
   626  	canAccess, err := s.getStorageEntityAuthFunc()
   627  	if err != nil {
   628  		return params.FilesystemParamsResults{}, err
   629  	}
   630  	envConfig, err := s.st.EnvironConfig()
   631  	if err != nil {
   632  		return params.FilesystemParamsResults{}, err
   633  	}
   634  	results := params.FilesystemParamsResults{
   635  		Results: make([]params.FilesystemParamsResult, len(args.Entities)),
   636  	}
   637  	poolManager := poolmanager.New(s.settings)
   638  	one := func(arg params.Entity) (params.FilesystemParams, error) {
   639  		tag, err := names.ParseFilesystemTag(arg.Tag)
   640  		if err != nil || !canAccess(tag) {
   641  			return params.FilesystemParams{}, common.ErrPerm
   642  		}
   643  		filesystem, err := s.st.Filesystem(tag)
   644  		if errors.IsNotFound(err) {
   645  			return params.FilesystemParams{}, common.ErrPerm
   646  		} else if err != nil {
   647  			return params.FilesystemParams{}, err
   648  		}
   649  		storageInstance, err := common.MaybeAssignedStorageInstance(
   650  			filesystem.Storage,
   651  			s.st.StorageInstance,
   652  		)
   653  		if err != nil {
   654  			return params.FilesystemParams{}, err
   655  		}
   656  		filesystemParams, err := common.FilesystemParams(
   657  			filesystem, storageInstance, envConfig, poolManager,
   658  		)
   659  		if err != nil {
   660  			return params.FilesystemParams{}, err
   661  		}
   662  		return filesystemParams, nil
   663  	}
   664  	for i, arg := range args.Entities {
   665  		var result params.FilesystemParamsResult
   666  		filesystemParams, err := one(arg)
   667  		if err != nil {
   668  			result.Error = common.ServerError(err)
   669  		} else {
   670  			result.Result = filesystemParams
   671  		}
   672  		results.Results[i] = result
   673  	}
   674  	return results, nil
   675  }
   676  
   677  // VolumeAttachmentParams returns the parameters for creating the volume
   678  // attachments with the specified IDs.
   679  func (s *StorageProvisionerAPI) VolumeAttachmentParams(
   680  	args params.MachineStorageIds,
   681  ) (params.VolumeAttachmentParamsResults, error) {
   682  	canAccess, err := s.getAttachmentAuthFunc()
   683  	if err != nil {
   684  		return params.VolumeAttachmentParamsResults{}, common.ServerError(common.ErrPerm)
   685  	}
   686  	results := params.VolumeAttachmentParamsResults{
   687  		Results: make([]params.VolumeAttachmentParamsResult, len(args.Ids)),
   688  	}
   689  	poolManager := poolmanager.New(s.settings)
   690  	one := func(arg params.MachineStorageId) (params.VolumeAttachmentParams, error) {
   691  		volumeAttachment, err := s.oneVolumeAttachment(arg, canAccess)
   692  		if err != nil {
   693  			return params.VolumeAttachmentParams{}, err
   694  		}
   695  		instanceId, err := s.st.MachineInstanceId(volumeAttachment.Machine())
   696  		if errors.IsNotProvisioned(err) {
   697  			// The worker must watch for machine provisioning events.
   698  			instanceId = ""
   699  		} else if err != nil {
   700  			return params.VolumeAttachmentParams{}, err
   701  		}
   702  		volume, err := s.st.Volume(volumeAttachment.Volume())
   703  		if err != nil {
   704  			return params.VolumeAttachmentParams{}, err
   705  		}
   706  		var volumeId string
   707  		var pool string
   708  		if volumeParams, ok := volume.Params(); ok {
   709  			pool = volumeParams.Pool
   710  		} else {
   711  			volumeInfo, err := volume.Info()
   712  			if err != nil {
   713  				return params.VolumeAttachmentParams{}, err
   714  			}
   715  			volumeId = volumeInfo.VolumeId
   716  			pool = volumeInfo.Pool
   717  		}
   718  		providerType, _, err := common.StoragePoolConfig(pool, poolManager)
   719  		if err != nil {
   720  			return params.VolumeAttachmentParams{}, errors.Trace(err)
   721  		}
   722  		var readOnly bool
   723  		if volumeAttachmentParams, ok := volumeAttachment.Params(); ok {
   724  			readOnly = volumeAttachmentParams.ReadOnly
   725  		} else {
   726  			// Attachment parameters may be requested even if the
   727  			// attachment exists; i.e. for reattachment.
   728  			volumeAttachmentInfo, err := volumeAttachment.Info()
   729  			if err != nil {
   730  				return params.VolumeAttachmentParams{}, errors.Trace(err)
   731  			}
   732  			readOnly = volumeAttachmentInfo.ReadOnly
   733  		}
   734  		return params.VolumeAttachmentParams{
   735  			volumeAttachment.Volume().String(),
   736  			volumeAttachment.Machine().String(),
   737  			volumeId,
   738  			string(instanceId),
   739  			string(providerType),
   740  			readOnly,
   741  		}, nil
   742  	}
   743  	for i, arg := range args.Ids {
   744  		var result params.VolumeAttachmentParamsResult
   745  		volumeAttachment, err := one(arg)
   746  		if err != nil {
   747  			result.Error = common.ServerError(err)
   748  		} else {
   749  			result.Result = volumeAttachment
   750  		}
   751  		results.Results[i] = result
   752  	}
   753  	return results, nil
   754  }
   755  
   756  // FilesystemAttachmentParams returns the parameters for creating the filesystem
   757  // attachments with the specified IDs.
   758  func (s *StorageProvisionerAPI) FilesystemAttachmentParams(
   759  	args params.MachineStorageIds,
   760  ) (params.FilesystemAttachmentParamsResults, error) {
   761  	canAccess, err := s.getAttachmentAuthFunc()
   762  	if err != nil {
   763  		return params.FilesystemAttachmentParamsResults{}, common.ServerError(common.ErrPerm)
   764  	}
   765  	results := params.FilesystemAttachmentParamsResults{
   766  		Results: make([]params.FilesystemAttachmentParamsResult, len(args.Ids)),
   767  	}
   768  	poolManager := poolmanager.New(s.settings)
   769  	one := func(arg params.MachineStorageId) (params.FilesystemAttachmentParams, error) {
   770  		filesystemAttachment, err := s.oneFilesystemAttachment(arg, canAccess)
   771  		if err != nil {
   772  			return params.FilesystemAttachmentParams{}, err
   773  		}
   774  		instanceId, err := s.st.MachineInstanceId(filesystemAttachment.Machine())
   775  		if errors.IsNotProvisioned(err) {
   776  			// The worker must watch for machine provisioning events.
   777  			instanceId = ""
   778  		} else if err != nil {
   779  			return params.FilesystemAttachmentParams{}, err
   780  		}
   781  		filesystem, err := s.st.Filesystem(filesystemAttachment.Filesystem())
   782  		if err != nil {
   783  			return params.FilesystemAttachmentParams{}, err
   784  		}
   785  		var filesystemId string
   786  		var pool string
   787  		if filesystemParams, ok := filesystem.Params(); ok {
   788  			pool = filesystemParams.Pool
   789  		} else {
   790  			filesystemInfo, err := filesystem.Info()
   791  			if err != nil {
   792  				return params.FilesystemAttachmentParams{}, err
   793  			}
   794  			filesystemId = filesystemInfo.FilesystemId
   795  			pool = filesystemInfo.Pool
   796  		}
   797  		providerType, _, err := common.StoragePoolConfig(pool, poolManager)
   798  		if err != nil {
   799  			return params.FilesystemAttachmentParams{}, errors.Trace(err)
   800  		}
   801  		var location string
   802  		var readOnly bool
   803  		if filesystemAttachmentParams, ok := filesystemAttachment.Params(); ok {
   804  			location = filesystemAttachmentParams.Location
   805  			readOnly = filesystemAttachmentParams.ReadOnly
   806  		} else {
   807  			// Attachment parameters may be requested even if the
   808  			// attachment exists; i.e. for reattachment.
   809  			filesystemAttachmentInfo, err := filesystemAttachment.Info()
   810  			if err != nil {
   811  				return params.FilesystemAttachmentParams{}, errors.Trace(err)
   812  			}
   813  			location = filesystemAttachmentInfo.MountPoint
   814  			readOnly = filesystemAttachmentInfo.ReadOnly
   815  		}
   816  		return params.FilesystemAttachmentParams{
   817  			filesystemAttachment.Filesystem().String(),
   818  			filesystemAttachment.Machine().String(),
   819  			filesystemId,
   820  			string(instanceId),
   821  			string(providerType),
   822  			// TODO(axw) dealias MountPoint. We now have
   823  			// Path, MountPoint and Location in different
   824  			// parts of the codebase.
   825  			location,
   826  			readOnly,
   827  		}, nil
   828  	}
   829  	for i, arg := range args.Ids {
   830  		var result params.FilesystemAttachmentParamsResult
   831  		filesystemAttachment, err := one(arg)
   832  		if err != nil {
   833  			result.Error = common.ServerError(err)
   834  		} else {
   835  			result.Result = filesystemAttachment
   836  		}
   837  		results.Results[i] = result
   838  	}
   839  	return results, nil
   840  }
   841  
   842  func (s *StorageProvisionerAPI) oneVolumeAttachment(
   843  	id params.MachineStorageId, canAccess func(names.MachineTag, names.Tag) bool,
   844  ) (state.VolumeAttachment, error) {
   845  	machineTag, err := names.ParseMachineTag(id.MachineTag)
   846  	if err != nil {
   847  		return nil, err
   848  	}
   849  	volumeTag, err := names.ParseVolumeTag(id.AttachmentTag)
   850  	if err != nil {
   851  		return nil, err
   852  	}
   853  	if !canAccess(machineTag, volumeTag) {
   854  		return nil, common.ErrPerm
   855  	}
   856  	volumeAttachment, err := s.st.VolumeAttachment(machineTag, volumeTag)
   857  	if errors.IsNotFound(err) {
   858  		return nil, common.ErrPerm
   859  	} else if err != nil {
   860  		return nil, err
   861  	}
   862  	return volumeAttachment, nil
   863  }
   864  
   865  func (s *StorageProvisionerAPI) oneVolumeBlockDevice(
   866  	id params.MachineStorageId, canAccess func(names.MachineTag, names.Tag) bool,
   867  ) (state.BlockDeviceInfo, error) {
   868  	volumeAttachment, err := s.oneVolumeAttachment(id, canAccess)
   869  	if err != nil {
   870  		return state.BlockDeviceInfo{}, err
   871  	}
   872  	volume, err := s.st.Volume(volumeAttachment.Volume())
   873  	if err != nil {
   874  		return state.BlockDeviceInfo{}, err
   875  	}
   876  	volumeInfo, err := volume.Info()
   877  	if err != nil {
   878  		return state.BlockDeviceInfo{}, err
   879  	}
   880  	volumeAttachmentInfo, err := volumeAttachment.Info()
   881  	if err != nil {
   882  		return state.BlockDeviceInfo{}, err
   883  	}
   884  	blockDevices, err := s.st.BlockDevices(volumeAttachment.Machine())
   885  	if err != nil {
   886  		return state.BlockDeviceInfo{}, err
   887  	}
   888  	blockDevice, ok := common.MatchingBlockDevice(
   889  		blockDevices,
   890  		volumeInfo,
   891  		volumeAttachmentInfo,
   892  	)
   893  	if !ok {
   894  		return state.BlockDeviceInfo{}, errors.NotFoundf(
   895  			"block device for volume %v on machine %v",
   896  			volumeAttachment.Volume().Id(),
   897  			volumeAttachment.Machine().Id(),
   898  		)
   899  	}
   900  	return *blockDevice, nil
   901  }
   902  
   903  func (s *StorageProvisionerAPI) oneFilesystemAttachment(
   904  	id params.MachineStorageId, canAccess func(names.MachineTag, names.Tag) bool,
   905  ) (state.FilesystemAttachment, error) {
   906  	machineTag, err := names.ParseMachineTag(id.MachineTag)
   907  	if err != nil {
   908  		return nil, err
   909  	}
   910  	filesystemTag, err := names.ParseFilesystemTag(id.AttachmentTag)
   911  	if err != nil {
   912  		return nil, err
   913  	}
   914  	if !canAccess(machineTag, filesystemTag) {
   915  		return nil, common.ErrPerm
   916  	}
   917  	filesystemAttachment, err := s.st.FilesystemAttachment(machineTag, filesystemTag)
   918  	if errors.IsNotFound(err) {
   919  		return nil, common.ErrPerm
   920  	} else if err != nil {
   921  		return nil, err
   922  	}
   923  	return filesystemAttachment, nil
   924  }
   925  
   926  // SetVolumeInfo records the details of newly provisioned volumes.
   927  func (s *StorageProvisionerAPI) SetVolumeInfo(args params.Volumes) (params.ErrorResults, error) {
   928  	canAccessVolume, err := s.getStorageEntityAuthFunc()
   929  	if err != nil {
   930  		return params.ErrorResults{}, err
   931  	}
   932  	results := params.ErrorResults{
   933  		Results: make([]params.ErrorResult, len(args.Volumes)),
   934  	}
   935  	one := func(arg params.Volume) error {
   936  		volumeTag, volumeInfo, err := common.VolumeToState(arg)
   937  		if err != nil {
   938  			return errors.Trace(err)
   939  		} else if !canAccessVolume(volumeTag) {
   940  			return common.ErrPerm
   941  		}
   942  		err = s.st.SetVolumeInfo(volumeTag, volumeInfo)
   943  		if errors.IsNotFound(err) {
   944  			return common.ErrPerm
   945  		}
   946  		return errors.Trace(err)
   947  	}
   948  	for i, arg := range args.Volumes {
   949  		err := one(arg)
   950  		results.Results[i].Error = common.ServerError(err)
   951  	}
   952  	return results, nil
   953  }
   954  
   955  // SetFilesystemInfo records the details of newly provisioned filesystems.
   956  func (s *StorageProvisionerAPI) SetFilesystemInfo(args params.Filesystems) (params.ErrorResults, error) {
   957  	canAccessFilesystem, err := s.getStorageEntityAuthFunc()
   958  	if err != nil {
   959  		return params.ErrorResults{}, err
   960  	}
   961  	results := params.ErrorResults{
   962  		Results: make([]params.ErrorResult, len(args.Filesystems)),
   963  	}
   964  	one := func(arg params.Filesystem) error {
   965  		filesystemTag, filesystemInfo, err := common.FilesystemToState(arg)
   966  		if err != nil {
   967  			return errors.Trace(err)
   968  		} else if !canAccessFilesystem(filesystemTag) {
   969  			return common.ErrPerm
   970  		}
   971  		err = s.st.SetFilesystemInfo(filesystemTag, filesystemInfo)
   972  		if errors.IsNotFound(err) {
   973  			return common.ErrPerm
   974  		}
   975  		return errors.Trace(err)
   976  	}
   977  	for i, arg := range args.Filesystems {
   978  		err := one(arg)
   979  		results.Results[i].Error = common.ServerError(err)
   980  	}
   981  	return results, nil
   982  }
   983  
   984  // SetVolumeAttachmentInfo records the details of newly provisioned volume
   985  // attachments.
   986  func (s *StorageProvisionerAPI) SetVolumeAttachmentInfo(
   987  	args params.VolumeAttachments,
   988  ) (params.ErrorResults, error) {
   989  	canAccess, err := s.getAttachmentAuthFunc()
   990  	if err != nil {
   991  		return params.ErrorResults{}, err
   992  	}
   993  	results := params.ErrorResults{
   994  		Results: make([]params.ErrorResult, len(args.VolumeAttachments)),
   995  	}
   996  	one := func(arg params.VolumeAttachment) error {
   997  		machineTag, volumeTag, volumeAttachmentInfo, err := common.VolumeAttachmentToState(arg)
   998  		if err != nil {
   999  			return errors.Trace(err)
  1000  		}
  1001  		if !canAccess(machineTag, volumeTag) {
  1002  			return common.ErrPerm
  1003  		}
  1004  		err = s.st.SetVolumeAttachmentInfo(machineTag, volumeTag, volumeAttachmentInfo)
  1005  		if errors.IsNotFound(err) {
  1006  			return common.ErrPerm
  1007  		}
  1008  		return errors.Trace(err)
  1009  	}
  1010  	for i, arg := range args.VolumeAttachments {
  1011  		err := one(arg)
  1012  		results.Results[i].Error = common.ServerError(err)
  1013  	}
  1014  	return results, nil
  1015  }
  1016  
  1017  // SetFilesystemAttachmentInfo records the details of newly provisioned filesystem
  1018  // attachments.
  1019  func (s *StorageProvisionerAPI) SetFilesystemAttachmentInfo(
  1020  	args params.FilesystemAttachments,
  1021  ) (params.ErrorResults, error) {
  1022  	canAccess, err := s.getAttachmentAuthFunc()
  1023  	if err != nil {
  1024  		return params.ErrorResults{}, err
  1025  	}
  1026  	results := params.ErrorResults{
  1027  		Results: make([]params.ErrorResult, len(args.FilesystemAttachments)),
  1028  	}
  1029  	one := func(arg params.FilesystemAttachment) error {
  1030  		machineTag, filesystemTag, filesystemAttachmentInfo, err := common.FilesystemAttachmentToState(arg)
  1031  		if err != nil {
  1032  			return errors.Trace(err)
  1033  		}
  1034  		if !canAccess(machineTag, filesystemTag) {
  1035  			return common.ErrPerm
  1036  		}
  1037  		err = s.st.SetFilesystemAttachmentInfo(machineTag, filesystemTag, filesystemAttachmentInfo)
  1038  		if errors.IsNotFound(err) {
  1039  			return common.ErrPerm
  1040  		}
  1041  		return errors.Trace(err)
  1042  	}
  1043  	for i, arg := range args.FilesystemAttachments {
  1044  		err := one(arg)
  1045  		results.Results[i].Error = common.ServerError(err)
  1046  	}
  1047  	return results, nil
  1048  }
  1049  
  1050  // AttachmentLife returns the lifecycle state of each specified machine
  1051  // storage attachment.
  1052  func (s *StorageProvisionerAPI) AttachmentLife(args params.MachineStorageIds) (params.LifeResults, error) {
  1053  	canAccess, err := s.getAttachmentAuthFunc()
  1054  	if err != nil {
  1055  		return params.LifeResults{}, err
  1056  	}
  1057  	results := params.LifeResults{
  1058  		Results: make([]params.LifeResult, len(args.Ids)),
  1059  	}
  1060  	one := func(arg params.MachineStorageId) (params.Life, error) {
  1061  		machineTag, err := names.ParseMachineTag(arg.MachineTag)
  1062  		if err != nil {
  1063  			return "", err
  1064  		}
  1065  		attachmentTag, err := names.ParseTag(arg.AttachmentTag)
  1066  		if err != nil {
  1067  			return "", err
  1068  		}
  1069  		if !canAccess(machineTag, attachmentTag) {
  1070  			return "", common.ErrPerm
  1071  		}
  1072  		var lifer state.Lifer
  1073  		switch attachmentTag := attachmentTag.(type) {
  1074  		case names.VolumeTag:
  1075  			lifer, err = s.st.VolumeAttachment(machineTag, attachmentTag)
  1076  		case names.FilesystemTag:
  1077  			lifer, err = s.st.FilesystemAttachment(machineTag, attachmentTag)
  1078  		}
  1079  		if errors.IsNotFound(err) {
  1080  			return "", common.ErrPerm
  1081  		} else if err != nil {
  1082  			return "", errors.Trace(err)
  1083  		}
  1084  		return params.Life(lifer.Life().String()), nil
  1085  	}
  1086  	for i, arg := range args.Ids {
  1087  		life, err := one(arg)
  1088  		if err != nil {
  1089  			results.Results[i].Error = common.ServerError(err)
  1090  		} else {
  1091  			results.Results[i].Life = life
  1092  		}
  1093  	}
  1094  	return results, nil
  1095  }
  1096  
  1097  // Remove removes volumes and filesystems from state.
  1098  func (s *StorageProvisionerAPI) Remove(args params.Entities) (params.ErrorResults, error) {
  1099  	canAccess, err := s.getStorageEntityAuthFunc()
  1100  	if err != nil {
  1101  		return params.ErrorResults{}, err
  1102  	}
  1103  	results := params.ErrorResults{
  1104  		Results: make([]params.ErrorResult, len(args.Entities)),
  1105  	}
  1106  	one := func(arg params.Entity) error {
  1107  		tag, err := names.ParseTag(arg.Tag)
  1108  		if err != nil {
  1109  			return errors.Trace(err)
  1110  		}
  1111  		if !canAccess(tag) {
  1112  			return common.ErrPerm
  1113  		}
  1114  		switch tag := tag.(type) {
  1115  		case names.FilesystemTag:
  1116  			return s.st.RemoveFilesystem(tag)
  1117  		case names.VolumeTag:
  1118  			return s.st.RemoveVolume(tag)
  1119  		default:
  1120  			// should have been picked up by canAccess
  1121  			logger.Debugf("unexpected %v tag", tag.Kind())
  1122  			return common.ErrPerm
  1123  		}
  1124  	}
  1125  	for i, arg := range args.Entities {
  1126  		err := one(arg)
  1127  		results.Results[i].Error = common.ServerError(err)
  1128  	}
  1129  	return results, nil
  1130  }
  1131  
  1132  // RemoveAttachments removes the specified machine storage attachments
  1133  // from state.
  1134  func (s *StorageProvisionerAPI) RemoveAttachment(args params.MachineStorageIds) (params.ErrorResults, error) {
  1135  	canAccess, err := s.getAttachmentAuthFunc()
  1136  	if err != nil {
  1137  		return params.ErrorResults{}, err
  1138  	}
  1139  	results := params.ErrorResults{
  1140  		Results: make([]params.ErrorResult, len(args.Ids)),
  1141  	}
  1142  	removeAttachment := func(arg params.MachineStorageId) error {
  1143  		machineTag, err := names.ParseMachineTag(arg.MachineTag)
  1144  		if err != nil {
  1145  			return err
  1146  		}
  1147  		attachmentTag, err := names.ParseTag(arg.AttachmentTag)
  1148  		if err != nil {
  1149  			return err
  1150  		}
  1151  		if !canAccess(machineTag, attachmentTag) {
  1152  			return common.ErrPerm
  1153  		}
  1154  		switch attachmentTag := attachmentTag.(type) {
  1155  		case names.VolumeTag:
  1156  			return s.st.RemoveVolumeAttachment(machineTag, attachmentTag)
  1157  		case names.FilesystemTag:
  1158  			return s.st.RemoveFilesystemAttachment(machineTag, attachmentTag)
  1159  		default:
  1160  			return common.ErrPerm
  1161  		}
  1162  	}
  1163  	for i, arg := range args.Ids {
  1164  		if err := removeAttachment(arg); err != nil {
  1165  			results.Results[i].Error = common.ServerError(err)
  1166  		}
  1167  	}
  1168  	return results, nil
  1169  }