github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/providers/qemu/run_instance.go (about) 1 package qemu 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "strings" 8 "time" 9 10 "io/ioutil" 11 12 "github.com/sirupsen/logrus" 13 "github.com/emc-advanced-dev/pkg/errors" 14 "github.com/solo-io/unik/pkg/compilers" 15 "github.com/solo-io/unik/pkg/providers/common" 16 "github.com/solo-io/unik/pkg/types" 17 "github.com/solo-io/unik/pkg/util" 18 ) 19 20 func (p *QemuProvider) RunInstance(params types.RunInstanceParams) (_ *types.Instance, err error) { 21 logrus.WithFields(logrus.Fields{ 22 "image-id": params.ImageId, 23 "mounts": params.MntPointsToVolumeIds, 24 "env": params.Env, 25 }).Infof("running instance %s", params.Name) 26 27 if _, err := p.GetInstance(params.Name); err == nil { 28 return nil, errors.New("instance with name "+params.Name+" already exists. qemu provider requires unique names for instances", nil) 29 } 30 31 image, err := p.GetImage(params.ImageId) 32 if err != nil { 33 return nil, errors.New("getting image", err) 34 } 35 36 if err := common.VerifyMntsInput(p, image, params.MntPointsToVolumeIds); err != nil { 37 return nil, errors.New("invalid mapping for volume", err) 38 } 39 40 volumeIdInOrder := make([]string, len(params.MntPointsToVolumeIds)) 41 42 for mntPoint, volumeId := range params.MntPointsToVolumeIds { 43 44 controllerPort, err := common.GetControllerPortForMnt(image, mntPoint) 45 if err != nil { 46 return nil, err 47 } 48 volumeIdInOrder[controllerPort] = volumeId 49 } 50 51 logrus.Debugf("creating qemu vm") 52 53 volImagesInOrder, err := p.getVolumeImages(volumeIdInOrder) 54 if err != nil { 55 return nil, errors.New("can't get volumes", err) 56 } 57 58 volArgs := volPathToQemuArgs(volImagesInOrder) 59 60 if params.InstanceMemory == 0 { 61 params.InstanceMemory = image.RunSpec.DefaultInstanceMemory 62 } 63 64 qemuArgs := []string{"-m", fmt.Sprintf("%v", params.InstanceMemory), "-net", 65 "nic,model=virtio,netdev=mynet0", "-netdev", "user,id=mynet0,net=192.168.76.0/24,dhcpstart=192.168.76.9", 66 } 67 68 cmdlinedata, err := ioutil.ReadFile(getCmdlinePath(image.Name)) 69 if err != nil { 70 logrus.Debugf("cmdLine not found, assuming classic bootloader") 71 qemuArgs = append(qemuArgs, "-drive", fmt.Sprintf("file=%s,format=raw,if=ide", getImagePath(image.Name))) 72 } else { 73 // inject env for rump: 74 cmdline := string(cmdlinedata) 75 if compilers.CompilerType(image.RunSpec.Compiler).Base() == compilers.Rump { 76 cmdline = injectEnv(cmdline, params.Env) 77 } 78 79 // qemu escape 80 cmdline = strings.Replace(cmdline, ",", ",,", -1) 81 82 if _, err := os.Stat(getImagePath(image.Name)); err == nil { 83 qemuArgs = append(qemuArgs, "-device", "virtio-blk-pci,id=blk0,drive=hd0") 84 qemuArgs = append(qemuArgs, "-drive", fmt.Sprintf("file=%s,format=qcow2,if=none,id=hd0", getImagePath(image.Name))) 85 } 86 87 qemuArgs = append(qemuArgs, "-kernel", getKernelPath(image.Name)) 88 qemuArgs = append(qemuArgs, "-append", cmdline) 89 } 90 91 if params.DebugMode { 92 logrus.Debugf("running instance in debug mode.\nattach unik debugger to port :%v", p.config.DebuggerPort) 93 qemuArgs = append(qemuArgs, "-s", "-S") 94 debuggerTargetImageName = image.Name 95 } 96 97 if p.config.NoGraphic { 98 qemuArgs = append(qemuArgs, "-nographic", "-vga", "none") 99 } 100 101 qemuArgs = append(qemuArgs, volArgs...) 102 cmd := exec.Command("qemu-system-x86_64", qemuArgs...) 103 104 util.LogCommand(cmd, true) 105 106 if err := cmd.Start(); err != nil { 107 return nil, errors.New("can't start qemu - make sure it's in your path.", nil) 108 } 109 110 var instanceIp string 111 112 instance := &types.Instance{ 113 Id: fmt.Sprintf("%d", cmd.Process.Pid), 114 Name: params.Name, 115 State: types.InstanceState_Running, 116 IpAddress: instanceIp, 117 Infrastructure: types.Infrastructure_QEMU, 118 ImageId: image.Id, 119 Created: time.Now(), 120 } 121 122 if err := p.state.ModifyInstances(func(instances map[string]*types.Instance) error { 123 instances[instance.Id] = instance 124 return nil 125 }); err != nil { 126 return nil, errors.New("modifying instance map in state", err) 127 } 128 129 logrus.WithField("instance", instance).Infof("instance created successfully") 130 131 return instance, nil 132 } 133 134 func (p *QemuProvider) getVolumeImages(volumeIdInOrder []string) ([]string, error) { 135 136 var volPath []string 137 for _, v := range volumeIdInOrder { 138 v, err := p.GetVolume(v) 139 if err != nil { 140 return nil, err 141 } 142 volPath = append(volPath, getVolumePath(v.Name)) 143 } 144 return volPath, nil 145 } 146 147 func volPathToQemuArgs(volPaths []string) []string { 148 var res []string 149 for _, v := range volPaths { 150 res = append(res, "-drive", fmt.Sprintf("if=virtio,file=%s,format=qcow2", v)) 151 } 152 return res 153 } 154 155 func injectEnv(cmdline string, env map[string]string) string { 156 // rump json is not really json so we can't parse it 157 var envRumpJson []string 158 for key, value := range env { 159 envRumpJson = append(envRumpJson, fmt.Sprintf("\"env\": \"%s=%s\"", key, value)) 160 } 161 162 cmdline = cmdline[:len(cmdline)-2] + "," + strings.Join(envRumpJson, ",") + "}}" 163 return cmdline 164 }