Skip to content

Commit

Permalink
fix #38
Browse files Browse the repository at this point in the history
  • Loading branch information
mhewedy committed Dec 19, 2020
1 parent 14715ba commit 9dc27bd
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 23 deletions.
42 changes: 28 additions & 14 deletions command/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,47 @@ var updateCmd = &cobra.Command{
Long: "Update configuration of a VM",
Example: `
You can either change the cpu and/or mem or you can use the update command to shrink the disk.
To change the VM to use 2 cores and 512MB memory
$ vermin update vm_01 --cpus 2 --mem 512
To shrink the disk size on the host machine
$ vermin update vm_01 --shrink-disk
`,
Run: func(cmd *cobra.Command, args []string) {
vmName := normalizeVmName(args[0])
var script string
if len(args) > 1 {
script = args[1]
checkFilePath(script)
}
cpus, _ := cmd.Flags().GetInt("cpus")
mem, _ := cmd.Flags().GetInt("mem")

if err := vms.Modify(vmName, cpus, mem); err != nil {
fmt.Println(err)
os.Exit(1)
shrink, _ := cmd.Flags().GetBool("shrink-disk")

if shrink {
if err := vms.Shrink(vmName); err != nil {
fmt.Println(err)
os.Exit(1)
}
} else {
cpus, _ := cmd.Flags().GetInt("cpus")
mem, _ := cmd.Flags().GetInt("mem")

if err := vms.Modify(vmName, cpus, mem); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
},
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("vm required")
}

cpus, _ := cmd.Flags().GetInt("cpus")
mem, _ := cmd.Flags().GetInt("mem")
shrink, _ := cmd.Flags().GetBool("shrink-disk")
if !shrink {
cpus, _ := cmd.Flags().GetInt("cpus")
mem, _ := cmd.Flags().GetInt("mem")

if cpus == 0 && mem == 0 {
return errors.New("should specify cpus and/or mem specs")
if cpus == 0 && mem == 0 {
return errors.New("should specify cpus and/or mem specs")
}
}
return nil
},
Expand All @@ -78,4 +91,5 @@ func init() {
// is called directly, e.g.:
updateCmd.Flags().IntP("cpus", "c", 0, "Number of cpu cores")
updateCmd.Flags().IntP("mem", "m", 0, "Memory size in mega bytes")
updateCmd.Flags().BoolP("shrink-disk", "", false, "Shrink the disk to reduce the size on the host machine")
}
16 changes: 12 additions & 4 deletions hypervisor/base/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type Hypervisor interface {
GetBoxInfo(vmName string) (*Box, error)

GetSubnet() (*Subnet, error)

ShrinkDisk(vmName string) error
}

type MountPath struct {
Expand All @@ -43,10 +45,16 @@ type MountPath struct {
}

type Box struct {
CPU string
Mem string
DiskSize string
MACAddr string
CPU string
Mem string
Disk *Disk
MACAddr string
}

type Disk struct {
Size string
UUID string
Location string
}

type Subnet struct {
Expand Down
10 changes: 10 additions & 0 deletions hypervisor/hypervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,13 @@ func GetSubnet() (*base.Subnet, error) {

return h.GetSubnet()
}

func ShrinkDisk(vmName string) error {

h, err := detect()
if err != nil {
return err
}

return h.ShrinkDisk(vmName)
}
21 changes: 17 additions & 4 deletions hypervisor/virtualbox/box.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
)

type vbox struct {
Expand All @@ -16,6 +17,7 @@ type vbox struct {
MediaRegistry struct {
HardDisks struct {
HardDisk []struct {
UUID string `xml:"uuid,attr"`
Location string `xml:"location,attr"`
} `xml:"HardDisk"`
} `xml:"HardDisks"`
Expand Down Expand Up @@ -55,11 +57,22 @@ func getBoxInfo(vm string) (*base.Box, error) {
diskLocation = vb.Machine.MediaRegistry.HardDisks.HardDisk[0].Location
}

diskUUID := ""
if len(vb.Machine.MediaRegistry.HardDisks.HardDisk) > 0 {
diskUUID = strings.TrimFunc(vb.Machine.MediaRegistry.HardDisks.HardDisk[0].UUID, func(r rune) bool {
return r == '{' || r == '}'
})
}

return &base.Box{
CPU: cpuCount,
Mem: vb.Machine.Hardware.Memory.RAMSize,
DiskSize: getDiskSizeInGB(vm, diskLocation),
MACAddr: vb.Machine.Hardware.Network.Adapter.MACAddress,
CPU: cpuCount,
Mem: vb.Machine.Hardware.Memory.RAMSize,
Disk: &base.Disk{
Size: getDiskSizeInGB(vm, diskLocation),
Location: diskLocation,
UUID: diskUUID,
},
MACAddr: vb.Machine.Hardware.Network.Adapter.MACAddress,
}, nil
}

Expand Down
93 changes: 93 additions & 0 deletions hypervisor/virtualbox/disk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package virtualbox

import (
"fmt"
"github.com/mhewedy/vermin/db"
"github.com/mhewedy/vermin/hypervisor/base"
"github.com/mhewedy/vermin/log"
"github.com/mhewedy/vermin/progress"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
)

func (*virtualbox) ShrinkDisk(vmName string) error {

stop := progress.Show("Shrinking disk", false)
defer stop()

box, err := getBoxInfo(vmName)
if err != nil {
return err
}

origDiskPath := filepath.Join(db.GetVMPath(vmName), box.Disk.Location)

if isVMDK(box.Disk) {

tmpDir, err := ioutil.TempDir("", "vermin_disk_shrink_"+vmName)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)

vdiPath := filepath.Join(tmpDir, box.Disk.Location+".vdi")
newVMDKPath := filepath.Join(tmpDir, box.Disk.Location)

log.Debug("clone vmdk disk into vdi")
if err := vboxManage("clonehd", origDiskPath, vdiPath, "--format", "vdi").Run(); err != nil {
return err
}
log.Debug("shrink the vdi")
if err := vboxManage("modifyhd", vdiPath, "--compact").Run(); err != nil {
return err
}
log.Debug("clone the vdi back into a new vmdk")
if err := vboxManage("clonehd", vdiPath, newVMDKPath, "--format", "vmdk").Run(); err != nil {
return err
}
log.Debug("set the uuid of the new vmdk with the same uuid of the old vmdk")
if err := vboxManage("internalcommands", "sethduuid", newVMDKPath, box.Disk.UUID).Run(); err != nil {
return err
}
log.Debug("copy the new vmdk into the same location of the old vmdk")
return copyFile(newVMDKPath, origDiskPath)

} else if isVDI(box.Disk) {
return vboxManage("modifyhd", origDiskPath, "--compact").Run()
} else {
return fmt.Errorf("unsupported disk format %s", box.Disk.Location)
}
}

func isVMDK(disk *base.Disk) bool {
return strings.HasSuffix(strings.ToLower(disk.Location), ".vmdk")
}

func isVDI(disk *base.Disk) bool {
return strings.HasSuffix(strings.ToLower(disk.Location), ".vdi")
}

// Copy the src file to dst. Any existing file will be overwritten and will not
// copy file attributes.
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()

out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()

_, err = io.Copy(out, in)
if err != nil {
return err
}
return out.Close()
}
2 changes: 1 addition & 1 deletion vms/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type vmInfo struct {
}

func (v vmInfo) String() string {
return fmt.Sprintf(format, v.name, v.image, v.box.CPU, v.box.Mem, v.box.DiskSize, v.tags)
return fmt.Sprintf(format, v.name, v.image, v.box.CPU, v.box.Mem, v.box.Disk.Size, v.tags)
}

type vmInfoList []vmInfo
Expand Down
40 changes: 40 additions & 0 deletions vms/shrink_disk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package vms

import (
"fmt"
"github.com/mhewedy/vermin/cmd/ssh"
"github.com/mhewedy/vermin/hypervisor"
"github.com/mhewedy/vermin/progress"
)

func Shrink(vmName string) error {

fmt.Println("The VM will restarted as part of the disk shrinking process.\n" +
"Please note that, this is a time-consuming process and requires a free disk space on your disk.")

if err := ssh.EstablishConn(vmName); err != nil {
return err
}

if err := zerofyDisk(vmName); err != nil {
return err
}

if err := Stop(vmName); err != nil {
return err
}

if err := hypervisor.ShrinkDisk(vmName); err != nil {
return err
}

return Start(vmName)
}

func zerofyDisk(vmName string) error {
stop := progress.Show("Filling free disk space with zeros", false)
defer stop()
// sometimes the an error returned, however the command succeed
_, _ = ssh.Execute(vmName, "sh -c 'cat /dev/zero > zero.fill; sync; sleep 1; sync; rm -f zero.fill'")
return nil
}

0 comments on commit 9dc27bd

Please sign in to comment.