func uiNUMATopologyHeader(ui *gui.DialogUi, c *guest.Config) string { ui.HelpButton(true) ui.SetHelpLabel("Back") ui.SetTitle("VA NUMA Configuration") ui.SetExtraLabel("Edit") var hdr string for _, n := range c.NUMAs { for _, nic := range n.NICs { if nic.HostNIC.Type == host.NicTypePhys || nic.HostNIC.Type == host.NicTypePhysVF { hdr += fmt.Sprintf("\nNUMA %d: %s", nic.HostNIC.NUMANode, nic.HostNIC.PCIAddr) } } } hdr += "\n" if hdr != "\n" { hdr = " \n---------------- PCI Devices Topology ---------------" + hdr hdr += "-----------------------------------------------------\n\n" } hdr += " __________________ CPU/NUMA Topology ________________\n" hdr += "|____________ VA ___________|_________ Host __________|\n" hdr += "|____ vCPU ___|___ vNUMA ___|_________CPU(s) _________|" return hdr }
// UiEulaMsg prints out appropriate EULA message func UiEulaMsg(ui *gui.DialogUi, pathToEula string) { ui.SetOkLabel("Agree") ui.SetExtraLabel("Disagree") ui.SetTitle("End User License Agreement") ui.SetSize(30, 80) if err := ui.Textbox(pathToEula); err != nil { os.Exit(1) } }
func uiHeaderSelectNics(ui *gui.DialogUi) int { str := " ___________________________________________________________________________________________________________________________" width := len(str) str += "\n|____________________________________________________HOST__________________________________________________________|___VM___|" str += fmt.Sprintf("\n|________%s________|__%s__|_______________ %s _________________|__%s__|__%s__|", "Port Name", "PCI Address", "Network Interface Description", "NUMA", "Port") ui.SetLabel(str) ui.SetExtraLabel("Next") ui.SetOkLabel("Select") ui.HelpButton(true) ui.SetHelpLabel("Back") return width }
func uiNetworkPolicySelector(ui *gui.DialogUi, net *xmlinput.Network) ([]xmlinput.ConnectionMode, error) { matrix := make(map[string][]xmlinput.ConnectionMode) for _, mode := range net.UiModeBinding { if _, ok := matrix[mode.Appear]; !ok { matrix[mode.Appear] = make([]xmlinput.ConnectionMode, 0) } matrix[mode.Appear] = append(matrix[mode.Appear], mode.Type) } var temp []string index := 1 for appear, _ := range matrix { temp = append(temp, strconv.Itoa(index), appear) index++ } length := len(matrix) ui.SetSize(length+8, 50) ui.SetTitle(fmt.Sprintf("Network interface type for network \"%s\"", net.Name)) ui.HelpButton(true) ui.SetHelpLabel("Back") if net.Optional { ui.SetExtraLabel("Skip") } val, err := ui.Menu(length, temp[0:]...) if err != nil { return nil, err } resultInt, err := strconv.Atoi(val) if err != nil { return nil, utils.FormatError(err) } if resultInt != 1 { resultInt++ } return matrix[temp[resultInt]], nil }
func UiNUMATopology(ui *gui.DialogUi, c *guest.Config, d deployer.EnvDriver, totalCpusOnHost int) (bool, error) { var list []string // file, err := os.Create("/tmp/UiNUMATopology.txt") // if err != nil { // return false, nil // } // defer file.Close() isChanged := false hCPUnotOnce := "" CheckIfCPUdoubleUsed := true MainLoop: for { // file.WriteString("[UiNUMATopology] MainLoop: \n") list = make([]string, 0) tempData := make(map[int]map[int]string) // file.WriteString("[UiNUMATopology] totalCpusOnHost: " + strconv.Itoa(totalCpusOnHost) + " \n") for _, n := range c.NUMAs { // file.WriteString("[UiNUMATopology] c.NUMAs\n") // file.WriteString("[UiNUMATopology] len(n.CPUPin): " + strconv.Itoa(len(n.CPUPin)) + "\n") keys := make([]int, 0) for vcpu, _ := range n.CPUPin { keys = append(keys, vcpu) // file.WriteString("[UiNUMATopology] vcpu: " + strconv.Itoa(vcpu) + "\n") } sort.Ints(keys) var hostCpu string for _, k := range keys { if len(n.CPUPin[k]) > 1 { if len(n.CPUPin[k]) == totalCpusOnHost { CheckIfCPUdoubleUsed = false hostCpu = "0-" + strconv.Itoa(totalCpusOnHost-1) } else { var tmpStrSlice []string for _, c := range n.CPUPin[k] { tmpStrSlice = append(tmpStrSlice, strconv.Itoa(c)) } hostCpu = strings.Join(tmpStrSlice, ",") } } else { hostCpu = strconv.Itoa(n.CPUPin[k][0]) } // file.WriteString("[UiNUMATopology] hostCpu: " + hostCpu + "\n") tempData[k] = make(map[int]string) tempData[k][n.CellID] = hostCpu // file.WriteString("tempData[" + strconv.Itoa(k) + "][" + strconv.Itoa(n.CellID) + "] = " + hostCpu + " \n") } } // we need to represent sorted vCPU IDs and not vNUMA IDs keys := make([]int, 0) for k, _ := range tempData { keys = append(keys, k) } duplicate_frequency := make(map[string]int) sort.Ints(keys) for _, key := range keys { for k, v := range tempData[key] { list = append(list, strconv.Itoa(key), fmt.Sprintf("%-10s%-18d%-7s", " ", k, v)) temphCPU := v _, exist := duplicate_frequency[temphCPU] if exist { duplicate_frequency[temphCPU] += 1 // increase counter by 1 if already in the map } else { duplicate_frequency[temphCPU] = 1 // else start counting from 1 } // file.WriteString("k: " + strconv.Itoa(k) + " v: " + v + " \n") } } hCPUnotOnce = "" for k_dup, v_dup := range duplicate_frequency { if v_dup > 1 { hCPUnotOnce = k_dup break } } ui.SetLabel(uiNUMATopologyHeader(ui, c)) result, err := ui.Menu(len(list), list[0:]...) // file.WriteString("[UiNUMATopology] result: " + result + " err: " + err.Error() + " len(list): " + strconv.Itoa(len(list)) + " \n") if err == nil { if hCPUnotOnce != "" && isChanged && CheckIfCPUdoubleUsed { ui.Output(gui.Warning, "CPU "+hCPUnotOnce+" is assigned to more than one vCPU") continue } break } if err.Error() != gui.DialogNext { // file.WriteString("[UiNUMATopology] err.Error() != gui.DialogNext " + err.Error() + " \n") return isChanged, err } InternalLoop: for { // file.WriteString("[UiNUMATopology] InternalLoop: \n") ui.SetTitle("VA vCPU Configuration") ui.SetExtraLabel("Help") // file.WriteString("result: (" + result + ") \n") resultInt, err := strconv.Atoi(result) if err != nil { // file.WriteString("[UiNUMATopology] strconv.Atoi(result) " + err.Error() + "\n") return isChanged, err } var vnumaStr string var cpusStr string tempDataLen := len(tempData) for k, v := range tempData[resultInt] { vnumaStr = strconv.Itoa(k) cpusStr = v // tempDataLen++ } // file.WriteString("resultInt: (" + result + ") \n") // DE11527 index := resultInt resultInt-- // var vnumaPredecStr string // for k, _ := range tempData[resultInt] { // vnumaPredecStr = strconv.Itoa(k) // // file.WriteString("vnumaPredecStr: (" + vnumaPredecStr + ") ") // } var lst []string label := "Set affinity for vCPU " + result var vnumaMinus1 string var vnumaPlus1 string var vnumaIndex string var vnumaTemp string if tempDataLen > 3 { if index > (tempDataLen - 1) { index = index - tempDataLen } indexMinus1 := index - 1 if indexMinus1 < 0 { indexMinus1 = tempDataLen + indexMinus1 } indexPlus1 := index + 1 if indexPlus1 > tempDataLen { indexPlus1 = indexPlus1 - tempDataLen } for k, _ := range tempData[indexMinus1] { vnumaMinus1 = strconv.Itoa(k) } for k, _ := range tempData[indexPlus1] { vnumaPlus1 = strconv.Itoa(k) } for k, _ := range tempData[index] { vnumaIndex = strconv.Itoa(k) } if index == (tempDataLen - 1) { // vnumaPlus1 = vnumaIndex for k, _ := range tempData[0] { vnumaTemp = strconv.Itoa(k) } if vnumaTemp != vnumaIndex { vnumaPlus1 = vnumaIndex } else { vnumaPlus1 = "vnumaPlus1" } } if index == 0 { // vnumaMinus1 = vnumaIndex for k, _ := range tempData[tempDataLen-1] { vnumaTemp = strconv.Itoa(k) } if vnumaTemp != vnumaIndex { vnumaMinus1 = vnumaIndex } else { vnumaMinus1 = "vnumaIndex" } } } else { vnumaMinus1 = "-1" vnumaPlus1 = "+1" } // xxxxxx := d.Id() // file.WriteString("d.Id(): (" + xxxxxx + ") ") // file.WriteString("vnumaStr: (" + vnumaStr + ") vnumaPredecStr: (" + vnumaPredecStr + ") \n") // file.WriteString("indexMinus1: (" + strconv.Itoa(indexMinus1) + ") index: (" + strconv.Itoa(index) + ") indexPlus1: (" + strconv.Itoa(indexPlus1) + ")\n") // file.WriteString("vnumaMinus1: (" + vnumaMinus1 + ") vnumaPlus1: (" + vnumaPlus1 + ") \n") // file.WriteString("tempDataLen: (" + strconv.Itoa(tempDataLen) + ") \n") // if vnumaStr == vnumaPredecStr && d.Id() == "QEMU-Libvirt" { if vnumaMinus1 == vnumaPlus1 && d.Id() == "QEMU-Libvirt" { lst = []string{"VA vNUMA ID : ", "1", "1", vnumaStr, "1", "15", "2", "0", "2"} label += "\n\nIMPORTANT! Some QEMU versions do not support\n" + "disjoint NUMA CPU ranges therefore vNUMA configuration\n" + "is disabled for this vCPU.\n" } else { lst = []string{"VA vNUMA ID : ", "1", "1", vnumaStr, "1", "15", "2", "0", "0"} } lst = append(lst, "Host CPU(s) : ", "2", "1", cpusStr, "2", "15", "30", "0", "0") r, err := ui.Mixedform(label, false, lst[0:]...) if err != nil { if err.Error() == gui.DialogNext { uiShowNumaTopologyHelpMsg(ui) continue } return isChanged, err } if len(r) < 2 { continue } vcpuInt, err := strconv.Atoi(result) if err != nil { continue } vnumaInt, err := strconv.Atoi(r[0]) if err != nil { ui.Output(gui.Warning, "Illegal input \""+r[0]+"\"", "Press <OK> to return to menu.") continue } if err := verifyRange(vnumaInt, len(c.NUMAs)); err != nil { ui.Output(gui.Warning, err.Error(), "Press <OK> to return to menu.") continue } hostCpus := r[1] cpus := make([]int, 0) if strings.Contains(hostCpus, ",") { for _, e := range strings.Split(hostCpus, ",") { if strings.Contains(e, "-") { cpus, err = splitByHypen(e, totalCpusOnHost) if err != nil { ui.Output(gui.Warning, err.Error(), "Press <OK> to return to menu.") continue InternalLoop } } else { cpu, err := strconv.Atoi(e) if err != nil { ui.Output(gui.Warning, "Illegal input \""+e+"\"", "Press <OK> to return to menu.") continue InternalLoop } if err := verifyRange(cpu, totalCpusOnHost); err != nil { ui.Output(gui.Warning, err.Error(), "Press <OK> to return to menu.") continue InternalLoop } cpus = append(cpus, cpu) } } } else if strings.Contains(hostCpus, "-") { cpus, err = splitByHypen(hostCpus, totalCpusOnHost) if err != nil { ui.Output(gui.Warning, err.Error(), "Press <OK> to return to menu.") continue } } else { cpu, err := strconv.Atoi(hostCpus) if err != nil { ui.Output(gui.Warning, "Illegal input \""+hostCpus+"\"", "Press <OK> to return to menu.") continue } if err := verifyRange(cpu, totalCpusOnHost); err != nil { ui.Output(gui.Warning, err.Error(), "Press <OK> to return to menu.") continue } cpus = append(cpus, cpu) } // delete the old entry isChanged = true for _, n := range c.NUMAs { for vcpu, _ := range n.CPUPin { if vcpu == vcpuInt { delete(n.CPUPin, vcpu) } } } sort.Ints(cpus) // set the new entry c.NUMAs[vnumaInt].CPUPin[vcpuInt] = cpus continue MainLoop } break } // ui.Output(gui.Warning, "CPU "+hCPUnotOnce+" is assigned to more than one vCPU") // if isChanged { // file.WriteString("isChanged\n") // } else { // file.WriteString("NotChanged\n") // } // if isChanged { // ui.Output(gui.Warning, "CPU j is assigned to more than one vCPU") // continue MainLoop // } // file.WriteString("return: \n") return isChanged, nil }