// volumeAttachmentParamsBySource separates the volume attachment parameters by volume source.
968874
func volumeAttachmentParamsBySource(
	baseStorageDir string,
	params []storage.VolumeAttachmentParams,
	registry storage.ProviderRegistry,
) (map[string][]storage.VolumeAttachmentParams, map[string]storage.VolumeSource, error) {
	// TODO(axw) later we may have multiple instantiations (sources)
	// for a storage provider, e.g. multiple Ceph installations. For
	// now we assume a single source for each provider type, with no
	// configuration.
	volumeSources := make(map[string]storage.VolumeSource)
	paramsBySource := make(map[string][]storage.VolumeAttachmentParams)
	for _, params := range params {
		sourceName := string(params.Provider)
		paramsBySource[sourceName] = append(paramsBySource[sourceName], params)
		if _, ok := volumeSources[sourceName]; ok {
			continue
		}
		volumeSource, err := volumeSource(
			baseStorageDir, sourceName, params.Provider, registry,
		)
		if errors.Cause(err) == errNonDynamic {
			volumeSource = nil
		} else if err != nil {
			return nil, nil, errors.Annotate(err, "getting volume source")
		}
		volumeSources[sourceName] = volumeSource
	}
	return paramsBySource, volumeSources, nil
}
654034
func (st *State) VolumeAttachmentParams(ids []params.MachineStorageId) ([]params.VolumeAttachmentParamsResult, error) {
	args := params.MachineStorageIds{ids}
	var results params.VolumeAttachmentParamsResults
	err := st.facade.FacadeCall("VolumeAttachmentParams", args, &results)
	if err != nil {
		return nil, err
	}
	if len(results.Results) != len(ids) {
		return nil, errors.Errorf("expected %d result(s), got %d", len(ids), len(results.Results))
	}
	return results.Results, nil
}
289827
func (os *OpenStack) GetAttachmentDiskPath(instanceID, volumeID string) (string, error) {
	// See issue #33128 - Cinder does not always tell you the right device path, as such
	// we must only use this value as a last resort.
	volume, err := os.getVolume(volumeID)
	if err != nil {
		return "", err
	}
	if volume.Status != volumeInUseStatus {
		return "", fmt.Errorf("can not get device path of volume %s, its status is %s ", volume.Name, volume.Status)
	}
	if volume.AttachedServerID != "" {
		if instanceID == volume.AttachedServerID {
			// Attachment[0]["device"] points to the device path
			// see http://developer.openstack.org/api-ref-blockstorage-v1.html
			return volume.AttachedDevice, nil
		}
		return "", fmt.Errorf("disk %q is attached to a different compute: %q, should be detached before proceeding", volumeID, volume.AttachedServerID)
	}
	return "", fmt.Errorf("volume %s has no ServerId", volumeID)
}
728569
func (d *driver) VolumeAttach(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeAttachOpts) (*types.Volume, string, error) {

	if err := d.refreshSession(ctx); err != nil {
		return nil, "", err
	}

	if volumeID == "" {
		return nil, "", goof.New("missing volume id")
	}

	// review volume with attachments to any host
	volumes, err := d.getVolume(ctx, volumeID, "", types.VolAttReq)
	if err != nil {
		return nil, "", err
	}

	if len(volumes) == 0 {
		return nil, "", apiUtils.NewNotFoundError(volumeID)
	}

	if len(volumes[0].Attachments) > 0 && !opts.Force {
		return nil, "", goof.New("volume already attached to a host")
	}
	if opts.Force {
		if _, err = d.VolumeDetach(ctx, volumeID, nil); err != nil {
			return nil, "", err
		}
	}

	err = d.attachVolume(ctx, volumeID, "")
	if err != nil {
		return nil, "", goof.WithFieldsE(
			log.Fields{
				"provider": vbox.Name,
				"volumeID": volumeID},
			"error attaching volume",
			err,
		)
	}

	volumes, err = d.getVolume(ctx, volumeID, "", types.VolAttReqTrue)
	if err != nil {
		return nil, "", err
	}

	if len(volumes) == 0 {
		return nil, "", err
	}

	svid := strings.Split(volumes[0].ID, "-")

	return volumes[0], svid[0], nil
}
172474
func (d *driver) VolumeAttach(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeAttachOpts) (*types.Volume, string, error) {

	svc := mustSession(ctx)

	vol, err := d.VolumeInspect(ctx, volumeID,
		&types.VolumeInspectOpts{Attachments: types.VolAttReqTrue})
	if err != nil {
		return nil, "", err
	}

	iid := context.MustInstanceID(ctx)

	var ma *types.VolumeAttachment
	for _, att := range vol.Attachments {
		if att.InstanceID.ID == iid.ID {
			ma = att
			break
		}
	}

	// No mount targets were found
	if ma == nil {

		var iSecGrpIDs []string
		secGrpIDs := d.secGroups
		if v, ok := iid.Fields[efs.InstanceIDFieldSecurityGroups]; ok {
			iSecGrpIDs = strings.Split(v, ";")
			if len(iSecGrpIDs) == 1 {
				ctx.WithField("secGrpIDs", iSecGrpIDs).Debug(
					"using instance security group IDs")
				secGrpIDs = iSecGrpIDs
			}
		}

		if len(secGrpIDs) == 0 {
			return nil, "", errInvalidSecGroups
		}

		// make sure all of the request security groups
		// are available on the instance
		var missingSecGrpIDs []string
		for _, csg := range secGrpIDs {
			var found bool
			for _, isg := range iSecGrpIDs {
				if csg == isg {
					found = true
					break
				}
			}
			if !found {
				missingSecGrpIDs = append(missingSecGrpIDs, csg)
			}
		}

		// log a warning if any of the server-side defined SGs
		// are not present in the list sent by the client instance
		if len(missingSecGrpIDs) > 0 {
			log.WithField("missingStorageGroups", missingSecGrpIDs).Warn(
				"configured sec grps not present on instance")
		}

		request := &awsefs.CreateMountTargetInput{
			FileSystemId:   aws.String(vol.ID),
			SubnetId:       aws.String(iid.ID),
			SecurityGroups: aws.StringSlice(secGrpIDs),
		}
		// TODO(mhrabovcin): Should we block here until MountTarget is in
		// "available" LifeCycleState? Otherwise mount could fail until creation
		//  is completed.
		_, err = svc.CreateMountTarget(request)
		// Failed to create mount target
		if err != nil {
			return nil, "", err
		}
	}

	return vol, "", err
}
698227
func (d *driver) VolumeAttach(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeAttachOpts) (*types.Volume, string, error) {

	zone, err := d.validZone(ctx)
	if err != nil {
		return nil, "", err
	}

	if zone == nil || *zone == "" {
		return nil, "", goof.New("Zone is required for VolumeAttach")
	}

	instanceName := context.MustInstanceID(ctx).ID
	gceInst, err := d.getInstance(ctx, zone, &instanceName)
	if err != nil {
		return nil, "", err
	}
	if gceInst == nil {
		return nil, "", goof.New("Instance to attach to not found")
	}

	// Check if volume is already attached somewhere, if so, force detach?
	gceDisk, err := d.getDisk(ctx, zone, &volumeID)
	if err != nil {
		return nil, "", err
	}
	if gceDisk == nil {
		return nil, "", apiUtils.NewNotFoundError(volumeID)
	}

	if len(gceDisk.Users) > 0 {
		if !opts.Force {
			return nil, "", goof.New(
				"Volume already attached to different host")
		}
		ctx.Info("Automatically detaching volume from other instance")
		err = d.detachVolume(ctx, gceDisk)
		if err != nil {
			return nil, "", goof.WithError(
				"Error detaching volume during force attach",
				err)
		}
	}

	err = d.attachVolume(ctx, &instanceName, zone, &volumeID)
	if err != nil {
		return nil, "", err
	}

	vol, err := d.VolumeInspect(
		ctx, volumeID, &types.VolumeInspectOpts{
			Attachments: types.VolAttReq,
			Opts:        opts.Opts,
		},
	)
	if err != nil {
		return nil, "", goof.WithError("Error getting volume", err)
	}

	return vol, volumeID, nil
}
1255355
func (s *oracleVolumeSource) AttachVolumes(ctx context.ProviderCallContext, params []storage.VolumeAttachmentParams) ([]storage.AttachVolumesResult, error) {
	instanceIds := []instance.Id{}
	for _, val := range params {
		instanceIds = append(instanceIds, val.InstanceId)
	}
	if len(instanceIds) == 0 {
		return []storage.AttachVolumesResult{}, nil
	}
	instancesAsMap, err := s.env.getOracleInstancesAsMap(instanceIds...)
	if err != nil {
		return []storage.AttachVolumesResult{}, errors.Trace(err)
	}
	attachmentsAsMap, err := s.getStorageAttachments()
	if err != nil {
		return []storage.AttachVolumesResult{}, errors.Trace(err)
	}

	ret := make([]storage.AttachVolumesResult, len(params))

	for i, val := range params {
		instance, ok := instancesAsMap[string(val.InstanceId)]
		if !ok {
			ret[i].Error = errors.NotFoundf("instance %q was not found", string(val.InstanceId))
			continue
		}

		result, err := s.attachVolume(instance, attachmentsAsMap, val)
		if err != nil {
			ret[i].Error = errors.Trace(err)
			continue
		}
		ret[i] = result

	}
	logger.Infof("returning attachments: %v", ret)
	return ret, nil
}
638384
func (c *sioClient) AttachVolume(id sioVolumeID, multipleMappings bool) error {
	if err := c.init(); err != nil {
		klog.Error(log("failed to init'd client in attach volume: %v", err))
		return err
	}

	iid, err := c.IID()
	if err != nil {
		klog.Error(log("failed to get instanceIID for attach volume: %v", err))
		return err
	}

	params := &siotypes.MapVolumeSdcParam{
		SdcID:                 iid,
		AllowMultipleMappings: strconv.FormatBool(multipleMappings),
		AllSdcs:               "",
	}
	volClient := sio.NewVolume(c.client)
	volClient.Volume = &siotypes.Volume{ID: string(id)}

	if err := volClient.MapVolumeSdc(params); err != nil {
		klog.Error(log("failed to attach volume id %s: %v", id, err))
		return err
	}

	klog.V(4).Info(log("volume %s attached successfully", id))
	return nil
}
550679
func (st *State) VolumeAttachments(ids []params.MachineStorageId) ([]params.VolumeAttachmentResult, error) {
	args := params.MachineStorageIds{ids}
	var results params.VolumeAttachmentResults
	err := st.facade.FacadeCall("VolumeAttachments", args, &results)
	if err != nil {
		return nil, err
	}
	if len(results.Results) != len(ids) {
		return nil, errors.Errorf("expected %d result(s), got %d", len(ids), len(results.Results))
	}
	return results.Results, nil
}
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
}
1262335
func (d *driver) VolumeAttach(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeAttachOpts) (*types.Volume, string, error) {

	vol, err := d.getVolume(ctx, volumeID, types.VolAttReq)
	if err != nil {
		return nil, "", err
	}
	return vol, "", nil
}
1119410
func (d *driver) VolumeAttach(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeAttachOpts) (*types.Volume, string, error) {
	// Initialize for logging
	fields := map[string]interface{}{
		"provider": d.Name(),
		"volumeID": volumeID,
	}
	// review volume with attachments to any host
	ec2vols, err := d.getVolume(ctx, volumeID, "")
	if err != nil {
		return nil, "", goof.WithFieldsE(fields, "error getting volume", err)
	}
	volumes, convErr := d.toTypesVolume(
		ctx, ec2vols, types.VolAttReqTrue)
	if convErr != nil {
		return nil, "", goof.WithError(
			"error converting to types.Volume", convErr)
	}

	// Check if there a volume to attach
	if len(volumes) == 0 {
		return nil, "", goof.New("no volume found")
	}

	// Check if volume is already attached
	if len(volumes[0].Attachments) > 0 {
		// Detach already attached volume if forced
		if !opts.Force {
			return nil, "", errVolAlreadyAttached
		}
		_, err := d.VolumeDetach(
			ctx,
			volumeID,
			&types.VolumeDetachOpts{
				Force: opts.Force,
				Opts:  opts.Opts,
			})
		if err != nil {
			return nil, "", goof.WithError("error detaching volume", err)
		}
	}

	if opts.NextDevice == nil {
		return nil, "", errMissingNextDevice
	}

	// tagName: e.g. "vol1"
	tagName := volumes[0].Name
	if tagName == "" {
		return nil, "", goof.WithFields(fields, "error empty Name tag")
	}
	// get fcvol constituent disks by Name tag
	ec2vols, err = d.getVolume(ctx, "", tagName)
	if err != nil {
		return nil, "", goof.WithError("error getting FittedCloud volumes", err)
	}

	// Make sure all volumes are FittedCloudCreated
	allOK := true
	for _, volume := range ec2vols {
		if d.fittedcloudCreated(volume.Tags) == "" {
			allOK = false
			break
		}
	}
	if !allOK {
		return nil, "", goof.WithFields(fields, "not a FittedCloudCreated volume")
	}

	// Attach constituent disks
	nextDevice := *opts.NextDevice
	for _, volume := range ec2vols {
		if nextDevice == "" {
			return nil, "", errMissingNextDevice
		}
		// Attach volume via helper function which uses EC2 API call
		err = d.attachVolume(ctx, *volume.VolumeId, volumes[0].Name, nextDevice)
		if err != nil {
			return nil, "", goof.WithFieldsE(
				log.Fields{
					"provider": d.Name(),
					"volumeID": volume.VolumeId},
				"error attaching volume",
				err,
			)
		}
		// Wait for volume's status to update
		err = d.waitVolumeComplete(ctx, *volume.VolumeId, waitVolumeAttach)
		if err != nil {
			return nil, "", goof.WithError("error waiting for volume attach", err)
		}
		nextDevice, _ = fcUtils.NextDevice(ctx, apiUtils.NewStore())
	}

	// Check if successful attach
	attachedVol, err := d.VolumeInspect(
		ctx, volumeID, &types.VolumeInspectOpts{
			Attachments: types.VolAttReqTrue,
			Opts:        opts.Opts,
		})
	if err != nil {
		return nil, "", goof.WithError("error getting volume", err)
	}

	// Token is the attachment's device name, which will be matched
	// to the executor's device ID
	return attachedVol, *opts.NextDevice, nil
}
897555
func Convert_v1_VolumeAttachment_To_storage_VolumeAttachment(in *v1.VolumeAttachment, out *storage.VolumeAttachment, s conversion.Scope) error {
	return autoConvert_v1_VolumeAttachment_To_storage_VolumeAttachment(in, out, s)
}
919136
func (sb *storageBackend) StorageAttachment(storage names.StorageTag, unit names.UnitTag) (StorageAttachment, error) {
	att, err := sb.storageAttachment(storage, unit)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return att, nil
}
990767
func (sb *storageBackend) UnitVolumeAttachments(unit names.UnitTag) ([]VolumeAttachment, error) {
	attachments, err := sb.volumeAttachments(bson.D{{"hostid", unit.Id()}})
	if err != nil {
		return nil, errors.Annotatef(err, "getting volume attachments for unit %q", unit.Id())
	}
	return attachments, nil
}
614373
func Convert_v1_VolumeAttachmentStatus_To_storage_VolumeAttachmentStatus(in *v1.VolumeAttachmentStatus, out *storage.VolumeAttachmentStatus, s conversion.Scope) error {
	return autoConvert_v1_VolumeAttachmentStatus_To_storage_VolumeAttachmentStatus(in, out, s)
}
67240
func (ec2i *FakeEC2Impl) AttachVolume(request *ec2.AttachVolumeInput) (resp *ec2.VolumeAttachment, err error) {
	panic("Not implemented")
}