// volumeAttachmentsZone determines the availability zone for each volume
// identified in the volume attachment parameters, checking that they are
// all the same, and returns the availability zone name.
180403
func volumeAttachmentsZone(volumeAttachments []storage.VolumeAttachmentParams) (string, error) {
	var zone string
	for i, a := range volumeAttachments {
		volumeZone, _, err := parseVolumeId(a.VolumeId)
		if err != nil {
			return "", errors.Trace(err)
		}
		if zone == "" {
			zone = volumeZone
		} else if zone != volumeZone {
			return "", errors.Errorf(
				"cannot attach volumes from multiple availability zones: %s is in %s, %s is in %s",
				volumeAttachments[i-1].VolumeId, zone, a.VolumeId, volumeZone,
			)
		}
	}
	return zone, nil
}
1238718
func (s *VolumeService) AttachVolume(p *AttachVolumeParams) (*AttachVolumeResponse, error) {
	resp, err := s.cs.newRequest("attachVolume", p.toURLValues())
	if err != nil {
		return nil, err
	}

	var r AttachVolumeResponse
	if err := json.Unmarshal(resp, &r); err != nil {
		return nil, err
	}

	// If we have a async client, we need to wait for the async result
	if s.cs.async {
		b, err := s.cs.GetAsyncJobResult(r.JobID, s.cs.timeout)
		if err != nil {
			if err == AsyncTimeoutErr {
				return &r, err
			}
			return nil, err
		}

		b, err = getRawValue(b)
		if err != nil {
			return nil, err
		}

		if err := json.Unmarshal(b, &r); err != nil {
			return nil, err
		}
	}

	return &r, nil
}
1067799
func (v *azureVolumeSource) DetachVolumes(ctx context.ProviderCallContext, attachParams []storage.VolumeAttachmentParams) ([]error, error) {
	results := make([]error, len(attachParams))
	instanceIds := make([]instance.Id, len(attachParams))
	for i, p := range attachParams {
		instanceIds[i] = p.InstanceId
	}
	if len(instanceIds) == 0 {
		return results, nil
	}
	virtualMachines, err := v.virtualMachines(ctx, instanceIds)
	if err != nil {
		return nil, errors.Annotate(err, "getting virtual machines")
	}

	// Update VirtualMachine objects in-memory,
	// and then perform the updates all at once.
	//
	// An detachment does not require an update
	// if the disk isn't attached, so we keep a
	// record of which VMs need updating.
	changed := make(map[instance.Id]bool, len(virtualMachines))
	for i, p := range attachParams {
		vm, ok := virtualMachines[p.InstanceId]
		if !ok {
			continue
		}
		if vm.err != nil {
			results[i] = vm.err
			continue
		}
		if v.detachVolume(vm.vm, p) {
			changed[p.InstanceId] = true
		}
	}
	for _, instanceId := range instanceIds {
		if !changed[instanceId] {
			delete(virtualMachines, instanceId)
		}
	}

	updateResults, err := v.updateVirtualMachines(ctx, virtualMachines, instanceIds)
	if err != nil {
		return nil, errors.Annotate(err, "updating virtual machines")
	}
	for i, err := range updateResults {
		if results[i] != nil || err == nil {
			continue
		}
		results[i] = err
	}
	return results, 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
}
323354
func (env *environ) AvailabilityZones(ctx context.ProviderCallContext) ([]common.AvailabilityZone, error) {
	zones, err := env.gce.AvailabilityZones(env.cloud.Region)
	if err != nil {
		return nil, google.HandleCredentialError(errors.Trace(err), ctx)
	}

	var result []common.AvailabilityZone
	for _, zone := range zones {
		if zone.Deprecated() {
			continue
		}
		// We make a copy since the loop var keeps the same pointer.
		zoneCopy := zone
		result = append(result, &zoneCopy)
	}
	return result, nil
}
599839
func validateVolumeAttachmentStatus(status *storage.VolumeAttachmentStatus, fldPath *field.Path) field.ErrorList {
	allErrs := field.ErrorList{}
	allErrs = append(allErrs, validateAttachmentMetadata(status.AttachmentMetadata, fldPath.Child("attachmentMetadata"))...)
	allErrs = append(allErrs, validateVolumeError(status.AttachError, fldPath.Child("attachError"))...)
	allErrs = append(allErrs, validateVolumeError(status.DetachError, fldPath.Child("detachError"))...)
	return allErrs
}
1037105
func Convert_storage_VolumeAttachmentSource_To_v1_VolumeAttachmentSource(in *storage.VolumeAttachmentSource, out *v1.VolumeAttachmentSource, s conversion.Scope) error {
	return autoConvert_storage_VolumeAttachmentSource_To_v1_VolumeAttachmentSource(in, out, s)
}
101362
func Convert_storage_VolumeAttachmentList_To_v1_VolumeAttachmentList(in *storage.VolumeAttachmentList, out *v1.VolumeAttachmentList, s conversion.Scope) error {
	return autoConvert_storage_VolumeAttachmentList_To_v1_VolumeAttachmentList(in, out, s)
}
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
}
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)
}
34318
func (lvs *loopVolumeSource) DetachVolumes(ctx context.ProviderCallContext, args []storage.VolumeAttachmentParams) ([]error, error) {
	results := make([]error, len(args))
	for i, arg := range args {
		if err := lvs.detachVolume(arg.Volume); err != nil {
			results[i] = errors.Annotatef(err, "detaching volume %s", arg.Volume.Id())
		}
	}
	return results, 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
}
815446
func createVolumeAttachmentPlans(ctx *context, volumeAttachments []storage.VolumeAttachment) error {
	// NOTE(gsamfira): should we merge this with setVolumeInfo?
	if len(volumeAttachments) == 0 {
		return nil
	}

	volumeAttachmentPlans := make([]params.VolumeAttachmentPlan, len(volumeAttachments))
	for i, val := range volumeAttachments {
		volumeAttachmentPlans[i] = volumeAttachmentPlanFromAttachment(val)
	}

	errorResults, err := ctx.config.Volumes.CreateVolumeAttachmentPlans(volumeAttachmentPlans)
	if err != nil {
		return errors.Annotatef(err, "creating volume plans")
	}
	for i, result := range errorResults {
		if result.Error != nil {
			return errors.Annotatef(
				result.Error, "creating volume plan of %s to %s to state",
				names.ReadableString(volumeAttachments[i].Volume),
				names.ReadableString(volumeAttachments[i].Machine),
			)
		}
		// Record the volume attachment in the context.
		id := params.MachineStorageId{
			MachineTag:    volumeAttachmentPlans[i].MachineTag,
			AttachmentTag: volumeAttachmentPlans[i].VolumeTag,
		}
		ctx.volumeAttachments[id] = volumeAttachments[i]
		// removePendingVolumeAttachment(ctx, id)
	}
	return nil
}
1089176
func (d *driver) VolumeRemove(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeRemoveOpts) error {

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

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

	// TODO: check if disk is still attached first
	asyncOp, err := mustSession(ctx).Disks.Delete(
		*d.projectID, *zone, volumeID).Do()
	if err != nil {
		return goof.WithError("Failed to initiate disk deletion", err)
	}

	err = d.waitUntilOperationIsFinished(
		ctx, zone, asyncOp)
	if err != nil {
		return err
	}

	return nil
}
1105613
func VolumeAttachmentInfoFromState(info state.VolumeAttachmentInfo) params.VolumeAttachmentInfo {
	planInfo := &params.VolumeAttachmentPlanInfo{}
	if info.PlanInfo != nil {
		planInfo.DeviceType = info.PlanInfo.DeviceType
		planInfo.DeviceAttributes = info.PlanInfo.DeviceAttributes
	} else {
		planInfo = nil
	}
	return params.VolumeAttachmentInfo{
		info.DeviceName,
		info.DeviceLink,
		info.BusAddress,
		info.ReadOnly,
		planInfo,
	}
}
317177
func Convert_storage_VolumeAttachmentSource_To_v1beta1_VolumeAttachmentSource(in *storage.VolumeAttachmentSource, out *v1beta1.VolumeAttachmentSource, s conversion.Scope) error {
	return autoConvert_storage_VolumeAttachmentSource_To_v1beta1_VolumeAttachmentSource(in, out, s)
}
391434
func (v *volumeClient) Attach(volumeID string, attachOptions map[string]string) (string, error) {
	response, err := v.doVolumeSetGetResponse(
		volumeID,
		&api.VolumeSetRequest{
			Action: &api.VolumeStateAction{
				Attach: api.VolumeActionParam_VOLUME_ACTION_PARAM_ON,
			},
			Options: attachOptions,
		},
	)
	if err != nil {
		return "", err
	}
	if response.Volume != nil {
		if response.Volume.Spec.Encrypted {
			return response.Volume.SecureDevicePath, nil
		} else {
			return response.Volume.DevicePath, nil
		}
	}
	return "", nil
}