// AttachVolume attaches the specified volume to this instance, returning the mountpoint & nil if successful
544402
func (a *ALIVolumes) AttachVolume(volume *Volume) error {
	// TODO: what if this volume has already been attached to another instance?
	// Aliyun Disk can only be attached to one instance
	if volume.LocalDevice == "" && volume.AttachedTo == "" {
		attachDiskArgs := &ecs.AttachDiskArgs{
			InstanceId: a.instanceId,
			DiskId:     volume.ID,
			// TODO: DeleteWithInstance?
		}
		err := a.client.AttachDisk(attachDiskArgs)
		if err != nil {
			return fmt.Errorf("error attach disk %q: %v", volume.ID, err)
		}

		// TODO: Do we have to wait for attach to complete?
		// retrieve device info
		args := &ecs.DescribeDisksArgs{
			RegionId: common.Region(a.region),
			ZoneId:   a.zone,
			DiskIds:  []string{volume.ID},
		}
		disks, _, err := a.client.DescribeDisks(args)
		if err != nil || len(disks) == 0 {
			return fmt.Errorf("error querying Aliyun disk %q: %v", volume.ID, err)
		}

		volume.LocalDevice = disks[0].Device
		volume.AttachedTo = a.instanceId
	} else if volume.AttachedTo != a.instanceId {
		return fmt.Errorf("cannot reattach an attached disk without detaching it first")
	}
	return nil
}
1281945
func Convert_v1beta1_VolumeAttachment_To_storage_VolumeAttachment(in *v1beta1.VolumeAttachment, out *storage.VolumeAttachment, s conversion.Scope) error {
	return autoConvert_v1beta1_VolumeAttachment_To_storage_VolumeAttachment(in, out, s)
}
1075739
func (m *sioMgr) DetachVolume(volName string) error {
	client, err := m.getClient()
	if err != nil {
		return err
	}
	iid, err := client.IID()
	if err != nil {
		klog.Error(log("failed to get instanceID: %v", err))
		return err
	}

	vol, err := client.FindVolume(volName)
	if err != nil {
		return err
	}
	if !m.isSdcMappedToVol(iid, vol) {
		klog.Warning(log(
			"skipping detached, vol %s not attached to instance %s",
			volName, iid,
		))
		return nil
	}

	if err := client.DetachVolume(sioVolumeID(vol.ID)); err != nil {
		klog.Error(log("failed to detach vol %s: %v", volName, err))
		return err
	}

	klog.V(4).Info(log("volume %s detached successfully", volName))

	return nil
}
1047809
func (client *Client) AttachDisk(args *AttachDiskArgs) error {
	response := AttachDiskResponse{}
	err := client.Invoke("AttachDisk", args, &response)
	return err
}
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)
}
104158
func (d *driver) attachVolume(
	ctx types.Context,
	volumeID, volumeName, deviceName string) error {

	// sanity check # of volumes to attach
	vol, err := d.getVolume(ctx, volumeID, volumeName)
	if err != nil {
		return goof.WithError("error getting volume", err)
	}

	if len(vol) == 0 {
		return errNoVolReturned
	}
	if len(vol) > 1 {
		return errTooManyVolsReturned
	}

	// Attach volume via EC2 API call
	avInput := &awsec2.AttachVolumeInput{
		Device:     &deviceName,
		InstanceId: mustInstanceIDID(ctx),
		VolumeId:   &volumeID,
	}

	if _, err := mustSession(ctx).AttachVolume(avInput); err != nil {
		return 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
}
71371
func (u *storageosUtil) AttachDevice(b *storageosMounter, deviceMountPath string) error {
	if err := u.NewAPI(b.apiCfg); err != nil {
		return err
	}

	opts := storageostypes.VolumeMountOptions{
		Name:       b.volName,
		Namespace:  b.volNamespace,
		FsType:     b.fsType,
		Mountpoint: deviceMountPath,
		Client:     b.plugin.host.GetHostName(),
	}
	if err := u.api.VolumeMount(opts); err != nil {
		return err
	}
	return nil
}
400528
func (s *VolumeServer) Attach(
	ctx context.Context,
	req *api.SdkVolumeAttachRequest,
) (*api.SdkVolumeAttachResponse, error) {
	if s.cluster() == nil || s.driver(ctx) == nil {
		return nil, status.Error(codes.Unavailable, "Resource has not been initialized")
	}

	if len(req.GetVolumeId()) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Must supply volume id")
	}

	// Get access rights
	if err := s.checkAccessForVolumeId(ctx, req.GetVolumeId(), api.Ownership_Write); err != nil {
		return nil, err
	}

	// Check options
	options := req.GetDriverOptions()
	if options == nil {
		options = make(map[string]string)
	}
	if req.GetOptions() != nil {
		if len(req.GetOptions().GetSecretContext()) != 0 {
			options[mountattachoptions.OptionsSecretContext] = req.GetOptions().GetSecretContext()
		}
		if len(req.GetOptions().GetSecretKey()) != 0 {
			options[mountattachoptions.OptionsSecretKey] = req.GetOptions().GetSecretKey()
		}
		if len(req.GetOptions().GetSecretName()) != 0 {
			options[mountattachoptions.OptionsSecret] = req.GetOptions().GetSecretName()
		}
	}

	devPath, err := s.driver(ctx).Attach(req.GetVolumeId(), options)
	if err == volume.ErrVolAttachedOnRemoteNode {
		return nil, status.Error(codes.AlreadyExists, err.Error())
	} else if err != nil {
		return nil, status.Errorf(
			codes.Internal,
			"failed  to attach volume: %v",
			err.Error())
	}

	return &api.SdkVolumeAttachResponse{DevicePath: devPath}, nil
}
1038031
func (c *Client) ResizeVolume(p *ResizeVolumeParameter) (*Volume, error) {
	obj, err := c.Request("resizeVolume", convertParamToMap(p))
	if err != nil {
		return nil, err
	}
	return obj.(*Volume), err
}
632255
func (ga *openstackStorageAdapter) DetachVolume(serverId, attachmentId string) error {
	if err := ga.novaClient.DetachVolume(serverId, attachmentId); err != nil {
		if gooseerrors.IsNotFound(err) {
			return errors.NewNotFound(nil,
				fmt.Sprintf("volume %q is not attached to server %q",
					attachmentId, serverId,
				),
			)
		}
		return err
	}
	return nil
}
605976
func detachVolumes(ctx *context, ops map[params.MachineStorageId]*detachVolumeOp) 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 statuses []params.EntityStatusArgs
	var remove []params.MachineStorageId
	for sourceName, volumeAttachmentParams := range paramsBySource {
		logger.Debugf("detaching 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
		}
		errs, err := volumeSource.DetachVolumes(ctx.config.CloudCallContext, volumeAttachmentParams)
		if err != nil {
			return errors.Annotatef(err, "detaching volumes from source %q", sourceName)
		}
		for i, err := range errs {
			p := volumeAttachmentParams[i]
			statuses = append(statuses, params.EntityStatusArgs{
				Tag: p.Volume.String(),
				// TODO(axw) when we support multiple
				// attachment, we'll have to check if
				// there are any other attachments
				// before saying the status "detached".
				Status: status.Detached.String(),
			})
			id := params.MachineStorageId{
				MachineTag:    p.Machine.String(),
				AttachmentTag: p.Volume.String(),
			}
			entityStatus := &statuses[len(statuses)-1]
			if err != nil {
				reschedule = append(reschedule, ops[id])
				entityStatus.Status = status.Detaching.String()
				entityStatus.Info = err.Error()
				logger.Debugf(
					"failed to detach %s from %s: %v",
					names.ReadableString(p.Volume),
					names.ReadableString(p.Machine),
					err,
				)
				continue
			}
			remove = append(remove, id)
		}
	}
	scheduleOperations(ctx, reschedule...)
	setStatus(ctx, statuses)
	if err := removeAttachments(ctx, remove); err != nil {
		return errors.Annotate(err, "removing attachments from state")
	}
	for _, id := range remove {
		delete(ctx.volumeAttachments, id)
	}
	return nil
}
1138583
func (vm *VirtualMachine) AttachDisk(ctx context.Context, vmDiskPath string, volumeOptions *VolumeOptions) (string, error) {
	// Check if the diskControllerType is valid
	if !CheckControllerSupported(volumeOptions.SCSIControllerType) {
		return "", fmt.Errorf("Not a valid SCSI Controller Type. Valid options are %q", SCSIControllerTypeValidOptions())
	}
	vmDiskPathCopy := vmDiskPath
	vmDiskPath = RemoveStorageClusterORFolderNameFromVDiskPath(vmDiskPath)
	attached, err := vm.IsDiskAttached(ctx, vmDiskPath)
	if err != nil {
		klog.Errorf("Error occurred while checking if disk is attached on VM: %q. vmDiskPath: %q, err: %+v", vm.InventoryPath, vmDiskPath, err)
		return "", err
	}
	// If disk is already attached, return the disk UUID
	if attached {
		diskUUID, _ := vm.Datacenter.GetVirtualDiskPage83Data(ctx, vmDiskPath)
		return diskUUID, nil
	}

	if volumeOptions.StoragePolicyName != "" {
		pbmClient, err := NewPbmClient(ctx, vm.Client())
		if err != nil {
			klog.Errorf("Error occurred while creating new pbmClient. err: %+v", err)
			return "", err
		}

		volumeOptions.StoragePolicyID, err = pbmClient.ProfileIDByName(ctx, volumeOptions.StoragePolicyName)
		if err != nil {
			klog.Errorf("Failed to get Profile ID by name: %s. err: %+v", volumeOptions.StoragePolicyName, err)
			return "", err
		}
	}

	dsObj, err := vm.Datacenter.GetDatastoreByPath(ctx, vmDiskPathCopy)
	if err != nil {
		klog.Errorf("Failed to get datastore from vmDiskPath: %q. err: %+v", vmDiskPath, err)
		return "", err
	}
	// If disk is not attached, create a disk spec for disk to be attached to the VM.
	disk, newSCSIController, err := vm.CreateDiskSpec(ctx, vmDiskPath, dsObj, volumeOptions)
	if err != nil {
		klog.Errorf("Error occurred while creating disk spec. err: %+v", err)
		return "", err
	}
	vmDevices, err := vm.Device(ctx)
	if err != nil {
		klog.Errorf("Failed to retrieve VM devices for VM: %q. err: %+v", vm.InventoryPath, err)
		return "", err
	}
	virtualMachineConfigSpec := types.VirtualMachineConfigSpec{}
	deviceConfigSpec := &types.VirtualDeviceConfigSpec{
		Device:    disk,
		Operation: types.VirtualDeviceConfigSpecOperationAdd,
	}
	// Configure the disk with the SPBM profile only if ProfileID is not empty.
	if volumeOptions.StoragePolicyID != "" {
		profileSpec := &types.VirtualMachineDefinedProfileSpec{
			ProfileId: volumeOptions.StoragePolicyID,
		}
		deviceConfigSpec.Profile = append(deviceConfigSpec.Profile, profileSpec)
	}
	virtualMachineConfigSpec.DeviceChange = append(virtualMachineConfigSpec.DeviceChange, deviceConfigSpec)
	requestTime := time.Now()
	task, err := vm.Reconfigure(ctx, virtualMachineConfigSpec)
	if err != nil {
		RecordvSphereMetric(APIAttachVolume, requestTime, err)
		klog.Errorf("Failed to attach the disk with storagePolicy: %q on VM: %q. err - %+v", volumeOptions.StoragePolicyID, vm.InventoryPath, err)
		if newSCSIController != nil {
			nestedErr := vm.deleteController(ctx, newSCSIController, vmDevices)
			if nestedErr != nil {
				return "", fmt.Errorf("failed to delete SCSI Controller after reconfiguration failed with err=%v: %v", err, nestedErr)
			}
		}
		return "", err
	}
	err = task.Wait(ctx)
	RecordvSphereMetric(APIAttachVolume, requestTime, err)
	if err != nil {
		klog.Errorf("Failed to attach the disk with storagePolicy: %+q on VM: %q. err - %+v", volumeOptions.StoragePolicyID, vm.InventoryPath, err)
		if newSCSIController != nil {
			nestedErr := vm.deleteController(ctx, newSCSIController, vmDevices)
			if nestedErr != nil {
				return "", fmt.Errorf("failed to delete SCSI Controller after waiting for reconfiguration failed with err='%v': %v", err, nestedErr)
			}
		}
		return "", err
	}

	// Once disk is attached, get the disk UUID.
	diskUUID, err := vm.Datacenter.GetVirtualDiskPage83Data(ctx, vmDiskPath)
	if err != nil {
		klog.Errorf("Error occurred while getting Disk Info from VM: %q. err: %v", vm.InventoryPath, err)
		nestedErr := vm.DetachDisk(ctx, vmDiskPath)
		if nestedErr != nil {
			return "", fmt.Errorf("failed to detach disk after getting VM UUID failed with err='%v': %v", err, nestedErr)
		}
		if newSCSIController != nil {
			nestedErr = vm.deleteController(ctx, newSCSIController, vmDevices)
			if nestedErr != nil {
				return "", fmt.Errorf("failed to delete SCSI Controller after getting VM UUID failed with err='%v': %v", err, nestedErr)
			}
		}
		return "", err
	}
	return diskUUID, nil
}
56150
func (s *VolumeServer) Mount(
	ctx context.Context,
	req *api.SdkVolumeMountRequest,
) (*api.SdkVolumeMountResponse, error) {

	if s.cluster() == nil || s.driver(ctx) == nil {
		return nil, status.Error(codes.Unavailable, "Resource has not been initialized")
	}

	if len(req.GetVolumeId()) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Must supply volume id")
	}
	if len(req.GetMountPath()) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Invalid Mount Path")
	}

	// Get access rights
	err := s.checkAccessForVolumeId(ctx, req.GetVolumeId(), api.Ownership_Write)
	if err != nil {
		return nil, err
	}

	err = s.driver(ctx).Mount(req.GetVolumeId(), req.GetMountPath(), req.GetDriverOptions())
	if err != nil {
		return nil, status.Errorf(
			codes.Internal,
			"Failed to mount volume %s: %v",
			req.GetVolumeId(),
			err.Error())
	}
	return &api.SdkVolumeMountResponse{}, err
}
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
}
575885
func (s *StorageProvisionerAPIv3) VolumeAttachmentParams(
	args params.MachineStorageIds,
) (params.VolumeAttachmentParamsResults, error) {
	canAccess, err := s.getAttachmentAuthFunc()
	if err != nil {
		return params.VolumeAttachmentParamsResults{}, common.ServerError(common.ErrPerm)
	}
	results := params.VolumeAttachmentParamsResults{
		Results: make([]params.VolumeAttachmentParamsResult, len(args.Ids)),
	}
	one := func(arg params.MachineStorageId) (params.VolumeAttachmentParams, error) {
		volumeAttachment, err := s.oneVolumeAttachment(arg, canAccess)
		if err != nil {
			return params.VolumeAttachmentParams{}, err
		}
		// Volumes can be attached to units (caas models) or machines.
		// We only care about instance id for machine attachments.
		var instanceId instance.Id
		if machineTag, ok := volumeAttachment.Host().(names.MachineTag); ok {
			instanceId, err = s.st.MachineInstanceId(machineTag)
			if errors.IsNotProvisioned(err) {
				// The worker must watch for machine provisioning events.
				instanceId = ""
			} else if err != nil {
				return params.VolumeAttachmentParams{}, err
			}
		}
		volume, err := s.sb.Volume(volumeAttachment.Volume())
		if err != nil {
			return params.VolumeAttachmentParams{}, err
		}
		var volumeId string
		var pool string
		if volumeParams, ok := volume.Params(); ok {
			pool = volumeParams.Pool
		} else {
			volumeInfo, err := volume.Info()
			if err != nil {
				return params.VolumeAttachmentParams{}, err
			}
			volumeId = volumeInfo.VolumeId
			pool = volumeInfo.Pool
		}
		providerType, _, err := storagecommon.StoragePoolConfig(pool, s.poolManager, s.registry)
		if err != nil {
			return params.VolumeAttachmentParams{}, errors.Trace(err)
		}
		var readOnly bool
		if volumeAttachmentParams, ok := volumeAttachment.Params(); ok {
			readOnly = volumeAttachmentParams.ReadOnly
		} else {
			// Attachment parameters may be requested even if the
			// attachment exists; i.e. for reattachment.
			volumeAttachmentInfo, err := volumeAttachment.Info()
			if err != nil {
				return params.VolumeAttachmentParams{}, errors.Trace(err)
			}
			readOnly = volumeAttachmentInfo.ReadOnly
		}
		return params.VolumeAttachmentParams{
			VolumeTag:  volumeAttachment.Volume().String(),
			MachineTag: volumeAttachment.Host().String(),
			VolumeId:   volumeId,
			InstanceId: string(instanceId),
			Provider:   string(providerType),
			ReadOnly:   readOnly,
		}, nil
	}
	for i, arg := range args.Ids {
		var result params.VolumeAttachmentParamsResult
		volumeAttachment, err := one(arg)
		if err != nil {
			result.Error = common.ServerError(err)
		} else {
			result.Result = volumeAttachment
		}
		results.Results[i] = result
	}
	return results, 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
}