// VolumeAttach attaches a volume and provides a token clients can use
// to validate that device has appeared locally.
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
}
417586
func ValidateVolumeAttachmentV1(volumeAttachment *storage.VolumeAttachment) field.ErrorList {
	allErrs := apivalidation.ValidateCSIDriverName(volumeAttachment.Spec.Attacher, field.NewPath("spec.attacher"))

	if volumeAttachment.Spec.Source.PersistentVolumeName != nil {
		pvName := *volumeAttachment.Spec.Source.PersistentVolumeName
		for _, msg := range apivalidation.ValidatePersistentVolumeName(pvName, false) {
			allErrs = append(allErrs, field.Invalid(field.NewPath("spec.source.persistentVolumeName"), pvName, msg))
		}
	}
	return allErrs
}
530299
func (a *flexVolumeAttacher) Attach(spec *volume.Spec, hostName types.NodeName) (string, error) {

	call := a.plugin.NewDriverCall(attachCmd)
	call.AppendSpec(spec, a.plugin.host, nil)
	call.Append(string(hostName))

	status, err := call.Run()
	if isCmdNotSupportedErr(err) {
		return (*attacherDefaults)(a).Attach(spec, hostName)
	} else if err != nil {
		return "", err
	}
	return status.DevicePath, err
}
498369
func Convert_v1beta1_VolumeAttachmentSource_To_storage_VolumeAttachmentSource(in *v1beta1.VolumeAttachmentSource, out *storage.VolumeAttachmentSource, s conversion.Scope) error {
	return autoConvert_v1beta1_VolumeAttachmentSource_To_storage_VolumeAttachmentSource(in, out, s)
}
264520
func Convert_v1alpha1_VolumeAttachment_To_storage_VolumeAttachment(in *v1alpha1.VolumeAttachment, out *storage.VolumeAttachment, s conversion.Scope) error {
	return autoConvert_v1alpha1_VolumeAttachment_To_storage_VolumeAttachment(in, out, s)
}
1290675
func (e *Engine) VirtualizationAttach(ctx context.Context, ID string, stream, stdin bool) (io.ReadCloser, io.WriteCloser, error) {
	resp, err := e.client.ContainerAttach(ctx, ID, dockertypes.ContainerAttachOptions{Stream: stream, Stdin: stdin})
	if err != nil {
		return nil, nil, err
	}
	return ioutil.NopCloser(resp.Reader), resp.Conn, nil
}
209723
func (a *attacherDefaults) WaitForAttach(spec *volume.Spec, devicePath string, timeout time.Duration) (string, error) {
	klog.Warning(logPrefix(a.plugin.flexVolumePlugin), "using default WaitForAttach for volume ", spec.Name(), ", device ", devicePath)
	return devicePath, nil
}
1077933
func VolumeAttachmentFromState(v state.VolumeAttachment) (params.VolumeAttachment, error) {
	info, err := v.Info()
	if err != nil {
		return params.VolumeAttachment{}, errors.Trace(err)
	}
	return params.VolumeAttachment{
		v.Volume().String(),
		v.Host().String(),
		VolumeAttachmentInfoFromState(info),
	}, nil
}
1074792
func (v *volumeSource) AttachVolumes(ctx context.ProviderCallContext, attachParams []storage.VolumeAttachmentParams) ([]storage.AttachVolumesResult, error) {
	// noop
	return nil, nil
}
594767
func (c *FakeVolumeAttachments) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.VolumeAttachment, err error) {
	obj, err := c.Fake.
		Invokes(testing.NewRootPatchSubresourceAction(volumeattachmentsResource, name, pt, data, subresources...), &v1alpha1.VolumeAttachment{})
	if obj == nil {
		return nil, err
	}
	return obj.(*v1alpha1.VolumeAttachment), err
}
106969
func (d *driver) Attach(
	ctx types.Context,
	volumeName string,
	opts *types.VolumeAttachOpts) (string, error) {
	return "", nil
}
1190678
func (sb *storageBackend) MachineVolumeAttachments(machine names.MachineTag) ([]VolumeAttachment, error) {
	attachments, err := sb.volumeAttachments(bson.D{{"hostid", machine.Id()}})
	if err != nil {
		return nil, errors.Annotatef(err, "getting volume attachments for machine %q", machine.Id())
	}
	return attachments, nil
}
511895
func (v *volumeClient) Detach(volumeID string, options map[string]string) error {
	return v.doVolumeSet(
		volumeID,
		&api.VolumeSetRequest{
			Action: &api.VolumeStateAction{
				Attach: api.VolumeActionParam_VOLUME_ACTION_PARAM_OFF,
			},
			Options: options,
		},
	)
}
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)
}
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)
}
205299
func (d *driver) VolumeAttach(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeAttachOpts) (*types.Volume, string, error) {

	d.Lock()
	defer d.Unlock()

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

	// ensure the volume exists and is exported
	vol, err := d.VolumeInspect(ctx, volumeID,
		&types.VolumeInspectOpts{Attachments: types.VolAttReqTrue})
	if err != nil {
		return nil, "", err
	}

	exportID, err := d.client.ExportVolume(ctx, volumeID)
	if err != nil {
		return nil, "", goof.WithError("problem exporting volume", err)
	}
	// see if anyone is attached already
	clients, err := d.client.GetExportClientsByID(ctx, exportID)
	if err != nil {
		return nil, "", goof.WithError("problem getting export client", err)
	}

	// clear out any existing clients if necessary.  if force is false and
	// we have existing clients, we need to exit.
	if len(clients) > 0 && !d.sharedMounts() && opts.Force == false {
		for _, c := range clients {
			if c == instanceID.InstanceID.ID {
				return nil, "", goof.New("volume already attached to instance")
			}
		}

		return nil, "", goof.New("volume already attached to another host")
	}

	if d.sharedMounts() {
		clients = append(clients, instanceID.InstanceID.ID)
	} else {
		clients = []string{instanceID.InstanceID.ID}
	}

	log.WithField("clients", clients).Info("setting exports")
	err = d.client.SetExportClientsByID(ctx, exportID, clients...)
	if err != nil {
		return nil, "", err
	}

	log.Info("disabling root squash for export")
	err = d.client.DisableRootMappingByID(ctx, exportID)
	if err != nil {
		return nil, "", err
	}

	log.Info("disabling failure mapping for export")
	err = d.client.DisableFailureMappingByID(ctx, exportID)
	if err != nil {
		return nil, "", err
	}

	log.Info("mapping non-root user to root")
	err = d.client.EnableNonRootMappingByID(ctx, exportID, "root")
	if err != nil {
		return nil, "", err
	}

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

	return vol, "", err
}
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
}