github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/providers/virtualbox/run_instance.go (about)

     1  package virtualbox
     2  
     3  import (
     4  	"os"
     5  	"time"
     6  
     7  	"path/filepath"
     8  
     9  	"github.com/sirupsen/logrus"
    10  	"github.com/emc-advanced-dev/pkg/errors"
    11  	unikos "github.com/solo-io/unik/pkg/os"
    12  	"github.com/solo-io/unik/pkg/providers/common"
    13  	"github.com/solo-io/unik/pkg/providers/virtualbox/virtualboxclient"
    14  	"github.com/solo-io/unik/pkg/types"
    15  	"github.com/layer-x/layerx-commons/lxhttpclient"
    16  )
    17  
    18  func (p *VirtualboxProvider) RunInstance(params types.RunInstanceParams) (_ *types.Instance, err error) {
    19  	logrus.WithFields(logrus.Fields{
    20  		"image-id": params.ImageId,
    21  		"mounts":   params.MntPointsToVolumeIds,
    22  		"env":      params.Env,
    23  	}).Infof("running instance %s", params.Name)
    24  
    25  	if _, err := p.GetInstance(params.Name); err == nil {
    26  		return nil, errors.New("instance with name "+params.Name+" already exists. virtualbox provider requires unique names for instances", nil)
    27  	}
    28  
    29  	image, err := p.GetImage(params.ImageId)
    30  	if err != nil {
    31  		return nil, errors.New("getting image", err)
    32  	}
    33  
    34  	if err := common.VerifyMntsInput(p, image, params.MntPointsToVolumeIds); err != nil {
    35  		return nil, errors.New("invalid mapping for volume", err)
    36  	}
    37  
    38  	instanceDir := getInstanceDir(params.Name)
    39  
    40  	portsUsed := []int{}
    41  
    42  	logrus.Debugf("using storage controller %s", image.RunSpec.StorageDriver)
    43  
    44  	defer func() {
    45  		if err != nil {
    46  			if params.NoCleanup {
    47  				logrus.Warnf("because --no-cleanup flag was provided, not cleaning up failed instance %s.2", params.Name)
    48  				return
    49  			}
    50  			logrus.WithError(err).Errorf("error encountered, ensuring vm and disks are destroyed")
    51  			virtualboxclient.PowerOffVm(params.Name)
    52  			for _, portUsed := range portsUsed {
    53  				virtualboxclient.DetachDisk(params.Name, portUsed, image.RunSpec.StorageDriver)
    54  			}
    55  			virtualboxclient.DestroyVm(params.Name)
    56  			os.RemoveAll(instanceDir)
    57  		}
    58  	}()
    59  
    60  	//if not set, use default
    61  	if params.InstanceMemory <= 0 {
    62  		params.InstanceMemory = image.RunSpec.DefaultInstanceMemory
    63  	}
    64  
    65  	logrus.Debugf("creating virtualbox vm")
    66  
    67  	if err := virtualboxclient.CreateVm(params.Name, virtualboxInstancesDirectory(), params.InstanceMemory, p.config.AdapterName, p.config.VirtualboxAdapterType, image.RunSpec.StorageDriver); err != nil {
    68  		return nil, errors.New("creating vm", err)
    69  	}
    70  
    71  	logrus.Debugf("copying source boot vmdk")
    72  	instanceBootImage := filepath.Join(instanceDir, "boot.vmdk")
    73  	if err := unikos.CopyFile(getImagePath(image.Name), instanceBootImage); err != nil {
    74  		return nil, errors.New("copying base boot image", err)
    75  	}
    76  	if err := virtualboxclient.RefreshDiskUUID(instanceBootImage); err != nil {
    77  		return nil, errors.New("refreshing disk uuid", err)
    78  	}
    79  	if err := virtualboxclient.AttachDisk(params.Name, instanceBootImage, 0, image.RunSpec.StorageDriver); err != nil {
    80  		return nil, errors.New("attaching boot vol to instance", err)
    81  	}
    82  
    83  	for mntPoint, volumeId := range params.MntPointsToVolumeIds {
    84  		volume, err := p.GetVolume(volumeId)
    85  		if err != nil {
    86  			return nil, errors.New("getting volume", err)
    87  		}
    88  		controllerPort, err := common.GetControllerPortForMnt(image, mntPoint)
    89  		if err != nil {
    90  			return nil, errors.New("getting controller port for mnt point", err)
    91  		}
    92  		if err := virtualboxclient.RefreshDiskUUID(getVolumePath(volume.Name)); err != nil {
    93  			return nil, errors.New("refreshing disk uuid", err)
    94  		}
    95  		if err := virtualboxclient.AttachDisk(params.Name, getVolumePath(volume.Name), controllerPort, image.RunSpec.StorageDriver); err != nil {
    96  			return nil, errors.New("attaching to vm", err)
    97  		}
    98  		portsUsed = append(portsUsed, controllerPort)
    99  	}
   100  
   101  	logrus.Debugf("setting instance id from mac address")
   102  	vm, err := virtualboxclient.GetVm(params.Name)
   103  	if err != nil {
   104  		return nil, errors.New("retrieving created vm from vbox", err)
   105  	}
   106  	macAddr := vm.MACAddr
   107  	instanceId := vm.UUID
   108  
   109  	instanceListenerIp, err := common.GetInstanceListenerIp(instanceListenerPrefix, timeout)
   110  	if err != nil {
   111  		return nil, errors.New("failed to retrieve instance listener ip. is unik instance listener running?", err)
   112  	}
   113  
   114  	logrus.Debugf("sending env to listener")
   115  	if _, _, err := lxhttpclient.Post(instanceListenerIp+":3000", "/set_instance_env?mac_address="+macAddr, nil, params.Env); err != nil {
   116  		return nil, errors.New("sending instance env to listener", err)
   117  	}
   118  
   119  	logrus.Debugf("powering on vm")
   120  	if err := virtualboxclient.PowerOnVm(params.Name); err != nil {
   121  		return nil, errors.New("powering on vm", err)
   122  	}
   123  
   124  	instance := &types.Instance{
   125  		Id:             instanceId,
   126  		Name:           params.Name,
   127  		State:          types.InstanceState_Pending,
   128  		IpAddress:      "",
   129  		Infrastructure: types.Infrastructure_VIRTUALBOX,
   130  		ImageId:        image.Id,
   131  		Created:        time.Now(),
   132  	}
   133  
   134  	if err := p.state.ModifyInstances(func(instances map[string]*types.Instance) error {
   135  		instances[instance.Id] = instance
   136  		return nil
   137  	}); err != nil {
   138  		return nil, errors.New("modifying instance map in state", err)
   139  	}
   140  
   141  	logrus.WithField("instance", instance).Infof("instance created successfully")
   142  
   143  	return instance, nil
   144  }