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

     1  package ukvm
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"os/exec"
     8  	"time"
     9  
    10  	"github.com/sirupsen/logrus"
    11  	"github.com/emc-advanced-dev/pkg/errors"
    12  	"github.com/solo-io/unik/pkg/compilers"
    13  	"github.com/solo-io/unik/pkg/providers/common"
    14  	"github.com/solo-io/unik/pkg/types"
    15  	"github.com/solo-io/unik/pkg/util"
    16  )
    17  
    18  func (p *UkvmProvider) 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. ukvm 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 image.RunSpec.Compiler != compilers.MIRAGE_OCAML_UKVM.String() {
    35  		return nil, errors.New("ukvm only supports mirage / ukvm", nil)
    36  	}
    37  
    38  	if err := common.VerifyMntsInput(p, image, params.MntPointsToVolumeIds); err != nil {
    39  		return nil, errors.New("invalid mapping for volume", err)
    40  	}
    41  
    42  	volumeIdInOrder := make([]string, len(params.MntPointsToVolumeIds))
    43  
    44  	for mntPoint, volumeId := range params.MntPointsToVolumeIds {
    45  
    46  		controllerPort, err := common.GetControllerPortForMnt(image, mntPoint)
    47  		if err != nil {
    48  			return nil, err
    49  		}
    50  		volumeIdInOrder[controllerPort] = volumeId
    51  	}
    52  
    53  	logrus.Debugf("creating ukvm vm")
    54  
    55  	volImagesInOrder, err := p.getVolumeImages(volumeIdInOrder)
    56  	if err != nil {
    57  		return nil, errors.New("can't get volumes", err)
    58  	}
    59  
    60  	volArgs := volPathToUkvmArgs(volImagesInOrder)
    61  
    62  	ukvmArgs := []string{}
    63  
    64  	if p.config.Tap != "" {
    65  		ukvmArgs = append(ukvmArgs, fmt.Sprintf("--net=%s", p.config.Tap))
    66  
    67  	}
    68  
    69  	ukvmArgs = append(ukvmArgs, volArgs...)
    70  	ukvmArgs = append(ukvmArgs, getKernelPath(image.Name))
    71  	cmd := exec.Command(getUkvmPath(image.Name), ukvmArgs...)
    72  
    73  	stdout, err := cmd.StdoutPipe()
    74  	if err != nil {
    75  		logrus.WithError(err).Warning("Can't get stdout for logs")
    76  	}
    77  
    78  	instanceLogName := getInstanceLogName(params.Name)
    79  
    80  	go func() {
    81  		f, err := os.Create(instanceLogName)
    82  		if err != nil {
    83  			logrus.WithError(err).Warning("Failed to create stdout log for instance " + params.Name)
    84  		}
    85  		defer f.Close()
    86  		io.Copy(f, stdout)
    87  
    88  	}()
    89  
    90  	util.LogCommand(cmd, true)
    91  
    92  	if err := cmd.Start(); err != nil {
    93  		return nil, errors.New("can't start ukvm.", nil)
    94  	}
    95  	// close command resources
    96  	go cmd.Wait()
    97  
    98  	var instanceIp string
    99  
   100  	instance := &types.Instance{
   101  		Id:             fmt.Sprintf("%v", cmd.Process.Pid),
   102  		Name:           params.Name,
   103  		State:          types.InstanceState_Running,
   104  		IpAddress:      instanceIp,
   105  		Infrastructure: types.Infrastructure_UKVM,
   106  		ImageId:        image.Id,
   107  		Created:        time.Now(),
   108  	}
   109  
   110  	if err := p.state.ModifyInstances(func(instances map[string]*types.Instance) error {
   111  		instances[instance.Id] = instance
   112  		return nil
   113  	}); err != nil {
   114  		return nil, errors.New("modifying instance map in state", err)
   115  	}
   116  
   117  	logrus.WithField("instance", instance).Infof("instance created successfully")
   118  
   119  	return instance, nil
   120  }
   121  
   122  func (p *UkvmProvider) getVolumeImages(volumeIdInOrder []string) ([]string, error) {
   123  
   124  	var volPath []string
   125  	for _, v := range volumeIdInOrder {
   126  		v, err := p.GetVolume(v)
   127  		if err != nil {
   128  			return nil, err
   129  		}
   130  		volPath = append(volPath, getVolumePath(v.Name))
   131  	}
   132  	return volPath, nil
   133  }
   134  
   135  func volPathToUkvmArgs(volPaths []string) []string {
   136  	var res []string
   137  	for _, v := range volPaths {
   138  		res = append(res, fmt.Sprintf("--disk=%s", v))
   139  	}
   140  	return res
   141  }