code: func (os *OpenStack) AttachDisk(instanceID, volumeID string) (string, error) {
  	volume, err := os.getVolume(volumeID)
  	if err != nil {
  		return "", err
  	}
  	if volume.Status != VolumeAvailableStatus {
  		errmsg := fmt.Sprintf("volume %s status is %s, not %s, can not be attached to instance %s.", volume.Name, volume.Status, VolumeAvailableStatus, instanceID)
  		glog.Error(errmsg)
  		return "", errors.New(errmsg)
  	}
  	cClient, err := os.NewComputeV2()
  	if err != nil {
  		return "", err
  	}
  
  	if volume.AttachedServerID != "" {
  		if instanceID == volume.AttachedServerID {
  			glog.V(4).Infof("Disk %s is already attached to instance %s", volumeID, instanceID)
  			return volume.ID, nil
  		}
  		glog.V(2).Infof("Disk %s is attached to a different instance (%s), detaching", volumeID, volume.AttachedServerID)
  		err = os.DetachDisk(volume.AttachedServerID, volumeID)
  		if err != nil {
  			return "", err
  		}
  	}
  
  	// add read only flag here if possible spothanis
  	_, err = volumeattach.Create(cClient, instanceID, &volumeattach.CreateOpts{
  		VolumeID: volume.ID,
  	}).Extract()
  	if err != nil {
  		glog.Errorf("Failed to attach %s volume to %s compute: %v", volumeID, instanceID, err)
  		return "", err
  	}
  	glog.V(2).Infof("Successfully attached %s volume to %s compute", volumeID, instanceID)
  	return volume.ID, nil
  }
docs: // AttachDisk attaches specified cinder volume to the compute running kubelet