Skip to content

Commit

Permalink
allow mounting volume by label (nanovms#662)
Browse files Browse the repository at this point in the history
* refactor volumes and allow mount by label

- remove JSON store, listing volumes now scans default volume dir
- <volume_name>:<volume_uuid> for filename, <volume_name>:<volume_label>
symlink for label
- if no label is specified, label is set to default
- if volume with default label exists, on next volume created without
label, attach label to the latest volume

* implement volume mount on local image operations

* add onprem volume tests

* add tests and fix bugs

* remove unused mock

* setup nightly for volume test

* fix create and mount volume with label

* Fix deleting volume by label and uuid.

* Also use volume name as label.

Co-authored-by: Fábio Ferreira <[email protected]>
  • Loading branch information
ronaudinho and fabioDMFerreira authored Oct 7, 2020
1 parent a15a8f2 commit b235d66
Show file tree
Hide file tree
Showing 20 changed files with 946 additions and 367 deletions.
13 changes: 12 additions & 1 deletion cmd/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func imageCreateCommandHandler(cmd *cobra.Command, args []string) {
pkg, _ := cmd.Flags().GetString("package")
pkg = strings.TrimSpace(pkg)
cmdargs, _ := cmd.Flags().GetStringArray("args")
mounts, _ := cmd.Flags().GetStringArray("mounts")

nightly, err := strconv.ParseBool(cmd.Flag("nightly").Value.String())
if err != nil {
Expand Down Expand Up @@ -59,6 +60,15 @@ func imageCreateCommandHandler(cmd *cobra.Command, args []string) {
}

prepareImages(c)
// borrow BuildDir from config
bd := c.BuildDir
c.BuildDir = api.LocalVolumeDir
err = api.AddMounts(mounts, c)
if err != nil {
exitWithError(err.Error())
}
c.BuildDir = bd

p, err := getCloudProvider(provider)
if err != nil {
exitWithError(err.Error())
Expand Down Expand Up @@ -204,7 +214,7 @@ func imageCreateCommandHandler(cmd *cobra.Command, args []string) {
func imageCreateCommand() *cobra.Command {
var (
config, pkg, imageName string
args []string
args, mounts []string
nightly bool
)

Expand All @@ -217,6 +227,7 @@ func imageCreateCommand() *cobra.Command {
cmdImageCreate.PersistentFlags().StringVarP(&config, "config", "c", "", "ops config file")
cmdImageCreate.PersistentFlags().StringVarP(&pkg, "package", "p", "", "ops package name")
cmdImageCreate.PersistentFlags().StringArrayVarP(&args, "args", "a", nil, "command line arguments")
cmdImageCreate.PersistentFlags().StringArrayVar(&mounts, "mounts", nil, "mount <volume_id:mount_path>")
cmdImageCreate.PersistentFlags().BoolVarP(&nightly, "nightly", "n", false, "nightly build")

cmdImageCreate.PersistentFlags().StringVarP(&imageName, "imagename", "i", "", "image name")
Expand Down
16 changes: 14 additions & 2 deletions cmd/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"log"
"os"
"path"
"strconv"
Expand Down Expand Up @@ -109,7 +110,6 @@ func buildFromPackage(packagepath string, c *api.Config) error {
}

func loadCommandHandler(cmd *cobra.Command, args []string) {

hypervisor := api.HypervisorInstance()
if hypervisor == nil {
panic(errors.New("No hypervisor found on $PATH"))
Expand Down Expand Up @@ -194,6 +194,16 @@ func loadCommandHandler(cmd *cobra.Command, args []string) {
pkgConfig.ManifestName = manifestName
setDefaultImageName(cmd, c)

mounts, _ := cmd.Flags().GetStringArray("mounts")
// borrow BuildDir from config
bd := c.BuildDir
c.BuildDir = api.LocalVolumeDir
err = api.AddMounts(mounts, c)
if err != nil {
log.Fatal(err)
}
c.BuildDir = bd

if !skipbuild {
if err = buildFromPackage(expackage, c); err != nil {
panic(err)
Expand Down Expand Up @@ -222,7 +232,7 @@ func loadCommandHandler(cmd *cobra.Command, args []string) {
// LoadCommand helps you to run application with package
func LoadCommand() *cobra.Command {
var (
ports, args []string
ports, args, mounts []string
force, debugflags, verbose bool
nightly, accel, bridged, local bool
skipbuild bool
Expand All @@ -248,5 +258,7 @@ func LoadCommand() *cobra.Command {
cmdLoadPackage.PersistentFlags().BoolVar(&accel, "accel", true, "use cpu virtualization extension")
cmdLoadPackage.PersistentFlags().BoolVarP(&skipbuild, "skipbuild", "s", false, "skip building package image")
cmdLoadPackage.PersistentFlags().BoolVarP(&local, "local", "l", false, "load local package")
cmdLoadPackage.PersistentFlags().StringArrayVar(&mounts, "mounts", nil, "<volume_id/label>:/<mount_path>")

return cmdLoadPackage
}
19 changes: 10 additions & 9 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,16 @@ func runCommandHandler(cmd *cobra.Command, args []string) {
c.NoTrace = noTrace
}
setDefaultImageName(cmd, c)
if len(mounts) > 0 {
for _, mount := range mounts {
vol := api.NewVolume(c)
err := vol.AttachOnRun(mount)
if err != nil {
log.Fatal(err)
}
}

// borrow BuildDir from config
bd := c.BuildDir
c.BuildDir = api.LocalVolumeDir
err = api.AddMounts(mounts, c)
if err != nil {
log.Fatal(err)
}
c.BuildDir = bd

if !skipbuild {
err = buildImages(c)
}
Expand Down Expand Up @@ -246,7 +247,7 @@ func RunCommand() *cobra.Command {
cmdRun.PersistentFlags().StringVarP(&manifestName, "manifest-name", "m", "", "save manifest to file")
cmdRun.PersistentFlags().BoolVar(&accel, "accel", true, "use cpu virtualization extension")
cmdRun.PersistentFlags().IntVarP(&smp, "smp", "", 1, "number of threads to use")
cmdRun.PersistentFlags().StringArrayVar(&mounts, "mounts", nil, "mount <volume_id:mount_path>")
cmdRun.PersistentFlags().StringArrayVar(&mounts, "mounts", nil, "<volume_id/label>:/<mount_path>")

return cmdRun
}
88 changes: 67 additions & 21 deletions cmd/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@ import (

func volumeCreateCommandHandler(cmd *cobra.Command, args []string) {
name := args[0]
if name == "" {
log.Fatal("name required")
}
data, _ := cmd.Flags().GetString("data")
size, _ := cmd.Flags().GetString("size")
config, _ := cmd.Flags().GetString("config")
provider, _ := cmd.Flags().GetString("provider")
provider, _ := cmd.Flags().GetString("target-cloud")
nightly, _ := cmd.Flags().GetBool("nightly")

conf := unWarpConfig(config)
Expand All @@ -35,17 +32,26 @@ func volumeCreateCommandHandler(cmd *cobra.Command, args []string) {
if conf.Mkfs == "" {
conf.Mkfs = path.Join(api.GetOpsHome(), version, "mkfs")
}
conf.BuildDir = api.LocalVolumeDir

vol := api.NewVolume(conf)
err = vol.Create(name, data, size, provider)
var vol api.VolumeService
if provider == "onprem" {
vol = &api.OnPrem{}
} else {
vol, err = getCloudProvider(provider)
if err != nil {
log.Fatal(err)
}
}
res, err := vol.CreateVolume(conf, name, data, size, provider)
if err != nil {
log.Fatal(err)
}
log.Printf("volume: %s created with UUID %s and label %s\n", res.Name, res.ID, res.Label)
}

func volumeCreateCommand() *cobra.Command {
var data string
var size string
var data, size string
cmdVolumeCreate := &cobra.Command{
Use: "create <volume_name>",
Short: "create volume",
Expand All @@ -59,14 +65,30 @@ func volumeCreateCommand() *cobra.Command {

func volumeListCommandHandler(cmd *cobra.Command, args []string) {
config, _ := cmd.Flags().GetString("config")
provider, _ := cmd.Flags().GetString("target-cloud")
conf := unWarpConfig(config)
vol := api.NewVolume(conf)
err := vol.GetAll()

var vol api.VolumeService
var err error
if provider == "onprem" {
vol = &api.OnPrem{}
} else {
vol, err = getCloudProvider(provider)
if err != nil {
log.Fatal(err)
}
}

conf.BuildDir = api.LocalVolumeDir

err = vol.GetAllVolumes(conf)
if err != nil {
log.Fatal(err)
}
}

// TODO might be nice to be able to filter by name/label
// api.GetVolumes can be implemented to achieve this
func volumeListCommand() *cobra.Command {
cmdVolumeList := &cobra.Command{
Use: "list",
Expand All @@ -77,19 +99,33 @@ func volumeListCommand() *cobra.Command {
}

func volumeDeleteCommandHandler(cmd *cobra.Command, args []string) {
id := args[0]
name := args[0]
config, _ := cmd.Flags().GetString("config")
provider, _ := cmd.Flags().GetString("target-cloud")
conf := unWarpConfig(config)
vol := api.NewVolume(conf)
err := vol.Delete(id)

var vol api.VolumeService
var err error
if provider == "onprem" {
vol = &api.OnPrem{}
} else {
vol, err = getCloudProvider(provider)
if err != nil {
log.Fatal(err)
}
}

conf.BuildDir = api.LocalVolumeDir

err = vol.DeleteVolume(conf, name)
if err != nil {
log.Fatal(err)
}
}

func volumeDeleteCommand() *cobra.Command {
cmdVolumeDelete := &cobra.Command{
Use: "delete <volume_id>",
Use: "delete <volume_name:volume_uuid>",
Short: "delete volume",
Run: volumeDeleteCommandHandler,
Args: cobra.MinimumNArgs(1),
Expand All @@ -99,20 +135,31 @@ func volumeDeleteCommand() *cobra.Command {

func volumeAttachCommandHandler(cmd *cobra.Command, args []string) {
image := args[0]
id := args[1]
name := args[1]
mount := args[2]
config, _ := cmd.Flags().GetString("config")
provider, _ := cmd.Flags().GetString("provider")
conf := unWarpConfig(config)
vol := api.NewVolume(conf)
err := vol.Attach(image, id, mount)

var vol api.VolumeService
var err error
if provider == "onprem" {
vol = &api.OnPrem{}
} else {
vol, err = getCloudProvider(provider)
if err != nil {
log.Fatal(err)
}
}
err = vol.AttachVolume(conf, image, name, mount)
if err != nil {
log.Fatal(err)
}
}

func volumeAttachCommand() *cobra.Command {
cmdVolumeAttach := &cobra.Command{
Use: "attach <image_name> <volume_id> <mount_path>",
Use: "attach <image_name> <volume_name> <mount_path>",
Short: "attach volume",
Run: volumeAttachCommandHandler,
Args: cobra.MinimumNArgs(3),
Expand All @@ -122,8 +169,7 @@ func volumeAttachCommand() *cobra.Command {

// VolumeCommands handles volumes related operations
func VolumeCommands() *cobra.Command {
var config string
var provider string
var config, provider string
var nightly bool
cmdVolume := &cobra.Command{
Use: "volume",
Expand All @@ -132,7 +178,7 @@ func VolumeCommands() *cobra.Command {
Args: cobra.OnlyValidArgs,
}
cmdVolume.PersistentFlags().StringVarP(&config, "config", "c", "", "ops config file")
cmdVolume.PersistentFlags().StringVarP(&provider, "provider", "p", "", "cloud provider")
cmdVolume.PersistentFlags().StringVarP(&provider, "target-cloud", "t", "onprem", "cloud provider")
cmdVolume.PersistentFlags().BoolVarP(&nightly, "nightly", "n", false, "nightly build")
cmdVolume.AddCommand(volumeCreateCommand())
cmdVolume.AddCommand(volumeListCommand())
Expand Down
27 changes: 27 additions & 0 deletions lepton/aws_volume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package lepton

// CreateVolume is a stub to satisfy VolumeService interface
func (a *AWS) CreateVolume(config *Config, name, data, size, provider string) (NanosVolume, error) {
var vol NanosVolume
return vol, nil
}

// GetAllVolumes is a stub to satisfy VolumeService interface
func (a *AWS) GetAllVolumes(config *Config) error {
return nil
}

// DeleteVolume is a stub to satisfy VolumeService interface
func (a *AWS) DeleteVolume(config *Config, name string) error {
return nil
}

// AttachVolume is a stub to satisfy VolumeService interface
func (a *AWS) AttachVolume(config *Config, image, name, mount string) error {
return nil
}

// DetachVolume is a stub to satisfy VolumeService interface
func (a *AWS) DetachVolume(config *Config, image, name string) error {
return nil
}
27 changes: 27 additions & 0 deletions lepton/azure_volume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package lepton

// CreateVolume is a stub to satisfy VolumeService interface
func (a *Azure) CreateVolume(config *Config, name, data, size, provider string) (NanosVolume, error) {
var vol NanosVolume
return vol, nil
}

// GetAllVolumes is a stub to satisfy VolumeService interface
func (a *Azure) GetAllVolumes(config *Config) error {
return nil
}

// DeleteVolume is a stub to satisfy VolumeService interface
func (a *Azure) DeleteVolume(config *Config, name string) error {
return nil
}

// AttachVolume is a stub to satisfy VolumeService interface
func (a *Azure) AttachVolume(config *Config, image, name, mount string) error {
return nil
}

// DetachVolume is a stub to satisfy VolumeService interface
func (a *Azure) DetachVolume(config *Config, image, name string) error {
return nil
}
27 changes: 27 additions & 0 deletions lepton/digital_ocean_volume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package lepton

// CreateVolume is a stub to satisfy VolumeService interface
func (do *DigitalOcean) CreateVolume(config *Config, name, data, size, provider string) (NanosVolume, error) {
var vol NanosVolume
return vol, nil
}

// GetAllVolumes is a stub to satisfy VolumeService interface
func (do *DigitalOcean) GetAllVolumes(config *Config) error {
return nil
}

// DeleteVolume is a stub to satisfy VolumeService interface
func (do *DigitalOcean) DeleteVolume(config *Config, name string) error {
return nil
}

// AttachVolume is a stub to satisfy VolumeService interface
func (do *DigitalOcean) AttachVolume(config *Config, image, name, mount string) error {
return nil
}

// DetachVolume is a stub to satisfy VolumeService interface
func (do *DigitalOcean) DetachVolume(config *Config, image, name string) error {
return nil
}
Loading

0 comments on commit b235d66

Please sign in to comment.