Merge pull request #105 from bergwolf/interaction

improve qemu interaction
This commit is contained in:
Julio Montes 2019-08-14 08:01:15 -05:00 committed by GitHub
commit e6644f4a25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 169 additions and 104 deletions

View File

@ -1456,8 +1456,8 @@ type Knobs struct {
// be set.
FileBackedMem bool
// FileBackedMemShared will set the FileBackedMem device as shared.
FileBackedMemShared bool
// MemShared will set the memory device as shared.
MemShared bool
// Mlock will control locking of memory
// Only active when Realtime is set to true
@ -1557,6 +1557,9 @@ type Config struct {
// PidFile is the -pidfile parameter
PidFile string
// LogFile is the -D parameter
LogFile string
qemuParams []string
}
@ -1755,46 +1758,34 @@ func (config *Config) appendKernel() {
}
func (config *Config) appendMemoryKnobs() {
if config.Knobs.HugePages {
if config.Memory.Size != "" {
dimmName := "dimm1"
objMemParam := "memory-backend-file,id=" + dimmName + ",size=" + config.Memory.Size + ",mem-path=/dev/hugepages,share=on,prealloc=on"
numaMemParam := "node,memdev=" + dimmName
config.qemuParams = append(config.qemuParams, "-object")
config.qemuParams = append(config.qemuParams, objMemParam)
config.qemuParams = append(config.qemuParams, "-numa")
config.qemuParams = append(config.qemuParams, numaMemParam)
}
} else if config.Knobs.MemPrealloc {
if config.Memory.Size != "" {
dimmName := "dimm1"
objMemParam := "memory-backend-ram,id=" + dimmName + ",size=" + config.Memory.Size + ",prealloc=on"
numaMemParam := "node,memdev=" + dimmName
config.qemuParams = append(config.qemuParams, "-object")
config.qemuParams = append(config.qemuParams, objMemParam)
config.qemuParams = append(config.qemuParams, "-numa")
config.qemuParams = append(config.qemuParams, numaMemParam)
}
} else if config.Knobs.FileBackedMem {
if config.Memory.Size != "" && config.Memory.Path != "" {
dimmName := "dimm1"
objMemParam := "memory-backend-file,id=" + dimmName + ",size=" + config.Memory.Size + ",mem-path=" + config.Memory.Path
if config.Knobs.FileBackedMemShared {
objMemParam += ",share=on"
}
numaMemParam := "node,memdev=" + dimmName
config.qemuParams = append(config.qemuParams, "-object")
config.qemuParams = append(config.qemuParams, objMemParam)
config.qemuParams = append(config.qemuParams, "-numa")
config.qemuParams = append(config.qemuParams, numaMemParam)
}
if config.Memory.Size == "" {
return
}
var objMemParam, numaMemParam string
dimmName := "dimm1"
if config.Knobs.HugePages {
objMemParam = "memory-backend-file,id=" + dimmName + ",size=" + config.Memory.Size + ",mem-path=/dev/hugepages"
numaMemParam = "node,memdev=" + dimmName
} else if config.Knobs.FileBackedMem && config.Memory.Path != "" {
objMemParam = "memory-backend-file,id=" + dimmName + ",size=" + config.Memory.Size + ",mem-path=" + config.Memory.Path
numaMemParam = "node,memdev=" + dimmName
} else {
objMemParam = "memory-backend-ram,id=" + dimmName + ",size=" + config.Memory.Size
numaMemParam = "node,memdev=" + dimmName
}
if config.Knobs.MemShared {
objMemParam += ",share=on"
}
if config.Knobs.MemPrealloc {
objMemParam += ",prealloc=on"
}
config.qemuParams = append(config.qemuParams, "-object")
config.qemuParams = append(config.qemuParams, objMemParam)
config.qemuParams = append(config.qemuParams, "-numa")
config.qemuParams = append(config.qemuParams, numaMemParam)
}
func (config *Config) appendKnobs() {
@ -1880,6 +1871,13 @@ func (config *Config) appendPidFile() {
}
}
func (config *Config) appendLogFile() {
if config.LogFile != "" {
config.qemuParams = append(config.qemuParams, "-D")
config.qemuParams = append(config.qemuParams, config.LogFile)
}
}
// LaunchQemu can be used to launch a new qemu instance.
//
// The Config parameter contains a set of qemu parameters and settings.
@ -1906,6 +1904,7 @@ func LaunchQemu(config Config, logger QMPLog) (string, error) {
config.appendIOThreads()
config.appendIncoming()
config.appendPidFile()
config.appendLogFile()
if err := config.appendCPUs(); err != nil {
return "", err

View File

@ -64,7 +64,7 @@ func testConfigAppend(config *Config, structure interface{}, expected string, t
case SMP:
config.SMP = s
if err := config.appendCPUs(); err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
case QMPSocket:
@ -488,16 +488,16 @@ func TestAppendEmptyDevice(t *testing.T) {
func TestAppendKnobsAllTrue(t *testing.T) {
var knobsString = "-no-user-config -nodefaults -nographic -daemonize -realtime mlock=on -S"
knobs := Knobs{
NoUserConfig: true,
NoDefaults: true,
NoGraphic: true,
Daemonize: true,
MemPrealloc: true,
FileBackedMem: true,
FileBackedMemShared: true,
Realtime: true,
Mlock: true,
Stopped: true,
NoUserConfig: true,
NoDefaults: true,
NoGraphic: true,
Daemonize: true,
MemPrealloc: true,
FileBackedMem: true,
MemShared: true,
Realtime: true,
Mlock: true,
Stopped: true,
}
testAppend(knobs, knobsString, t)
@ -506,15 +506,15 @@ func TestAppendKnobsAllTrue(t *testing.T) {
func TestAppendKnobsAllFalse(t *testing.T) {
var knobsString = "-realtime mlock=off"
knobs := Knobs{
NoUserConfig: false,
NoDefaults: false,
NoGraphic: false,
MemPrealloc: false,
FileBackedMem: false,
FileBackedMemShared: false,
Realtime: false,
Mlock: false,
Stopped: false,
NoUserConfig: false,
NoDefaults: false,
NoGraphic: false,
MemPrealloc: false,
FileBackedMem: false,
MemShared: false,
Realtime: false,
Mlock: false,
Stopped: false,
}
testAppend(knobs, knobsString, t)
@ -533,10 +533,10 @@ func TestAppendMemoryHugePages(t *testing.T) {
testConfigAppend(conf, conf.Memory, memString, t)
knobs := Knobs{
HugePages: true,
MemPrealloc: true,
FileBackedMem: true,
FileBackedMemShared: true,
HugePages: true,
MemPrealloc: true,
FileBackedMem: true,
MemShared: true,
}
knobsString := "-object memory-backend-file,id=dimm1,size=1G,mem-path=/dev/hugepages,share=on,prealloc=on -numa node,memdev=dimm1"
mlockFalseString := "-realtime mlock=off"
@ -557,17 +557,16 @@ func TestAppendMemoryMemPrealloc(t *testing.T) {
testConfigAppend(conf, conf.Memory, memString, t)
knobs := Knobs{
MemPrealloc: true,
FileBackedMem: true,
FileBackedMemShared: true,
MemPrealloc: true,
MemShared: true,
}
knobsString := "-object memory-backend-ram,id=dimm1,size=1G,prealloc=on -numa node,memdev=dimm1"
knobsString := "-object memory-backend-ram,id=dimm1,size=1G,share=on,prealloc=on -numa node,memdev=dimm1"
mlockFalseString := "-realtime mlock=off"
testConfigAppend(conf, knobs, memString+" "+knobsString+" "+mlockFalseString, t)
}
func TestAppendMemoryFileBackedMemShared(t *testing.T) {
func TestAppendMemoryMemShared(t *testing.T) {
conf := &Config{
Memory: Memory{
Size: "1G",
@ -580,8 +579,8 @@ func TestAppendMemoryFileBackedMemShared(t *testing.T) {
testConfigAppend(conf, conf.Memory, memString, t)
knobs := Knobs{
FileBackedMem: true,
FileBackedMemShared: true,
FileBackedMem: true,
MemShared: true,
}
knobsString := "-object memory-backend-file,id=dimm1,size=1G,mem-path=foobar,share=on -numa node,memdev=dimm1"
mlockFalseString := "-realtime mlock=off"
@ -602,8 +601,8 @@ func TestAppendMemoryFileBackedMem(t *testing.T) {
testConfigAppend(conf, conf.Memory, memString, t)
knobs := Knobs{
FileBackedMem: true,
FileBackedMemShared: false,
FileBackedMem: true,
MemShared: false,
}
knobsString := "-object memory-backend-file,id=dimm1,size=1G,mem-path=foobar -numa node,memdev=dimm1"
mlockFalseString := "-realtime mlock=off"
@ -611,6 +610,29 @@ func TestAppendMemoryFileBackedMem(t *testing.T) {
testConfigAppend(conf, knobs, memString+" "+knobsString+" "+mlockFalseString, t)
}
func TestAppendMemoryFileBackedMemPrealloc(t *testing.T) {
conf := &Config{
Memory: Memory{
Size: "1G",
Slots: 8,
MaxMem: "3G",
Path: "foobar",
},
}
memString := "-m 1G,slots=8,maxmem=3G"
testConfigAppend(conf, conf.Memory, memString, t)
knobs := Knobs{
FileBackedMem: true,
MemShared: true,
MemPrealloc: true,
}
knobsString := "-object memory-backend-file,id=dimm1,size=1G,mem-path=foobar,share=on,prealloc=on -numa node,memdev=dimm1"
mlockFalseString := "-realtime mlock=off"
testConfigAppend(conf, knobs, memString+" "+knobsString+" "+mlockFalseString, t)
}
var kernelString = "-kernel /opt/vmlinux.container -initrd /opt/initrd.container -append root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro rw rootfstype=ext4 tsc=reliable"
func TestAppendKernel(t *testing.T) {
@ -712,7 +734,8 @@ func TestAppendQMPSocketServer(t *testing.T) {
}
var pidfile = "/run/vc/vm/iamsandboxid/pidfile"
var qemuString = "-name cc-qemu -cpu host -uuid " + agentUUID + " -pidfile " + pidfile
var logfile = "/run/vc/vm/iamsandboxid/logfile"
var qemuString = "-name cc-qemu -cpu host -uuid " + agentUUID + " -pidfile " + pidfile + " -D " + logfile
func TestAppendStrings(t *testing.T) {
config := Config{
@ -721,12 +744,14 @@ func TestAppendStrings(t *testing.T) {
UUID: agentUUID,
CPUModel: "host",
PidFile: pidfile,
LogFile: logfile,
}
config.appendName()
config.appendCPUModel()
config.appendUUID()
config.appendPidFile()
config.appendLogFile()
result := strings.Join(config.qemuParams, " ")
if result != qemuString {
@ -984,7 +1009,7 @@ func TestBadMemoryKnobs(t *testing.T) {
c = &Config{
Knobs: Knobs{
HugePages: true,
MemShared: true,
},
}
c.appendMemoryKnobs()
@ -1001,19 +1026,6 @@ func TestBadMemoryKnobs(t *testing.T) {
if len(c.qemuParams) != 0 {
t.Errorf("Expected empty qemuParams, found %s", c.qemuParams)
}
c = &Config{
Knobs: Knobs{
FileBackedMem: true,
},
Memory: Memory{
Size: "1024",
},
}
c.appendMemoryKnobs()
if len(c.qemuParams) != 0 {
t.Errorf("Expected empty qemuParams, found %s", c.qemuParams)
}
}
func TestBadKnobs(t *testing.T) {

View File

@ -251,6 +251,13 @@ type SchemaInfo struct {
Name string `json:"name"`
}
// StatusInfo represents guest running status
type StatusInfo struct {
Running bool `json:"running"`
SingleStep bool `json:"singlestep"`
Status string `json:"status"`
}
func (q *QMP) readLoop(fromVMCh chan<- []byte) {
scanner := bufio.NewScanner(q.conn)
if q.cfg.MaxCapacity > 0 {
@ -1545,3 +1552,23 @@ func (q *QMP) ExecQueryQmpSchema(ctx context.Context) ([]SchemaInfo, error) {
return schemaInfo, nil
}
// ExecuteQueryStatus queries guest status
func (q *QMP) ExecuteQueryStatus(ctx context.Context) (StatusInfo, error) {
response, err := q.executeCommandWithResponse(ctx, "query-status", nil, nil, nil)
if err != nil {
return StatusInfo{}, err
}
data, err := json.Marshal(response)
if err != nil {
return StatusInfo{}, fmt.Errorf("unable to extract migrate status information: %v", err)
}
var status StatusInfo
if err = json.Unmarshal(data, &status); err != nil {
return StatusInfo{}, fmt.Errorf("unable to convert migrate status information: %v", err)
}
return status, nil
}

View File

@ -1110,13 +1110,13 @@ func TestQMPExecuteQueryHotpluggableCPUs(t *testing.T) {
checkVersion(t, connectedCh)
hotCPUs, err := q.ExecuteQueryHotpluggableCPUs(context.Background())
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
if len(hotCPUs) != 1 {
t.Fatalf("Expected hot CPUs length equals to 1\n")
}
if reflect.DeepEqual(hotCPUs[0], hotCPU) == false {
t.Fatalf("Expected %v equals to %v\n", hotCPUs[0], hotCPU)
t.Fatalf("Expected %v equals to %v", hotCPUs[0], hotCPU)
}
q.Shutdown()
<-disconnectedCh
@ -1146,13 +1146,13 @@ func TestQMPExecuteQueryMemoryDevices(t *testing.T) {
checkVersion(t, connectedCh)
memDevices, err := q.ExecQueryMemoryDevices(context.Background())
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
if len(memDevices) != 1 {
t.Fatalf("Expected memory devices length equals to 1\n")
}
if reflect.DeepEqual(memDevices[0], memoryDevices) == false {
t.Fatalf("Expected %v equals to %v\n", memDevices[0], memoryDevices)
t.Fatalf("Expected %v equals to %v", memDevices[0], memoryDevices)
}
q.Shutdown()
<-disconnectedCh
@ -1184,13 +1184,13 @@ func TestQMPExecuteQueryCpus(t *testing.T) {
checkVersion(t, connectedCh)
cpus, err := q.ExecQueryCpus(context.Background())
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
if len(cpus) != 1 {
t.Fatalf("Expected memory devices length equals to 1\n")
}
if reflect.DeepEqual(cpus[0], cpuInfo) == false {
t.Fatalf("Expected %v equals to %v\n", cpus[0], cpuInfo)
t.Fatalf("Expected %v equals to %v", cpus[0], cpuInfo)
}
q.Shutdown()
<-disconnectedCh
@ -1220,13 +1220,13 @@ func TestQMPExecuteQueryCpusFast(t *testing.T) {
checkVersion(t, connectedCh)
cpus, err := q.ExecQueryCpusFast(context.Background())
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
if len(cpus) != 1 {
t.Fatalf("Expected memory devices length equals to 1\n")
}
if reflect.DeepEqual(cpus[0], cpuInfoFast) == false {
t.Fatalf("Expected %v equals to %v\n", cpus[0], cpuInfoFast)
t.Fatalf("Expected %v equals to %v", cpus[0], cpuInfoFast)
}
q.Shutdown()
<-disconnectedCh
@ -1249,7 +1249,7 @@ func TestExecSetMigrationCaps(t *testing.T) {
}
err := q.ExecSetMigrationCaps(context.Background(), caps)
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
q.Shutdown()
<-disconnectedCh
@ -1266,7 +1266,7 @@ func TestExecSetMigrateArguments(t *testing.T) {
checkVersion(t, connectedCh)
err := q.ExecSetMigrateArguments(context.Background(), "exec:foobar")
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
q.Shutdown()
<-disconnectedCh
@ -1284,7 +1284,7 @@ func TestExecHotplugMemory(t *testing.T) {
checkVersion(t, connectedCh)
err := q.ExecHotplugMemory(context.Background(), "memory-backend-ram", "mem0", "", 128, true)
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
q.Shutdown()
<-disconnectedCh
@ -1419,7 +1419,7 @@ func TestExecuteQueryMigration(t *testing.T) {
t.Fatalf("Unexpected error %v", err)
}
if !reflect.DeepEqual(s, status) {
t.Fatalf("expected %v\n got %v", status, s)
t.Fatalf("expected %v got %v", status, s)
}
q.Shutdown()
<-disconnectedCh
@ -1538,7 +1538,7 @@ func TestExecuteNVDIMMDeviceAdd(t *testing.T) {
checkVersion(t, connectedCh)
err := q.ExecuteNVDIMMDeviceAdd(context.Background(), "nvdimm0", "/dev/rbd0", 1024)
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
q.Shutdown()
<-disconnectedCh
@ -1612,13 +1612,40 @@ func TestQMPExecQueryQmpSchema(t *testing.T) {
checkVersion(t, connectedCh)
info, err := q.ExecQueryQmpSchema(context.Background())
if err != nil {
t.Fatalf("Unexpected error: %v\n", err)
t.Fatalf("Unexpected error: %v", err)
}
if len(schemaInfo) != 2 {
t.Fatalf("Expected schema infos length equals to 2\n")
}
if reflect.DeepEqual(info, schemaInfo) == false {
t.Fatalf("Expected %v equals to %v\n", info, schemaInfo)
t.Fatalf("Expected %v equals to %v", info, schemaInfo)
}
q.Shutdown()
<-disconnectedCh
}
func TestQMPExecQueryQmpStatus(t *testing.T) {
connectedCh := make(chan *QMPVersion)
disconnectedCh := make(chan struct{})
buf := newQMPTestCommandBuffer(t)
statusInfo := StatusInfo{
Running: true,
SingleStep: false,
Status: "running",
}
buf.AddCommand("query-status", nil, "return", statusInfo)
cfg := QMPConfig{
Logger: qmpTestLogger{},
MaxCapacity: 1024,
}
q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh)
checkVersion(t, connectedCh)
info, err := q.ExecuteQueryStatus(context.Background())
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if reflect.DeepEqual(info, statusInfo) == false {
t.Fatalf("Expected %v equals to %v", info, statusInfo)
}
q.Shutdown()
<-disconnectedCh