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

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