// 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 }
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 }
// 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 }
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 }
// 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 }
// 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) }
// 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 }
// 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 }