Skip to content

Commit

Permalink
implement volume mount on local image operations
Browse files Browse the repository at this point in the history
  • Loading branch information
ronaudinho authored and fabioDMFerreira committed Oct 7, 2020
1 parent b47e4ae commit 6d54f1d
Showing 1 changed file with 221 additions and 0 deletions.
221 changes: 221 additions & 0 deletions lepton/onprem_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ func (op *OnPrem) CreateVolume(config *Config, name, data, size, provider string

if data != "" {
config.Dirs = append(config.Dirs, data)
<<<<<<< HEAD
mnfPath = path.Join(config.BuildDir, mnf)
=======
mnfPath = path.Join(localVolumeDir, mnf)
fmt.Println(mnfPath)
>>>>>>> implement volume mount on local image operations
err := buildVolumeManifest(config, mnfPath)
if err != nil {
return vol, err
Expand All @@ -86,12 +91,20 @@ func (op *OnPrem) CreateVolume(config *Config, name, data, size, provider string
uuid := mkfsCommand.GetUUID()

raw := fmt.Sprintf("%s%s%s.raw", name, VolumeDelimiter, uuid)
<<<<<<< HEAD
rawPath := path.Join(config.BuildDir, raw)
=======
rawPath := path.Join(localVolumeDir, raw)
>>>>>>> implement volume mount on local image operations
err = os.Rename(tmpPath, rawPath)
if err != nil {
fmt.Printf("volume: UUID: failed adding UUID info for volume %s\n", name)
fmt.Printf("rename the file to %s%s%s should you want to attach it by UUID\n", name, VolumeDelimiter, uuid)
<<<<<<< HEAD
fmt.Printf("symlink the file to %s should you want to attach it by label\n", name)
=======
fmt.Printf("symlink the file to %s%s%s should you want to attach it by label\n", name, VolumeDelimiter, label)
>>>>>>> implement volume mount on local image operations
} else {
symlinkVolume(config.BuildDir, name, uuid)
}
Expand All @@ -109,7 +122,11 @@ func (op *OnPrem) CreateVolume(config *Config, name, data, size, provider string

// GetAllVolumes prints list of all onprem nanos-managed volumes
func (op *OnPrem) GetAllVolumes(config *Config) error {
<<<<<<< HEAD
vols, err := GetVolumes(config.BuildDir, nil)
=======
vols, err := GetVolumes(nil)
>>>>>>> implement volume mount on local image operations
if err != nil {
return err
}
Expand All @@ -127,6 +144,7 @@ func (op *OnPrem) GetAllVolumes(config *Config) error {
return nil
}

<<<<<<< HEAD
// DeleteVolume deletes nanos-managed volume (filename and symlink)
func (op *OnPrem) DeleteVolume(config *Config, name string) error {
query := map[string]string{
Expand All @@ -149,6 +167,19 @@ func (op *OnPrem) DeleteVolume(config *Config, name string) error {
err = os.Remove(symlinkPath)
if err != nil {
return err
=======
// isVolumeExists checks if onprem nanos-managed volume
// with the given name exists
func (op *OnPrem) isVolumeExists(name string) (bool, error) {
fi, err := ioutil.ReadDir(localVolumeDir)
if err != nil {
return false, err
}

for _, vol := range fi {
if vol.Name() == name {
return true, nil
>>>>>>> implement volume mount on local image operations
}
}

Expand All @@ -160,7 +191,11 @@ func (op *OnPrem) DeleteVolume(config *Config, name string) error {
// on `ops image create --mount`, it simply creates a mount path
// with the given volume label
// label can refer to volume UUID or volume label
<<<<<<< HEAD
func (op *OnPrem) AttachVolume(config *Config, image, name, mount string) error {
=======
func (op *OnPrem) AttachVolume(config *Config, image, name, label, mount string) error {
>>>>>>> implement volume mount on local image operations
fmt.Println("not implemented")
fmt.Println("use <ops run> or <ops load> with --mounts flag instead")
fmt.Println("alternatively, use <ops image create -t onprem> with --mounts flag")
Expand All @@ -169,7 +204,11 @@ func (op *OnPrem) AttachVolume(config *Config, image, name, mount string) error
}

// DetachVolume detaches volume
<<<<<<< HEAD
func (op *OnPrem) DetachVolume(config *Config, image, name string) error {
=======
func (op *OnPrem) DetachVolume(config *Config, image, label string) error {
>>>>>>> implement volume mount on local image operations
fmt.Println("not implemented")
return nil
}
Expand Down Expand Up @@ -233,12 +272,21 @@ func cleanUpVolumeManifest(file string) error {
// symlinkVolume creates a symlink to volume that acts as volume label
// if label of the same name exists for a volume, removes the label from the older volume
// and assigns it to the newly created volume
<<<<<<< HEAD
func symlinkVolume(dir, name, uuid string) error {
msg := fmt.Sprintf("volume: label: failed adding label info for volume %s\n", name)
msg = fmt.Sprintf("%vsymlink the file to %s should you want to attach it by label\n", msg, name)

src := path.Join(dir, fmt.Sprintf("%s%s%s.raw", name, VolumeDelimiter, uuid))
dst := path.Join(dir, fmt.Sprintf("%s.raw", name))
=======
func symlinkVolume(name, uuid, label string) error {
msg := fmt.Sprintf("volume: label: failed adding label info for volume %s\n", name)
msg = fmt.Sprintf("%vsymlink the file to %s%s%s should you want to attach it by label\n", msg, name, VolumeDelimiter, label)

src := path.Join(localVolumeDir, fmt.Sprintf("%s%s%s.raw", name, VolumeDelimiter, uuid))
dst := path.Join(localVolumeDir, fmt.Sprintf("%s%s%s.raw", name, VolumeDelimiter, label))
>>>>>>> implement volume mount on local image operations

_, err := os.Lstat(dst)
if err == nil {
Expand Down Expand Up @@ -442,3 +490,176 @@ func addMounts(config *Config) error {

return nil
}

// GetVolumes get nanos volume using filter
// TODO pass dir to allow for cleaner testing
// TODO might be better to interface this
func GetVolumes(query map[string]string) ([]NanosVolume, error) {
var vols []NanosVolume
mvols := make(map[string]NanosVolume)

fi, err := ioutil.ReadDir(localVolumeDir)
if err != nil {
return vols, err
}

for _, info := range fi {
if info.IsDir() {
continue
}

// checks if volume has been scanned from its symlink
_, ok := mvols[info.Name()]
if ok {
continue
}

link, err := os.Readlink(path.Join(localVolumeDir, info.Name()))
if err == nil {
var id string
var label string
nl := strings.Split(strings.TrimSuffix(info.Name(), ".raw"), VolumeDelimiter)
if len(nl) == 2 {
label = nl[1]
}
src, err := os.Stat(link)
// ignore dangling symlink
if err != nil {
continue
}
nu := strings.Split(strings.TrimSuffix(src.Name(), ".raw"), VolumeDelimiter)
if len(nu) == 2 {
id = nu[1]
}
mvols[src.Name()] = NanosVolume{
ID: id,
Name: nu[0],
Label: label,
Size: bytes2Human(src.Size()),
Path: path.Join(localVolumeDir, src.Name()),
}
} else {
var id string
nu := strings.Split(strings.TrimSuffix(info.Name(), ".raw"), VolumeDelimiter)
if len(nu) == 2 {
id = nu[1]
}
mvols[info.Name()] = NanosVolume{
ID: id,
Name: nu[0],
Size: bytes2Human(info.Size()),
Path: path.Join(localVolumeDir, info.Name()),
}
}
}

for _, vol := range mvols {
vols = append(vols, vol)
}
if query == nil {
return vols, nil
}

vols = filterVolume(vols, query)
return vols, nil
}

// emulate kv store to easily extend query terms
// although multiple marshals/unmarshals makes this too convoluted
// another approach is to simply filter by designated field and repeat
// each time we need to query another field
func filterVolume(all []NanosVolume, query map[string]string) []NanosVolume {
var vols []NanosVolume
b, _ := json.Marshal(all)
// empty slice and repopulate with filtered results
all = nil
var tmpVols []map[string]interface{}
json.Unmarshal(b, &tmpVols)
for k, v := range query {
var vol NanosVolume
for _, tmp := range tmpVols {
// check if key is queried
vv, ok := tmp[k]
if !ok {
continue
}

if vv == v {
b, _ := json.Marshal(tmp)
json.Unmarshal(b, &vol)
vols = append(vols, vol)
}
}
}
return vols
}

// AddMounts adds Mounts and RunConfig.Mounts to image from flags
func AddMounts(mounts []string, config *Config) error {
if config.Mounts == nil {
config.Mounts = make(map[string]string)
}
query := make(map[string]string)

for _, mnt := range mounts {
lm := strings.Split(mnt, VolumeDelimiter)
if len(lm) != 2 {
return fmt.Errorf("mount config invalid: %s", mnt)
}
if lm[1][0] != '/' {
return fmt.Errorf("mount config invalid: %s", mnt)
}

query["id"] = lm[0]
query["label"] = lm[0]
vols, err := GetVolumes(query)
if err != nil {
return err
}

if len(vols) == 0 {
return fmt.Errorf("volume with uuid/label %s not found", lm[0])
} else if len(vols) > 1 {
return fmt.Errorf("ambiguous volume uuid/label: %s: multiple volumes found", lm[0])
}
config.Mounts[lm[0]] = lm[1]
config.RunConfig.Mounts = append(config.RunConfig.Mounts, vols[0].Path)
}

return nil
}

// addMounts adds RunConfig.Mounts to image from existing Mounts
// to simulate attach/detach volume locally
func addMounts(config *Config) error {
if config.Mounts == nil {
return fmt.Errorf("no mount configuration found for image")
}
query := make(map[string]string)

for mnt, _ := range config.Mounts {
lm := strings.Split(mnt, VolumeDelimiter)
if len(lm) != 2 {
return fmt.Errorf("mount config invalid: %s", mnt)
}
if lm[1][0] != '/' {
return fmt.Errorf("mount config invalid: %s", mnt)
}

query["id"] = lm[0]
query["label"] = lm[0]
vols, err := GetVolumes(query)
if err != nil {
return err
}

if len(vols) == 0 {
return fmt.Errorf("volume with uuid/label %s not found", lm[0])
} else if len(vols) > 1 {
return fmt.Errorf("ambiguous volume uuid/label: %s: multiple volumes found", lm[0])
}
config.RunConfig.Mounts = append(config.RunConfig.Mounts, vols[0].Path)
}

return nil
}

0 comments on commit 6d54f1d

Please sign in to comment.