// DetachDisk detaches the disk from the node.
// It detaches device from the node if device is provided, and removes the lock
// if there is persisted RBD info under deviceMountPath.
179195
func (util *RBDUtil) DetachDisk(plugin *rbdPlugin, deviceMountPath string, device string) error {
	if len(device) == 0 {
		return fmt.Errorf("DetachDisk failed , device is empty")
	}

	exec := plugin.host.GetExec(plugin.GetPluginName())

	var rbdCmd string

	// Unlike map, we cannot fallthrough for unmap
	// the tool to unmap is based on device type
	if strings.HasPrefix(device, "/dev/nbd") {
		rbdCmd = "rbd-nbd"
	} else {
		rbdCmd = "rbd"
	}

	// rbd unmap
	output, err := exec.Run(rbdCmd, "unmap", device)
	if err != nil {
		return rbdErrors(err, fmt.Errorf("rbd: failed to unmap device %s, error %v, rbd output: %v", device, err, output))
	}
	klog.V(3).Infof("rbd: successfully unmap device %s", device)

	// Currently, we don't persist rbd info on the disk, but for backward
	// compatbility, we need to clean it if found.
	rbdFile := filepath.Join(deviceMountPath, "rbd.json")
	exists, err := utilpath.Exists(utilpath.CheckFollowSymlink, rbdFile)
	if err != nil {
		return err
	}
	if exists {
		klog.V(3).Infof("rbd: old rbd.json is found under %s, cleaning it", deviceMountPath)
		err = util.cleanOldRBDFile(plugin, rbdFile)
		if err != nil {
			klog.Errorf("rbd: failed to clean %s", rbdFile)
			return err
		}
		klog.V(3).Infof("rbd: successfully remove %s", rbdFile)
	}
	return nil
}
88490
func (os *OpenStack) DetachDisk(instanceID, volumeID string) error {
	volume, err := os.getVolume(volumeID)
	if err != nil {
		return err
	}
	if volume.Status != VolumeInUseStatus {
		errmsg := fmt.Sprintf("can not detach volume %s, its status is %s.", volume.Name, volume.Status)
		glog.Error(errmsg)
		return errors.New(errmsg)
	}
	cClient, err := os.NewComputeV2()
	if err != nil {
		return err
	}
	if volume.AttachedServerID != instanceID {
		errMsg := fmt.Sprintf("Disk: %s has no attachments or is not attached to compute: %s", volume.Name, instanceID)
		glog.Error(errMsg)
		return errors.New(errMsg)
	}

	// This is a blocking call and effects kubelet's performance directly.
	// We should consider kicking it out into a separate routine, if it is bad.
	err = volumeattach.Delete(cClient, instanceID, volume.ID).ExtractErr()
	if err != nil {
		glog.Errorf("Failed to delete volume %s from compute %s attached %v", volume.ID, instanceID, err)
		return err
	}
	glog.V(2).Infof("Successfully detached volume: %s from compute: %s", volume.ID, instanceID)
	return nil
}
1128896
func (d *driver) Detach(
	ctx types.Context,
	volumeName string,
	opts *types.VolumeDetachOpts) error {
	return nil
}
659582
func (gce *Connection) DetachDisk(zone, instanceId, volumeName string) error {
	disk, err := gce.raw.GetDisk(gce.projectID, zone, volumeName)
	if err != nil {
		return errors.Annotatef(err, "cannot obtain disk %q to detach it", volumeName)
	}
	dn := deviceName(zone, disk.Id)
	err = gce.raw.DetachDisk(gce.projectID, zone, instanceId, dn)
	if err != nil {
		return errors.Annotatef(err, "cannot detach %q from %q", dn, instanceId)
	}
	return nil
}
454610
func (util *ISCSIUtil) DetachDisk(c iscsiDiskUnmounter, mntPath string) error {
	if pathExists, pathErr := mount.PathExists(mntPath); pathErr != nil {
		return fmt.Errorf("Error checking if path exists: %v", pathErr)
	} else if !pathExists {
		klog.Warningf("Warning: Unmount skipped because path does not exist: %v", mntPath)
		return nil
	}

	notMnt, err := c.mounter.IsLikelyNotMountPoint(mntPath)
	if err != nil {
		return err
	}
	if !notMnt {
		if err := c.mounter.Unmount(mntPath); err != nil {
			klog.Errorf("iscsi detach disk: failed to unmount: %s\nError: %v", mntPath, err)
			return err
		}
	}

	// if device is no longer used, see if need to logout the target
	device, prefix, err := extractDeviceAndPrefix(mntPath)
	if err != nil {
		return err
	}

	var bkpPortal []string
	var volName, iqn, iface, initiatorName string
	found := true

	// load iscsi disk config from json file
	if err := util.loadISCSI(c.iscsiDisk, mntPath); err == nil {
		bkpPortal, iqn, iface, volName = c.iscsiDisk.Portals, c.iscsiDisk.Iqn, c.iscsiDisk.Iface, c.iscsiDisk.VolName
		initiatorName = c.iscsiDisk.InitiatorName
	} else {
		// If the iscsi disk config is not found, fall back to the original behavior.
		// This portal/iqn/iface is no longer referenced, log out.
		// Extract the portal and iqn from device path.
		bkpPortal = make([]string, 1)
		bkpPortal[0], iqn, err = extractPortalAndIqn(device)
		if err != nil {
			return err
		}
		// Extract the iface from the mountPath and use it to log out. If the iface
		// is not found, maintain the previous behavior to facilitate kubelet upgrade.
		// Logout may fail as no session may exist for the portal/IQN on the specified interface.
		iface, found = extractIface(mntPath)
	}

	// Delete all the scsi devices and any multipath devices after unmounting
	if err = deleteDevices(c); err != nil {
		klog.Warningf("iscsi detach disk: failed to delete devices\nError: %v", err)
		// Fall through -- even if deleting fails, a logout may fix problems
	}

	// Lock the target while we determine if we can safely log out or not
	c.plugin.targetLocks.LockKey(iqn)
	defer c.plugin.targetLocks.UnlockKey(iqn)

	// if device is no longer used, see if need to logout the target
	refCount, err := getDevicePrefixRefCount(c.mounter, prefix)
	if err != nil || refCount != 0 {
		return nil
	}

	portals := removeDuplicate(bkpPortal)
	if len(portals) == 0 {
		return fmt.Errorf("iscsi detach disk: failed to detach iscsi disk. Couldn't get connected portals from configurations")
	}

	err = util.detachISCSIDisk(c.exec, portals, iqn, iface, volName, initiatorName, found)
	if err != nil {
		return fmt.Errorf("failed to finish detachISCSIDisk, err: %v", err)
	}
	return nil
}
1073687
func (util *DiskUtil) AttachDisk(b *cinderVolumeMounter, globalPDPath string) error {
	options := []string{}
	if b.readOnly {
		options = append(options, "ro")
	}
	cloud, err := b.plugin.getCloudProvider()
	if err != nil {
		return err
	}
	instanceid, err := cloud.InstanceID()
	if err != nil {
		return err
	}
	diskid, err := cloud.AttachDisk(instanceid, b.pdName)
	if err != nil {
		return err
	}

	var devicePath string
	numTries := 0
	for {
		devicePath = cloud.GetDevicePath(diskid)
		probeAttachedVolume()

		_, err := os.Stat(devicePath)
		if err == nil {
			break
		}
		if err != nil && !os.IsNotExist(err) {
			return err
		}
		numTries++
		if numTries == 10 {
			return errors.New("Could not attach disk: Timeout after 60s")
		}
		time.Sleep(time.Second * 6)
	}
	notmnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath)
	if err != nil {
		if os.IsNotExist(err) {
			if err := os.MkdirAll(globalPDPath, 0750); err != nil {
				return err
			}
			notmnt = true
		} else {
			return err
		}
	}
	if notmnt {
		err = b.blockDeviceMounter.FormatAndMount(devicePath, globalPDPath, b.fsType, options)
		if err != nil {
			os.Remove(globalPDPath)
			return err
		}
		klog.V(2).Infof("Safe mount successful: %q\n", devicePath)
	}
	return nil
}
536733
func (c *Cloud) DetachDisk(diskName KubernetesVolumeID, nodeName types.NodeName) (string, error) {
	diskInfo, attached, err := c.checkIfAttachedToNode(diskName, nodeName)
	if err != nil {
		if isAWSErrorVolumeNotFound(err) {
			// Someone deleted the volume being detached; complain, but do nothing else and return success
			klog.Warningf("DetachDisk %s called for node %s but volume does not exist; assuming the volume is detached", diskName, nodeName)
			return "", nil
		}

		return "", err
	}

	if !attached && diskInfo.ec2Instance != nil {
		klog.Warningf("DetachDisk %s called for node %s but volume is attached to node %s", diskName, nodeName, diskInfo.nodeName)
		return "", nil
	}

	if !attached {
		return "", nil
	}

	awsInstance := newAWSInstance(c.ec2, diskInfo.ec2Instance)

	mountDevice, alreadyAttached, err := c.getMountDevice(awsInstance, diskInfo.ec2Instance, diskInfo.disk.awsID, false)
	if err != nil {
		return "", err
	}

	if !alreadyAttached {
		klog.Warningf("DetachDisk called on non-attached disk: %s", diskName)
		// TODO: Continue?  Tolerate non-attached error from the AWS DetachVolume call?
	}

	request := ec2.DetachVolumeInput{
		InstanceId: &awsInstance.awsID,
		VolumeId:   diskInfo.disk.awsID.awsString(),
	}

	response, err := c.ec2.DetachVolume(&request)
	if err != nil {
		return "", fmt.Errorf("error detaching EBS volume %q from %q: %q", diskInfo.disk.awsID, awsInstance.awsID, err)
	}

	if response == nil {
		return "", errors.New("no response from DetachVolume")
	}

	attachment, err := diskInfo.disk.waitForAttachmentStatus("detached")
	if err != nil {
		return "", err
	}
	if da, ok := c.deviceAllocators[awsInstance.nodeName]; ok {
		da.Deprioritize(mountDevice)
	}
	if attachment != nil {
		// We expect it to be nil, it is (maybe) interesting if it is not
		klog.V(2).Infof("waitForAttachmentStatus returned non-nil attachment with state=detached: %v", attachment)
	}

	if mountDevice != "" {
		c.endAttaching(awsInstance, diskInfo.disk.awsID, mountDevice)
		// We don't check the return value - we don't really expect the attachment to have been
		// in progress, though it might have been
	}

	hostDevicePath := "/dev/xvd" + string(mountDevice)
	return hostDevicePath, err
}
247259
func (v *ebsVolumeSource) DetachVolumes(ctx context.ProviderCallContext, attachParams []storage.VolumeAttachmentParams) ([]error, error) {
	return detachVolumes(v.env.ec2, ctx, attachParams)
}
1013740
func (s *awsService) Detach(ctx context.Context, groupID string, instanceIDs []string) error {
	input := &aws.DetachGroupInput{
		GroupID:                       fi.String(groupID),
		InstanceIDs:                   instanceIDs,
		ShouldDecrementTargetCapacity: fi.Bool(false),
		ShouldTerminateInstances:      fi.Bool(true),
	}

	_, err := s.svc.Detach(ctx, input)
	return err
}
902721
func (util *RBDUtil) DetachBlockDisk(disk rbdDiskUnmapper, mapPath string) error {

	if pathExists, pathErr := mount.PathExists(mapPath); pathErr != nil {
		return fmt.Errorf("Error checking if path exists: %v", pathErr)
	} else if !pathExists {
		klog.Warningf("Warning: Unmap skipped because path does not exist: %v", mapPath)
		return nil
	}
	// If we arrive here, device is no longer used, see if we need to logout of the target
	device, err := getBlockVolumeDevice(mapPath)
	if err != nil {
		return err
	}

	if len(device) == 0 {
		return fmt.Errorf("DetachDisk failed , device is empty")
	}

	exec := disk.plugin.host.GetExec(disk.plugin.GetPluginName())

	var rbdCmd string

	// Unlike map, we cannot fallthrough here.
	// Any nbd device must be unmapped by rbd-nbd
	if strings.HasPrefix(device, "/dev/nbd") {
		rbdCmd = "rbd-nbd"
		klog.V(4).Infof("rbd: using rbd-nbd for unmap function")
	} else {
		rbdCmd = "rbd"
		klog.V(4).Infof("rbd: using rbd for unmap function")
	}

	// rbd unmap
	output, err := exec.Run(rbdCmd, "unmap", device)
	if err != nil {
		return rbdErrors(err, fmt.Errorf("rbd: failed to unmap device %s, error %v, rbd output: %s", device, err, string(output)))
	}
	klog.V(3).Infof("rbd: successfully unmap device %s", device)

	return nil
}
682032
func (d *azureDiskDetacher) Detach(diskURI string, nodeName types.NodeName) error {
	if diskURI == "" {
		return fmt.Errorf("invalid disk to detach: %q", diskURI)
	}

	diskController, err := getDiskController(d.plugin.host)
	if err != nil {
		return err
	}

	err = diskController.DetachDisk("", diskURI, nodeName)
	if err != nil {
		klog.Errorf("failed to detach azure disk %q, err %v", diskURI, err)
	}

	klog.V(2).Infof("azureDisk - disk:%s was detached from node:%v", diskURI, nodeName)
	return err
}
505181
func detachLoopDevice(run runCommandFunc, deviceName string) error {
	_, err := run("losetup", "-d", path.Join("/dev", deviceName))
	if err != nil {
		return errors.Annotatef(err, "detaching loop device %q", deviceName)
	}
	return err
}
71834
func (conn *gdbConn) detach() error {
	if conn.conn == nil {
		// Already detached
		return nil
	}
	_, err := conn.exec([]byte{'$', 'D'}, "detach")
	conn.conn.Close()
	conn.conn = nil
	return err
}
1185441
func (sb *storageBackend) DetachStorage(storage names.StorageTag, unit names.UnitTag, force bool, maxWait time.Duration) (err error) {
	defer errors.DeferredAnnotatef(&err, "cannot destroy storage attachment %s:%s", storage.Id(), unit.Id())
	buildTxn := func(attempt int) ([]txn.Op, error) {
		s, err := sb.storageAttachment(storage, unit)
		if errors.IsNotFound(err) && attempt > 0 {
			// On the first attempt, we expect it to exist.
			return nil, jujutxn.ErrNoOperations
		} else if err != nil {
			return nil, errors.Trace(err)
		}
		if s.doc.Life == Dying {
			return nil, jujutxn.ErrNoOperations
		}
		si, err := sb.storageInstance(storage)
		if err != nil {
			return nil, jujutxn.ErrNoOperations
		}
		var ops []txn.Op
		var ownerAssert bson.DocElem
		switch owner := si.maybeOwner(); owner {
		case nil:
			ownerAssert = bson.DocElem{"owner", bson.D{{"$exists", false}}}
		case unit:
			validateRemoveOps, err := validateRemoveOwnerStorageInstanceOps(si)
			if err != nil {
				return nil, errors.Trace(err)
			}
			ops = append(ops, validateRemoveOps...)
			fallthrough
		default:
			ownerAssert = bson.DocElem{"owner", si.doc.Owner}
		}
		ops = append(ops, txn.Op{
			C:      storageInstancesC,
			Id:     si.doc.Id,
			Assert: bson.D{ownerAssert},
		})

		// Check if the unit is assigned to a machine, and if the
		// associated machine storage has been attached yet. If not,
		// we can short-circuit the removal of the storage attachment.
		var assert interface{}
		removeStorageAttachment := true
		u, err := sb.unit(unit.Id())
		if err != nil {
			return nil, errors.Trace(err)
		}

		processAttachments := true
		var hostTag names.Tag = unit
		if u.ShouldBeAssigned() {
			machineId, err := u.AssignedMachineId()
			if errors.IsNotAssigned(err) {
				// The unit is not assigned to a machine, therefore
				// there can be no associated machine storage. It
				// is safe to remove.
				ops = append(ops, u.noAssignedMachineOp())
				processAttachments = false
			} else if err != nil {
				return nil, errors.Trace(err)
			}
			hostTag = names.NewMachineTag(machineId)
		}
		if processAttachments {
			volumeAttachment, filesystemAttachment, err := sb.storageHostAttachment(
				si, unit, hostTag,
			)
			if err != nil {
				return nil, errors.Trace(err)
			}
			if volumeAttachment != nil {
				var assert interface{}
				if _, err := volumeAttachment.Info(); err == nil {
					// The volume attachment has been provisioned,
					// so we cannot short-circuit the removal of
					// the storage attachment.
					removeStorageAttachment = false
					assert = txn.DocExists
				} else {
					assert = bson.D{{"info", bson.D{{"$exists", false}}}}
				}
				ops = append(ops, txn.Op{
					C: volumeAttachmentsC,
					Id: volumeAttachmentId(
						volumeAttachment.Host().Id(),
						volumeAttachment.Volume().Id(),
					),
					Assert: assert,
				})
			}
			if filesystemAttachment != nil {
				var assert interface{}
				if _, err := filesystemAttachment.Info(); err == nil {
					// The filesystem attachment has been provisioned,
					// so we cannot short-circuit the removal of
					// the storage attachment.
					removeStorageAttachment = false
					assert = txn.DocExists
				} else {
					assert = bson.D{{"info", bson.D{{"$exists", false}}}}
				}
				ops = append(ops, txn.Op{
					C: filesystemAttachmentsC,
					Id: filesystemAttachmentId(
						filesystemAttachment.Host().Id(),
						filesystemAttachment.Filesystem().Id(),
					),
					Assert: assert,
				})
			}
		}
		if removeStorageAttachment {
			// Short-circuit the removal of the storage attachment.
			return removeStorageAttachmentOps(sb, s, si, force, assert, ops...)
		}
		return append(ops, detachStorageOps(storage, unit)...), nil
	}
	return sb.mb.db().Run(buildTxn)
}
322471
func (container *Container) DetachAndUnmount(volumeEventLog func(name, action string, attributes map[string]string)) error {
	networkMounts := container.NetworkMounts()
	mountPaths := make([]string, 0, len(container.MountPoints)+len(networkMounts))

	for _, mntPoint := range container.MountPoints {
		dest, err := container.GetResourcePath(mntPoint.Destination)
		if err != nil {
			logrus.Warnf("Failed to get volume destination path for container '%s' at '%s' while lazily unmounting: %v", container.ID, mntPoint.Destination, err)
			continue
		}
		mountPaths = append(mountPaths, dest)
	}

	for _, m := range networkMounts {
		dest, err := container.GetResourcePath(m.Destination)
		if err != nil {
			logrus.Warnf("Failed to get volume destination path for container '%s' at '%s' while lazily unmounting: %v", container.ID, m.Destination, err)
			continue
		}
		mountPaths = append(mountPaths, dest)
	}

	for _, mountPath := range mountPaths {
		if err := mount.Unmount(mountPath); err != nil {
			logrus.WithError(err).WithField("container", container.ID).
				Warn("Unable to unmount")
		}
	}
	return container.UnmountVolumes(volumeEventLog)
}
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
}
889641
func (n *NodeDevice) DetachFlags(driverName string, flags uint32) error {
	cDriverName := C.CString(driverName)
	defer C.free(unsafe.Pointer(cDriverName))
	var err C.virError
	result := C.virNodeDeviceDetachFlagsWrapper(n.ptr, cDriverName, C.uint(flags), &err)
	if result == -1 {
		return makeError(&err)
	}
	return nil
}