Пример #1
0
// Create will create a new volume with the volumeName and opts.
func (d *driver) Create(
	ctx types.Context,
	volumeName string,
	opts *types.VolumeCreateOpts) (*types.Volume, error) {

	if volumeName == "" {
		return nil, goof.New("missing volume name or ID")
	}

	optsNew := &types.VolumeCreateOpts{}
	az := d.availabilityZone()
	optsNew.AvailabilityZone = &az
	i, _ := strconv.Atoi(d.size())
	size := int64(i)
	optsNew.Size = &size
	volumeType := d.volumeType()
	optsNew.Type = &volumeType
	io, _ := strconv.Atoi(d.iops())
	IOPS := int64(io)
	optsNew.IOPS = &IOPS

	if opts.Opts.IsSet("availabilityZone") {
		az = opts.Opts.GetString("availabilityZone")
	}
	if opts.Opts.IsSet("size") {
		size = opts.Opts.GetInt64("size")
	}
	if opts.Opts.IsSet("volumeType") {
		volumeType = opts.Opts.GetString("volumeType")
	}
	if opts.Opts.IsSet("type") {
		volumeType = opts.Opts.GetString("type")
	}
	if opts.Opts.IsSet("iops") {
		IOPS = opts.Opts.GetInt64("iops")
	}

	optsNew.Opts = opts.Opts

	ctx.WithFields(log.Fields{
		"volumeName":       volumeName,
		"availabilityZone": az,
		"size":             size,
		"volumeType":       volumeType,
		"IOPS":             IOPS,
		"opts":             opts}).Info("creating volume")

	client := context.MustClient(ctx)
	vol, err := client.Storage().VolumeCreate(ctx, volumeName, optsNew)
	if err != nil {
		return nil, err
	}

	ctx.WithFields(log.Fields{
		"volumeName": volumeName,
		"vol":        vol}).Info("volume created")

	return vol, nil
}
Пример #2
0
func (d *driver) volumeInspectByID(
	ctx types.Context,
	volumeID string,
	attachments types.VolumeAttachmentsTypes,
	opts types.Store) (*types.Volume, error) {
	client := context.MustClient(ctx)
	vol, err := client.Storage().VolumeInspect(ctx, volumeID,
		&types.VolumeInspectOpts{
			Attachments: attachments})
	if err != nil {
		return nil, err
	}
	return vol, nil
}
Пример #3
0
// Path will return the mounted path of the volumeName or volumeID.
func (d *driver) Path(
	ctx types.Context,
	volumeID, volumeName string,
	opts types.Store) (string, error) {

	ctx.WithFields(log.Fields{
		"volumeName": volumeName,
		"volumeID":   volumeID,
		"opts":       opts}).Info("getting path to volume")

	vol, err := d.volumeInspectByIDOrName(
		ctx, volumeID, volumeName, types.VolAttReqTrue, opts)
	if err != nil {
		return "", err
	} else if vol == nil {
		return "", utils.NewNotFoundError(
			fmt.Sprintf("volumeID=%s,volumeName=%s", volumeID, volumeName))
	}

	if len(vol.Attachments) == 0 {
		return "", nil
	}

	client := context.MustClient(ctx)

	mounts, err := client.OS().Mounts(
		ctx, vol.Attachments[0].DeviceName, "", opts)
	if err != nil {
		return "", err
	}

	if len(mounts) == 0 {
		return "", nil
	}

	volPath := d.volumeMountPath(mounts[0].MountPoint)

	ctx.WithFields(log.Fields{
		"volPath": volPath,
		"vol":     vol}).Info("returning path to volume")

	return volPath, nil
}
Пример #4
0
func (d *driver) volumeInspectByIDOrName(
	ctx types.Context,
	volumeID, volumeName string,
	attachments types.VolumeAttachmentsTypes,
	opts types.Store) (*types.Volume, error) {

	if volumeID != "" && volumeName != "" {
		return nil, goof.New("specify either volumeID or volumeName")
	}

	client := context.MustClient(ctx)

	var obj *types.Volume
	if volumeID != "" {
		var err error
		obj, err = d.volumeInspectByID(ctx, volumeID, attachments, opts)
		if err != nil {
			return nil, err
		}
	} else {
		objs, err := client.Storage().Volumes(
			ctx, &types.VolumesOpts{Attachments: 0})
		if err != nil {
			return nil, err
		}
		for _, o := range objs {
			if strings.EqualFold(volumeName, o.Name) {
				obj, err = d.volumeInspectByID(ctx, o.ID, attachments, opts)
				if err != nil {
					return nil, err
				}
				break
			}
		}
	}

	if obj == nil {
		return nil, utils.NewNotFoundError(
			fmt.Sprintf("volumeID=%s,volumeName=%s", volumeID, volumeName))
	}
	return obj, nil
}
Пример #5
0
// List returns all available volume mappings.
func (d *driver) List(
	ctx types.Context,
	opts types.Store) ([]types.VolumeMapping, error) {

	client := context.MustClient(ctx)
	vols, err := client.Storage().Volumes(
		ctx,
		&types.VolumesOpts{
			Attachments: opts.GetAttachments(),
			Opts:        opts,
		},
	)
	if err != nil {
		return nil, err
	}

	serviceName, serviceNameOK := context.ServiceName(ctx)
	if !serviceNameOK {
		return nil, goof.New("service name is missing")
	}

	volMaps := []types.VolumeMapping{}
	for _, v := range vols {
		vs := make(map[string]interface{})
		vs["name"] = v.Name
		vs["size"] = v.Size
		vs["iops"] = v.IOPS
		vs["type"] = v.Type
		vs["availabilityZone"] = v.AvailabilityZone
		vs["fields"] = v.Fields
		vs["service"] = serviceName
		vs["server"] = serviceName
		volMaps = append(volMaps, &volumeMapping{
			Name:             v.Name,
			VolumeMountPoint: v.MountPoint(),
			VolumeStatus:     vs,
		})
	}

	return volMaps, nil
}
Пример #6
0
// Remove will remove a volume of volumeName.
func (d *driver) Remove(
	ctx types.Context,
	volumeName string,
	opts types.Store) error {

	if volumeName == "" {
		return goof.New("missing volume name or ID")
	}

	vol, err := d.volumeInspectByIDOrName(
		ctx, "", volumeName, 0, opts)
	if err != nil {
		return err
	}

	if vol == nil {
		return goof.New("volume not found")
	}

	client := context.MustClient(ctx)

	return client.Storage().VolumeRemove(ctx, vol.ID, opts)
}
Пример #7
0
// Unmount will unmount the specified volume by volumeName or volumeID.
func (d *driver) Unmount(
	ctx types.Context,
	volumeID, volumeName string,
	opts types.Store) (*types.Volume, error) {

	ctx.WithFields(log.Fields{
		"volumeName": volumeName,
		"volumeID":   volumeID,
		"opts":       opts}).Info("unmounting volume")

	if volumeName == "" && volumeID == "" {
		return nil, goof.New("missing volume name or ID")
	}

	vol, err := d.volumeInspectByIDOrName(
		ctx, volumeID, volumeName,
		types.VolAttReqWithDevMapOnlyVolsAttachedToInstance, opts)
	if err != nil {
		return nil, err
	}

	if len(vol.Attachments) == 0 {
		return nil, nil
	}

	client := context.MustClient(ctx)

	inst, err := client.Storage().InstanceInspect(ctx, utils.NewStore())
	if err != nil {
		return nil, goof.New("problem getting instance ID")
	}
	var ma *types.VolumeAttachment
	for _, att := range vol.Attachments {
		if att.InstanceID.ID == inst.InstanceID.ID {
			ma = att
			break
		}
	}

	if ma == nil {
		return nil, goof.New("no attachment found for instance")
	}

	if ma.DeviceName == "" {
		return nil, goof.New("no device name found for attachment")
	}

	mounts, err := client.OS().Mounts(
		ctx, ma.DeviceName, "", opts)
	if err != nil {
		return nil, err
	}

	for _, mount := range mounts {
		ctx.WithField("mount", mount).Debug("retrieved mount")
	}

	if len(mounts) > 0 {
		for _, mount := range mounts {
			ctx.WithField("mount", mount).Debug("unmounting mount point")
			err = client.OS().Unmount(ctx, mount.MountPoint, opts)
			if err != nil {
				return nil, err
			}
		}
	}

	vol, err = client.Storage().VolumeDetach(ctx, vol.ID,
		&types.VolumeDetachOpts{
			Force: opts.GetBool("force"),
			Opts:  utils.NewStore(),
		})
	if err != nil {
		return nil, err
	}

	ctx.WithFields(log.Fields{
		"vol": vol}).Info("unmounted and detached volume")

	return vol, nil
}
Пример #8
0
// Mount will return a mount point path when specifying either a volumeName
// or volumeID.  If a overwriteFs boolean is specified it will overwrite
// the FS based on newFsType if it is detected that there is no FS present.
func (d *driver) Mount(
	ctx types.Context,
	volumeID, volumeName string,
	opts *types.VolumeMountOpts) (string, *types.Volume, error) {

	ctx.WithFields(log.Fields{
		"volumeName": volumeName,
		"volumeID":   volumeID,
		"opts":       opts}).Info("mounting volume")

	vol, err := d.volumeInspectByIDOrName(
		ctx, volumeID, volumeName,
		types.VolAttReqWithDevMapOnlyVolsAttachedToInstanceOrUnattachedVols,
		opts.Opts)
	if isErrNotFound(err) && d.volumeCreateImplicit() {
		var err error
		if vol, err = d.Create(ctx, volumeName, &types.VolumeCreateOpts{
			Opts: utils.NewStore(),
		}); err != nil {
			return "", nil, goof.WithError(
				"problem creating volume implicitly", err)
		}
	} else if err != nil {
		return "", nil, err
	}

	if vol == nil {
		return "", nil, goof.New("no volume returned or created")
	}

	client := context.MustClient(ctx)
	if len(vol.Attachments) == 0 || opts.Preempt {
		mp, err := d.getVolumeMountPath(vol.Name)
		if err != nil {
			return "", nil, err
		}

		ctx.Debug("performing precautionary unmount")
		_ = client.OS().Unmount(ctx, mp, opts.Opts)

		var token string
		vol, token, err = client.Storage().VolumeAttach(
			ctx, vol.ID, &types.VolumeAttachOpts{
				Force: opts.Preempt,
				Opts:  utils.NewStore(),
			})
		if err != nil {
			return "", nil, err
		}

		if token != "" {
			opts := &types.WaitForDeviceOpts{
				LocalDevicesOpts: types.LocalDevicesOpts{
					ScanType: apiconfig.DeviceScanType(d.config),
					Opts:     opts.Opts,
				},
				Token:   token,
				Timeout: apiconfig.DeviceAttachTimeout(d.config),
			}

			_, _, err = client.Executor().WaitForDevice(ctx, opts)
			if err != nil {
				return "", nil, goof.WithError(
					"problem with device discovery", err)
			}
		}

		vol, err = d.volumeInspectByIDOrName(
			ctx, vol.ID, "", types.VolAttReqTrue, opts.Opts)
		if err != nil {
			return "", nil, err
		}

	}

	if len(vol.Attachments) == 0 {
		return "", nil, goof.New("volume did not attach")
	}

	inst, err := client.Storage().InstanceInspect(ctx, utils.NewStore())
	if err != nil {
		return "", nil, goof.New("problem getting instance ID")
	}
	var ma *types.VolumeAttachment
	for _, att := range vol.Attachments {
		if att.InstanceID.ID == inst.InstanceID.ID {
			ma = att
			break
		}
	}

	if ma == nil {
		return "", nil, goof.New("no local attachment found")
	}

	if ma.DeviceName == "" {
		return "", nil, goof.New("no device name returned")
	}

	mounts, err := client.OS().Mounts(
		ctx, ma.DeviceName, "", opts.Opts)
	if err != nil {
		return "", nil, err
	}

	if len(mounts) > 0 {
		return d.volumeMountPath(mounts[0].MountPoint), vol, nil
	}

	if opts.NewFSType == "" {
		opts.NewFSType = d.fsType()
	}

	if err := client.OS().Format(
		ctx,
		ma.DeviceName,
		&types.DeviceFormatOpts{
			NewFSType:   opts.NewFSType,
			OverwriteFS: opts.OverwriteFS,
		}); err != nil {
		return "", nil, err
	}

	mountPath, err := d.getVolumeMountPath(vol.Name)
	if err != nil {
		return "", nil, err
	}

	if err := os.MkdirAll(mountPath, 0755); err != nil {
		return "", nil, err
	}

	if err := client.OS().Mount(
		ctx,
		ma.DeviceName,
		mountPath,
		&types.DeviceMountOpts{}); err != nil {
		return "", nil, err
	}

	mntPath := d.volumeMountPath(mountPath)

	fields := log.Fields{
		"vol":     vol,
		"mntPath": mntPath,
	}
	ctx.WithFields(fields).Info("volume mounted")

	return mntPath, vol, nil
}