// AttachFilesystems is specified on the storage.FilesystemSource interface.
350185
func (s *lxdFilesystemSource) AttachFilesystems(ctx context.ProviderCallContext, args []storage.FilesystemAttachmentParams) ([]storage.AttachFilesystemsResult, error) {
	var instanceIds []instance.Id
	instanceIdsSeen := make(set.Strings)
	for _, arg := range args {
		if instanceIdsSeen.Contains(string(arg.InstanceId)) {
			continue
		}
		instanceIdsSeen.Add(string(arg.InstanceId))
		instanceIds = append(instanceIds, arg.InstanceId)
	}
	instances, err := s.env.Instances(ctx, instanceIds)
	switch err {
	case nil, environs.ErrPartialInstances, environs.ErrNoInstances:
	default:
		common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
		return nil, errors.Trace(err)
	}

	results := make([]storage.AttachFilesystemsResult, len(args))
	for i, arg := range args {
		var inst *environInstance
		for i, instanceId := range instanceIds {
			if instanceId != arg.InstanceId {
				continue
			}
			if instances[i] != nil {
				inst = instances[i].(*environInstance)
			}
			break
		}
		attachment, err := s.attachFilesystem(arg, inst)
		if err != nil {
			results[i].Error = errors.Annotatef(
				err, "attaching %s to %s",
				names.ReadableString(arg.Filesystem),
				names.ReadableString(arg.Machine),
			)
			common.HandleCredentialError(IsAuthorisationFailure, err, ctx)
			continue
		}
		results[i].FilesystemAttachment = attachment
	}
	return results, nil
}
390557
func (sa *StorageAccessor) UnitStorageAttachments(unitTag names.UnitTag) ([]params.StorageAttachmentId, error) {
	if sa.facade.BestAPIVersion() < 2 {
		return nil, errors.NotImplementedf("UnitStorageAttachments() (need V2+)")
	}
	args := params.Entities{
		Entities: []params.Entity{{Tag: unitTag.String()}},
	}
	var results params.StorageAttachmentIdsResults
	err := sa.facade.FacadeCall("UnitStorageAttachments", args, &results)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if len(results.Results) != 1 {
		return nil, errors.Errorf("expected 1 result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if result.Error != nil {
		return nil, result.Error
	}
	return result.Result.Ids, nil
}
1074792
func (v *volumeSource) AttachVolumes(ctx context.ProviderCallContext, attachParams []storage.VolumeAttachmentParams) ([]storage.AttachVolumesResult, error) {
	// noop
	return nil, nil
}
239093
func (sb *storageBackend) AttachStorage(storage names.StorageTag, unit names.UnitTag) (err error) {
	defer errors.DeferredAnnotatef(&err,
		"cannot attach %s to %s",
		names.ReadableString(storage),
		names.ReadableString(unit),
	)
	buildTxn := func(attempt int) ([]txn.Op, error) {
		si, err := sb.storageInstance(storage)
		if err != nil {
			return nil, errors.Trace(err)
		}
		u, err := sb.unit(unit.Id())
		if err != nil {
			return nil, errors.Trace(err)
		}
		if u.Life() != Alive {
			return nil, errors.New("unit not alive")
		}
		ch, err := u.charm()
		if err != nil {
			return nil, errors.Annotate(err, "getting charm")
		}
		ops, err := sb.attachStorageOps(si, u.UnitTag(), u.Series(), ch, u)
		if err != nil {
			return nil, errors.Trace(err)
		}
		if si.doc.Owner == "" {
			// The storage instance will be owned by the unit, so we
			// must increment the unit's refcount for the storage name.
			//
			// Make sure that we *can* assign another storage instance
			// to the unit.
			_, currentCountOp, err := validateStorageCountChange(
				sb, u.UnitTag(), si.StorageName(), 1, ch.Meta(),
			)
			if err != nil {
				return nil, errors.Trace(err)
			}
			incRefOp, err := increfEntityStorageOp(sb.mb, u.UnitTag(), si.StorageName(), 1)
			if err != nil {
				return nil, errors.Trace(err)
			}
			ops = append(ops, currentCountOp, incRefOp)
		}
		ops = append(ops, txn.Op{
			C:      unitsC,
			Id:     u.doc.Name,
			Assert: isAliveDoc,
			Update: bson.D{{"$inc", bson.D{{"storageattachmentcount", 1}}}},
		})
		ops = append(ops, u.assertCharmOps(ch)...)
		return ops, nil
	}
	return sb.mb.db().Run(buildTxn)
}
705475
func attachVolumes(ctx *context, ops map[params.MachineStorageId]*attachVolumeOp) error {
	volumeAttachmentParams := make([]storage.VolumeAttachmentParams, 0, len(ops))
	for _, op := range ops {
		volumeAttachmentParams = append(volumeAttachmentParams, op.args)
	}
	paramsBySource, volumeSources, err := volumeAttachmentParamsBySource(
		ctx.config.StorageDir, volumeAttachmentParams, ctx.config.Registry,
	)
	if err != nil {
		return errors.Trace(err)
	}
	var reschedule []scheduleOp
	var volumeAttachments []storage.VolumeAttachment
	var statuses []params.EntityStatusArgs
	for sourceName, volumeAttachmentParams := range paramsBySource {
		logger.Debugf("attaching volumes: %+v", volumeAttachmentParams)
		volumeSource := volumeSources[sourceName]
		if volumeSource == nil {
			// The storage provider does not support dynamic
			// storage, there's nothing for the provisioner
			// to do here.
			continue
		}
		results, err := volumeSource.AttachVolumes(ctx.config.CloudCallContext, volumeAttachmentParams)
		if err != nil {
			return errors.Annotatef(err, "attaching volumes from source %q", sourceName)
		}

		for i, result := range results {
			p := volumeAttachmentParams[i]
			statuses = append(statuses, params.EntityStatusArgs{
				Tag:    p.Volume.String(),
				Status: status.Attached.String(),
			})
			entityStatus := &statuses[len(statuses)-1]
			if result.Error != nil {
				// Reschedule the volume attachment.
				id := params.MachineStorageId{
					MachineTag:    p.Machine.String(),
					AttachmentTag: p.Volume.String(),
				}
				reschedule = append(reschedule, ops[id])

				// Note: we keep the status as "attaching" to
				// indicate that we will retry. When we distinguish
				// between transient and permanent errors, we will
				// set the status to "error" for permanent errors.
				entityStatus.Status = status.Attaching.String()
				entityStatus.Info = result.Error.Error()
				logger.Debugf(
					"failed to attach %s to %s: %v",
					names.ReadableString(p.Volume),
					names.ReadableString(p.Machine),
					result.Error,
				)
				continue
			}
			volumeAttachments = append(volumeAttachments, *result.VolumeAttachment)
		}
	}
	scheduleOperations(ctx, reschedule...)
	setStatus(ctx, statuses)
	if err := createVolumeAttachmentPlans(ctx, volumeAttachments); err != nil {
		return errors.Trace(err)
	}
	if err := setVolumeAttachmentInfo(ctx, volumeAttachments); err != nil {
		return errors.Trace(err)
	}

	return nil
}
689143
func (e *lxdStorageProvider) FilesystemSource(cfg *storage.Config) (storage.FilesystemSource, error) {
	return &lxdFilesystemSource{e.env}, nil
}
987082
func (s *cinderVolumeSource) AttachVolumes(ctx context.ProviderCallContext, args []storage.VolumeAttachmentParams) ([]storage.AttachVolumesResult, error) {
	results := make([]storage.AttachVolumesResult, len(args))
	for i, arg := range args {
		attachment, err := s.attachVolume(arg)
		if err != nil {
			results[i].Error = errors.Trace(err)
			if denial := common.MaybeHandleCredentialError(IsAuthorisationFailure, err, ctx); denial {
				// We do not want to continue here as we'll 100% fail if we got unauthorised error.
				break
			}
			continue
		}
		results[i].VolumeAttachment = attachment
	}
	return results, nil
}
362537
func (p *cinderProvider) FilesystemSource(providerConfig *storage.Config) (storage.FilesystemSource, error) {
	return nil, errors.NotSupportedf("filesystems")
}
734594
func (lvs *loopVolumeSource) AttachVolumes(ctx context.ProviderCallContext, args []storage.VolumeAttachmentParams) ([]storage.AttachVolumesResult, error) {
	results := make([]storage.AttachVolumesResult, len(args))
	for i, arg := range args {
		attachment, err := lvs.attachVolume(arg)
		if err != nil {
			results[i].Error = errors.Annotatef(err, "attaching volume %v", arg.Volume.Id())
			continue
		}
		results[i].VolumeAttachment = attachment
	}
	return results, nil
}
375721
func filesystemAttachmentParams(
	ctx *context, ids []params.MachineStorageId,
) ([]storage.FilesystemAttachmentParams, error) {
	paramsResults, err := ctx.config.Filesystems.FilesystemAttachmentParams(ids)
	if err != nil {
		return nil, errors.Annotate(err, "getting filesystem attachment params")
	}
	attachmentParams := make([]storage.FilesystemAttachmentParams, len(ids))
	for i, result := range paramsResults {
		if result.Error != nil {
			return nil, errors.Annotate(result.Error, "getting filesystem attachment parameters")
		}
		params, err := filesystemAttachmentParamsFromParams(result.Result)
		if err != nil {
			return nil, errors.Annotate(err, "getting filesystem attachment parameters")
		}
		attachmentParams[i] = params
	}
	return attachmentParams, nil
}
274539
func (s *StorageProvisionerAPIv3) WatchFilesystemAttachments(args params.Entities) (params.MachineStorageIdsWatchResults, error) {
	w := filesystemwatcher.Watchers{s.sb}
	return s.watchAttachments(
		args,
		w.WatchModelManagedFilesystemAttachments,
		w.WatchMachineManagedFilesystemAttachments,
		w.WatchUnitManagedFilesystemAttachments,
		storagecommon.ParseFilesystemAttachmentIds,
	)
}
896281
func (client *Client) AttachInstances(args *AttachInstancesArgs) (resp *AttachInstancesResponse, err error) {
	response := AttachInstancesResponse{}
	err = client.InvokeByFlattenMethod("AttachInstances", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}
485826
func (s stage) createFilesystems(config types.Config) error {
	fss := config.Storage.Filesystems
	s.Logger.Info("fss: %v", fss)

	if len(fss) == 0 {
		return nil
	}

	s.Logger.PushPrefix("createFilesystems")
	defer s.Logger.PopPrefix()

	devs := []string{}
	for _, fs := range fss {
		devs = append(devs, string(fs.Device))
	}

	if err := s.waitOnDevicesAndCreateAliases(devs, "filesystems"); err != nil {
		return err
	}

	// Create filesystems concurrently up to GOMAXPROCS
	concurrency := runtime.GOMAXPROCS(-1)
	work := make(chan types.Filesystem, len(fss))
	results := make(chan error)

	for i := 0; i < concurrency; i++ {
		go func() {
			for fs := range work {
				results <- s.createFilesystem(fs)
			}
		}()
	}

	for _, fs := range fss {
		work <- fs
	}
	close(work)

	// Return combined errors
	var errs []string
	for range fss {
		if err := <-results; err != nil {
			errs = append(errs, err.Error())
		}
	}

	if len(errs) > 0 {
		return errors.New(strings.Join(errs, "\n"))
	}

	return nil
}
200449
func (s *managedFilesystemSource) DetachFilesystems(ctx context.ProviderCallContext, args []storage.FilesystemAttachmentParams) ([]error, error) {
	results := make([]error, len(args))
	for i, arg := range args {
		if err := maybeUnmount(s.run, s.dirFuncs, arg.Path); err != nil {
			results[i] = err
		}
	}
	return results, nil
}
522447
func (s *FilesystemSource) ReleaseFilesystems(ctx context.ProviderCallContext, volIds []string) ([]error, error) {
	s.MethodCall(s, "ReleaseFilesystems", ctx, volIds)
	if s.ReleaseFilesystemsFunc != nil {
		return s.ReleaseFilesystemsFunc(ctx, volIds)
	}
	return nil, errors.NotImplementedf("ReleaseFilesystems")
}
906223
func (sb *storageBackend) AllFilesystems() ([]Filesystem, error) {
	filesystems, err := sb.filesystems(nil)
	if err != nil {
		return nil, errors.Annotate(err, "cannot get filesystems")
	}
	return filesystemsToInterfaces(filesystems), nil
}
26714
func (a *StorageAPI) ListFilesystems(filters params.FilesystemFilters) (params.FilesystemDetailsListResults, error) {
	results := params.FilesystemDetailsListResults{
		Results: make([]params.FilesystemDetailsListResult, len(filters.Filters)),
	}
	if err := a.checkCanRead(); err != nil {
		return results, errors.Trace(err)
	}

	stFileAccess := a.storageAccess.FilesystemAccess()
	for i, filter := range filters.Filters {
		filesystems, filesystemAttachments, err := filterFilesystems(stFileAccess, filter)
		if err != nil {
			results.Results[i].Error = common.ServerError(err)
			continue
		}
		details, err := createFilesystemDetailsList(
			a.backend, a.storageAccess, filesystems, filesystemAttachments,
		)
		if err != nil {
			results.Results[i].Error = common.ServerError(err)
			continue
		}
		results.Results[i].Result = details
	}
	return results, nil
}