Skip to content

Commit

Permalink
add vbox integration (#984)
Browse files Browse the repository at this point in the history
* Add virtual box provider (closes #888)

* move wslpath utilities to own package

* remove temporary images after converting for the right format in OCI and Hyper-V providers

* Add virtual box images commands

* Add virtual box instance commands
  • Loading branch information
fabioDMFerreira authored Apr 8, 2021
1 parent 1b56558 commit 1493304
Show file tree
Hide file tree
Showing 16 changed files with 567 additions and 38 deletions.
8 changes: 3 additions & 5 deletions cmd/cmd_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,9 @@ func imageCreateCommandHandler(cmd *cobra.Command, args []string) {
}

if len(c.CloudConfig.BucketName) == 0 &&
c.CloudConfig.Platform != "onprem" &&
c.CloudConfig.Platform != "hyper-v" &&
c.CloudConfig.Platform != "upcloud" &&
c.CloudConfig.Platform != "openstack" &&
c.CloudConfig.Platform != "oci" {
(c.CloudConfig.Platform == "gcp" ||
c.CloudConfig.Platform == "aws" ||
c.CloudConfig.Platform == "azure") {
exitWithError("Please specify a cloud bucket in config")
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/flags_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func NewProviderCommandFlags(cmdFlags *pflag.FlagSet) (flags *ProviderCommandFla

// PersistProviderCommandFlags append a command the required flags to run an image
func PersistProviderCommandFlags(cmdFlags *pflag.FlagSet) {
cmdFlags.StringP("target-cloud", "t", "onprem", "cloud platform [gcp, aws, onprem, vultr, vsphere, azure, openstack, upcloud, hyper-v, oci]")
cmdFlags.StringP("target-cloud", "t", "onprem", "cloud platform [gcp, aws, onprem, vultr, vsphere, azure, openstack, upcloud, hyper-v, oci, vbox]")
cmdFlags.StringP("projectid", "g", os.Getenv("GOOGLE_CLOUD_PROJECT"), "project-id for GCP or set env GOOGLE_CLOUD_PROJECT")
cmdFlags.StringP("zone", "z", os.Getenv("GOOGLE_CLOUD_ZONE"), "zone name for GCP or set env GOOGLE_CLOUD_ZONE")
}
3 changes: 3 additions & 0 deletions cmd/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/nanovms/ops/openstack"
"github.com/nanovms/ops/types"
"github.com/nanovms/ops/upcloud"
"github.com/nanovms/ops/vbox"
"github.com/nanovms/ops/vsphere"
"github.com/nanovms/ops/vultr"
)
Expand Down Expand Up @@ -45,6 +46,8 @@ func getCloudProvider(providerName string, c *types.ProviderConfig) (api.Provide
provider = upcloud.NewProvider()
case "oci":
provider = oci.NewProvider()
case "vbox":
provider = vbox.NewProvider()
default:
return provider, fmt.Errorf("error:Unknown provider %s", providerName)
}
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ require (
github.com/spf13/cobra v0.0.5
github.com/spf13/pflag v1.0.3
github.com/stretchr/testify v1.7.0
github.com/terra-farm/go-virtualbox v0.0.4
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31
github.com/vmware/govmomi v0.22.2
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
golang.org/x/oauth2 v0.0.0-20210210192628-66670185b0cd
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
google.golang.org/api v0.30.0
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/ini.v1 v1.55.0 // indirect
Expand Down
7 changes: 4 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/oracle/oci-go-sdk v1.8.0 h1:4SO45bKV0I3/Mn1os3ANDZmV0eSE5z5CLdSUIkxtyzs=
github.com/oracle/oci-go-sdk v24.3.0+incompatible h1:x4mcfb4agelf1O4/1/auGlZ1lr97jXRSSN5MxTgG/zU=
github.com/oracle/oci-go-sdk v24.3.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
Expand Down Expand Up @@ -279,6 +278,8 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/terra-farm/go-virtualbox v0.0.4 h1:UAEVNAYLA3g80Z//fMZFVSWHEPqRWkWP2gmFh2p/guQ=
github.com/terra-farm/go-virtualbox v0.0.4/go.mod h1:5n2X+HKR2eAzHfuGFnrZlCrgiYrseNHIcNTSpA/ViyU=
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4=
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
Expand Down Expand Up @@ -428,8 +429,8 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo=
golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
Expand Down
5 changes: 5 additions & 0 deletions hyperv/hyperv.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/nanovms/ops/lepton"
"github.com/nanovms/ops/types"
"github.com/nanovms/ops/wsl"
)

// Provider provides access to the Hyper-V API.
Expand All @@ -29,6 +30,10 @@ func (p *Provider) Initialize(c *types.ProviderConfig) error {
return errors.New("this feature is only supported on terminals with elevated privileges")
}

if !wsl.IsWSL() {
return errors.New("Hyper-v is only supported on WSL")
}

return nil
}

Expand Down
12 changes: 11 additions & 1 deletion hyperv/hyperv_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,17 @@ func (p *Provider) BuildImageWithPackage(ctx *lepton.Context, pkgpath string) (s
return "", err
}

return p.createVhdxImage(c)
imagePath, err := p.createVhdxImage(c)
if err != nil {
return "", err
}

err = os.Remove(c.RunConfig.Imagename)
if err != nil {
return "", err
}

return imagePath, nil
}

func (p *Provider) createVhdxImage(c *types.Config) (imagePath string, err error) {
Expand Down
3 changes: 2 additions & 1 deletion hyperv/hyperv_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/nanovms/ops/lepton"
"github.com/nanovms/ops/wsl"
"github.com/olekukonko/tablewriter"
)

Expand All @@ -38,7 +39,7 @@ func (p *Provider) CreateInstance(ctx *lepton.Context) error {
return fmt.Errorf("invalid instance flavor '%s'; available flavors: 'gen1', 'gen2'", c.CloudConfig.Flavor)
}
}
windowsImagePath, err := convertPathFromWSLtoWindows(imagePath)
windowsImagePath, err := wsl.ConvertPathFromWSLtoWindows(imagePath)
if err != nil {
return err
}
Expand Down
4 changes: 3 additions & 1 deletion hyperv/powershell.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"os/exec"
"strconv"
"strings"

"github.com/nanovms/ops/wsl"
)

const (
Expand Down Expand Up @@ -142,7 +144,7 @@ func saveScript(fileContents string) (string, error) {
return "", err
}

scriptWindowsPath, err := convertPathFromWSLtoWindows(newFilename)
scriptWindowsPath, err := wsl.ConvertPathFromWSLtoWindows(newFilename)
if err != nil {
return "", err
}
Expand Down
24 changes: 0 additions & 24 deletions hyperv/wslpath.go

This file was deleted.

12 changes: 11 additions & 1 deletion oci/oci_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,17 @@ func (p *Provider) BuildImageWithPackage(ctx *lepton.Context, pkgpath string) (s
return "", err
}

return ctx.Config().RunConfig.Imagename, nil
imagePath, err := p.createQcow2Image(c)
if err != nil {
return "", err
}

err = os.Remove(c.RunConfig.Imagename)
if err != nil {
return "", err
}

return imagePath, nil
}

// CreateImage creates a storage object and upload image
Expand Down
16 changes: 16 additions & 0 deletions vbox/vbox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package vbox

import "github.com/nanovms/ops/types"

// Provider provides access to the VirtualBox API.
type Provider struct{}

// NewProvider returns an instance of VirtualBox Provider
func NewProvider() *Provider {
return &Provider{}
}

// Initialize checks conditions to use VirtualBox
func (p *Provider) Initialize(c *types.ProviderConfig) error {
return nil
}
182 changes: 182 additions & 0 deletions vbox/vbox_image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package vbox

import (
"errors"
"os"
"os/exec"
"path"
"path/filepath"
"strings"

"github.com/nanovms/ops/types"

"github.com/nanovms/ops/lepton"
"github.com/olekukonko/tablewriter"
)

var (
vdiImagesDir = path.Join(lepton.GetOpsHome(), "vdi-images")
)

// BuildImage creates local image
func (p *Provider) BuildImage(ctx *lepton.Context) (string, error) {
c := ctx.Config()
err := lepton.BuildImage(*c)
if err != nil {
return "", err
}

imagePath, err := p.createVdiImage(c)
if err != nil {
return "", err
}

err = os.Remove(c.RunConfig.Imagename)
if err != nil {
return "", err
}

return imagePath, nil
}

// BuildImageWithPackage creates local image using package image
func (p *Provider) BuildImageWithPackage(ctx *lepton.Context, pkgpath string) (string, error) {
c := ctx.Config()
err := lepton.BuildImageFromPackage(pkgpath, *c)
if err != nil {
return "", err
}

imagePath, err := p.createVdiImage(c)
if err != nil {
return "", err
}

err = os.Remove(c.RunConfig.Imagename)
if err != nil {
return "", err
}

return imagePath, nil
}

// CreateImage is a stub
func (p *Provider) CreateImage(ctx *lepton.Context, imagePath string) error {
return nil
}

// ListImages prints vcloud images in table format
func (p *Provider) ListImages(ctx *lepton.Context) error {
images, err := p.GetImages(ctx)
if err != nil {
return err
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"UUID", "Name", "Status", "Size", "CreatedAt"})
table.SetHeaderColor(
tablewriter.Colors{tablewriter.Bold, tablewriter.FgCyanColor},
tablewriter.Colors{tablewriter.Bold, tablewriter.FgCyanColor},
tablewriter.Colors{tablewriter.Bold, tablewriter.FgCyanColor},
tablewriter.Colors{tablewriter.Bold, tablewriter.FgCyanColor},
tablewriter.Colors{tablewriter.Bold, tablewriter.FgCyanColor})
table.SetRowLine(true)
for _, i := range images {
var row []string
row = append(row, i.ID)
row = append(row, i.Name)
row = append(row, i.Status)
row = append(row, lepton.Bytes2Human(i.Size))
row = append(row, lepton.Time2Human(i.Created))
table.Append(row)
}
table.Render()
return nil
}

// GetImages returns the list of images available
func (p *Provider) GetImages(ctx *lepton.Context) (images []lepton.CloudImage, err error) {
images = []lepton.CloudImage{}

if _, err = os.Stat(vdiImagesDir); os.IsNotExist(err) {
return
}

err = filepath.Walk(vdiImagesDir, func(hostpath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
name := info.Name()

if len(name) > 4 && strings.Contains(info.Name(), ".vdi") {
images = append(images, lepton.CloudImage{
Name: strings.Replace(info.Name(), ".vdi", "", 1),
Path: hostpath,
Size: info.Size(),
Created: info.ModTime(),
})
}
return nil
})

return
}

// DeleteImage removes VirtualBox image
func (p *Provider) DeleteImage(ctx *lepton.Context, imagename string) (err error) {
imgpath := path.Join(vdiImagesDir, imagename+".vdi")
err = os.Remove(imgpath)

return
}

// ResizeImage is a stub
func (p *Provider) ResizeImage(ctx *lepton.Context, imagename string, hbytes string) error {
return errors.New("Unsupported")
}

// SyncImage is a stub
func (p *Provider) SyncImage(config *types.Config, target lepton.Provider, imagename string) error {
return errors.New("Unsupported")
}

// CustomizeImage is a stub
func (p *Provider) CustomizeImage(ctx *lepton.Context) (string, error) {
return "", errors.New("Unsupported")
}

func (p *Provider) createVdiImage(c *types.Config) (imagePath string, err error) {
vdiImagesDir, err := findOrCreateVdiImagesDir()
if err != nil {
return
}

imagePath = path.Join(vdiImagesDir, c.CloudConfig.ImageName+".vdi")

args := []string{
"convert",
"-O", "vdi",
c.RunConfig.Imagename, imagePath,
}

cmd := exec.Command("qemu-img", args...)
_, err = cmd.CombinedOutput()
if err != nil {
return
}

return
}

func findOrCreateVdiImagesDir() (string, error) {
if _, err := os.Stat(vdiImagesDir); os.IsNotExist(err) {
os.MkdirAll(vdiImagesDir, 0755)
} else if err != nil {
return "", err
}

return vdiImagesDir, nil
}
Loading

0 comments on commit 1493304

Please sign in to comment.