func uiShowNumaTopologyHelpMsg(ui *gui.DialogUi) { msg := "CPU Pinning Help\n" msg += "----------------\n\n" msg += "Example 1 : one to one pinning\n\n" msg += " _____________________________________\n" msg += "| VA vNUMA ID : 0_____________________|\n" msg += "| Host CPU(s) : 0_____________________|\n" msg += "|_____________________________________|\n\n" msg += " __________________ CPU/NUMA Topology ________________\n" msg += "|____________ VA ___________|_________ Host __________|\n" msg += "|____ vCPU ___|___ vNUMA ___|_________CPU(s) _________|\n" msg += "|______ 0 ____|_____ 0 _____|__________ 0 ____________|\n\n" msg += "VA CPU 0 will be pinned to the host CPU 0\n\n\n" msg += "Example 2 : pinning to a range of the host CPUs\n\n" msg += " _____________________________________\n" msg += "| VA vNUMA ID : 0_____________________|\n" msg += "| Host CPU(s) : 0-3___________________|\n" msg += "|_____________________________________|\n\n" msg += " __________________ CPU/NUMA Topology ________________\n" msg += "|____________ VA ___________|_________ Host __________|\n" msg += "|____ vCPU ___|___ vNUMA ___|_________CPU(s) _________|\n" msg += "|______ 0 ____|_____ 0 _____|__________ 0,1,2,3_______|\n\n" msg += "VA CPUs will be pinned to the host CPUs 0,1,2 and 3\n\n\n" msg += "Example 3 : pinning to a list of the host CPUs\n\n" msg += " _____________________________________\n" msg += "| VA vNUMA ID : 0_____________________|\n" msg += "| Host CPU(s) : 0,1,2,3,8_____________|\n" msg += "|_____________________________________|\n\n" msg += " __________________ CPU/NUMA Topology ________________\n" msg += "|____________ VA ___________|_________ Host __________|\n" msg += "|____ vCPU ___|___ vNUMA ___|_________CPU(s) _________|\n" msg += "|______ 0 ____|_____ 0 _____|_______ 0,1,2,3,8 _______|\n\n" msg += "VA CPUs will be pinned to the host CPUs 0,1,2,3 and 8\n\n" ui.Msgbox(msg) }
// 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 uiDiskNotOK(ui *gui.DialogUi, selectedDiskInMb, minDiskInMb, maxDiskInMb int) bool { if selectedDiskInMb < minDiskInMb { ui.Output(gui.Warning, fmt.Sprintf("Minimum disk size requirement is %dGB.", minDiskInMb/1024), "Press <OK> to return to menu.") return true } if selectedDiskInMb > maxDiskInMb { ui.Output(gui.Warning, fmt.Sprintf("Maximum disk size requirement is %dGB.", maxDiskInMb/1024), "Press <OK> to return to menu.") return true } return false }
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 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 }
func UiGatherHWInfo(ui *gui.DialogUi, hidriver deployer.HostinfoDriver, remote bool) error { errCh := make(chan error) defer close(errCh) go func() { errCh <- hidriver.Init() }() var msg string if remote { msg = "Gathering harwdare information from remote host.\nPlease wait..." } else { msg = "Gathering hardware information from local host.\nPlease wait..." } return ui.Wait(msg, time.Second*2, 0, errCh) }
func uiCpuNotOK(ui *gui.DialogUi, selectedCpus, installedCpus, minCpus, maxCpus int) bool { if selectedCpus < minCpus { ui.Output(gui.Warning, fmt.Sprintf("Minimum vCPUs requirement is %d.", minCpus), "Press <OK> to return to menu.") return true } if selectedCpus > maxCpus { ui.Output(gui.Warning, fmt.Sprintf("Amount of vCPUs exceeds maximum supported vCPUs(%d).", maxCpus), "Press <OK> to return to menu.") return true } if selectedCpus > installedCpus { if !UiVCPUsOvercommit(ui, installedCpus) { return true } } return false }
func UiImagePath(ui *gui.DialogUi, defaultLocation string, remote bool) (string, error) { if remote { return ui.GetFromInput("Select directory on remote server to install the VA image on", defaultLocation, "Back", "") } var location string var err error for { location, err = ui.GetPathToDirFromInput("Select directory to install the VA image on", defaultLocation, "Back", "") if err != nil { return "", err } if _, err := os.Stat(location); err == nil { break } } return location, nil }
func UiRemoteMode(ui *gui.DialogUi) (bool, error) { ui.SetTitle("Deployment Mode") ui.SetSize(9, 28) answer, err := ui.Menu(2, "1", "Local", "2", "Remote") if err != nil { return false, err } if answer == "1" { return false, nil } if _, err := exec.LookPath("sshfs"); err != nil { ui.Output(gui.Error, "sshfs utility is not installed") } return true, nil }
func uiBundleConfig(ui *gui.DialogUi, configs []*Config, advancedConfig bool) (*Config, error) { var temp []string index := 0 for _, c := range configs { index += 1 temp = append(temp, strconv.Itoa(index), fmt.Sprintf("%-15s [ vCPU %-2d | RAM %-3dMB]", c.Name, c.CPUs, c.RAM)) } advIndex := index + 1 temp = append(temp, strconv.Itoa(advIndex), "Custom configuration") sliceLength := len(temp) var configNumStr string var err error for { ui.SetSize(sliceLength+6, 50) ui.SetLabel("Select Virtual Machine configuration") configNumStr, err = ui.Menu(sliceLength+6, temp[0:]...) if err != nil { return nil, err } if configNumStr != "" { break } } configNumInt, err := strconv.Atoi(configNumStr) if err != nil { return nil, utils.FormatError(err) } if configNumInt == advIndex { return nil, nil } return configs[configNumInt-1], nil }
func uiRamNotOK(ui *gui.DialogUi, selectedRamInMb, installedRamMb, minRamInMb, maxRamInMb int) bool { if selectedRamInMb > installedRamMb { ui.Output(gui.Warning, "Required RAM exceeds host machine available memory.", "Press <OK> to return to menu.") return true } if selectedRamInMb < minRamInMb { ui.Output(gui.Warning, fmt.Sprintf("Minimum RAM requirement is %0.1fGB.", float64(minRamInMb)/1024), "Press <OK> to return to menu.") return true } if selectedRamInMb > maxRamInMb { ui.Output(gui.Warning, fmt.Sprintf("Maximum RAM requirement is %0.1fGB.", float64(maxRamInMb)/1024), "Press <OK> to return to menu.") return true } return false }
func UiVCPUsOvercommit(ui *gui.DialogUi, installedCpus int) bool { ui.SetSize(8, 75) ui.SetTitle(gui.Warning) ui.SetLabel(fmt.Sprintf("\nThe host only has %d CPUs.Overcommitting vCPUs can reduce performance!\nWould you like to proceed?", installedCpus)) return ui.Yesno() }
func UiApplianceName(ui *gui.DialogUi, defaultName string, driver deployer.EnvDriver) (string, error) { var name string var err error for { ui.SetSize(8, len(defaultName)+10) ui.SetTitle("Virtual machine name") ui.HelpButton(true) ui.SetHelpLabel("Back") name, err = ui.Inputbox(defaultName) if err != nil { return "", err } if name != "" { name = strings.Replace(name, ".", "-", -1) if driver != nil { if driver.DomainExists(name) { ui.Output(gui.Warning, "domain "+name+" already exists.", "Press <OK> to return to menu.") continue } } break } } return name, 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 }
func UiWarningOnOptimizationFailure(ui *gui.DialogUi, warningStr string) bool { ui.SetTitle(gui.Warning) ui.SetSize(10, 80) ui.SetLabel("Virtual machine configuration can not be optimized.\n" + warningStr + "\n\nDo you want to continue?") return ui.Yesno() }
func UiDeploymentResult(ui *gui.DialogUi, msg string, err error) { if err != nil { ui.Output(gui.Error, err.Error()) } ui.Output(gui.Success, msg) }
func UiSshConfig(ui *gui.DialogUi) (*sshconf.Config, error) { cfg := new(sshconf.Config) cfg.Port = "22" cfg.User = "******" origlist := []string{"IP : ", "1", "1", "", "1", "10", "22", "0", "0", "SSH Port: ", "2", "1", cfg.Port, "2", "10", "22", "0", "0", "Username: "******"3", "1", cfg.User, "3", "10", "22", "0", "0"} MainLoop: for { ui.HelpButton(true) ui.SetHelpLabel("Back") reslist, err := ui.Mixedform("Remote session configuration", false, origlist[0:]...) if err != nil { return nil, err } if len(reslist) < 3 { continue } if net.ParseIP(reslist[0]) == nil { continue } cfg.Host = reslist[0] portDig, err := strconv.Atoi(reslist[1]) if err != nil { return nil, utils.FormatError(err) } if portDig > 65535 { continue } AuthLoop: for { ui.SetTitle("Authentication method") ui.SetSize(9, 18) ui.HelpButton(true) ui.SetHelpLabel("Back") val, err := ui.Menu(2, "1", "Password", "2", "Private key") if err != nil { switch err.Error() { case gui.DialogMoveBack: continue MainLoop case gui.DialogExit: os.Exit(1) } } switch val { case "1": cfg.Password, err = ui.GetPasswordFromInput(cfg.Host, cfg.User, "Back", "", false) case "2": cfg.PrvtKeyFile, err = ui.GetPathToFileFromInput("Path to ssh private key file", "Back", "") } if err != nil { switch err.Error() { case gui.DialogMoveBack: continue AuthLoop case gui.DialogExit: os.Exit(1) } } break MainLoop } } run := utils.RunFunc(cfg) errCh := make(chan error) defer close(errCh) go func() { // verifying that user is able execute a command by using sudo _, err := run("uname") errCh <- err }() if err := ui.Wait("Trying to establish SSH connection to remote host.\nPlease wait...", time.Second*1, time.Second*5, errCh); err != nil { ui.Output(gui.Warning, "Unable to establish SSH connection.", "Press <OK> to return to menu.") goto MainLoop } return cfg, nil }
func UiNetworks(ui *gui.DialogUi, data *xmlinput.XMLInputData, allowedNics host.NICList, gconf *guest.Config) error { guestPciSlotCounter := data.GuestNic.PCI.FirstSlot lastGuestPciSlotCounter := guestPciSlotCounter portCounter := 1 lastPortCounter := portCounter i := 0 MainLoop: for i < len(data.Networks.Configs) { net := data.Networks.Configs[i] PolicyLoop: for { var modes []xmlinput.ConnectionMode if net.UiModeBinding == nil || len(net.UiModeBinding) == 0 { for _, mode := range net.Modes { modes = append(modes, mode.Type) } } else { var err error modes, err = uiNetworkPolicySelector(ui, net) if err != nil { switch err.Error() { case gui.DialogMoveBack: gconf.Networks = gconf.Networks[:i] gconf.NICLists = gconf.NICLists[:i] portCounter = lastPortCounter - 1 guestPciSlotCounter = lastGuestPciSlotCounter - 1 if i == 0 { return err } i-- continue MainLoop case gui.DialogNext: i++ continue MainLoop case gui.DialogExit: os.Exit(1) default: return err } } } retainedNics, err := host_hwfilter.NicsByType(allowedNics, modes) if err != nil { return utils.FormatError(err) } if len(retainedNics) == 0 { ui.Output(gui.Warning, "No interfaces have been found.", "Press <OK> to return to menu.") continue MainLoop } if net.UiResetCounter { portCounter = 1 } list, err := uiNicSelectMenu(ui, data, &portCounter, &guestPciSlotCounter, retainedNics, net, i) if err != nil { switch err.Error() { case gui.DialogMoveBack: if i == 0 { return err } gconf.Networks = gconf.Networks[:i] gconf.NICLists = gconf.NICLists[:i] continue PolicyLoop case gui.DialogExit: os.Exit(1) } } gconf.Networks = append(gconf.Networks, net) gconf.NICLists = append(gconf.NICLists, list) lastPortCounter = portCounter lastGuestPciSlotCounter = guestPciSlotCounter i++ break } } return nil }
// UiValidateUser intended for validate the ID // of the user executing deployer binary func UiValidateUser(ui *gui.DialogUi, userId int) { if err := infrautils.ValidateUserID(userId); err != nil { ui.Output(gui.Error, err.Error()) } }
func UiNumaRamNotOK(ui *gui.DialogUi, driver deployer.HostinfoDriver, c *guest.Config, selectedRamInMb int) (bool, error) { // file, err := os.Create("/tmp/_setNUMATuneData.txt") // defer file.Close() numas, err := driver.NUMAInfo() if err != nil { return true, utils.FormatError(err) } NumaForCheck := make([]int, 0) // file.WriteString("uiNumaRamNotOK\n") for _, n := range c.NUMAs { // file.WriteString("c.NUMAs\n") for _, nic := range n.NICs { if nic.HostNIC.Type == host.NicTypePhys || nic.HostNIC.Type == host.NicTypePhysVF { isAdd := true for _, v := range NumaForCheck { if v == nic.HostNIC.NUMANode { isAdd = false } } if isAdd { NumaForCheck = append(NumaForCheck, nic.HostNIC.NUMANode) // file.WriteString("NumaForCheck: [" + strconv.Itoa(nic.HostNIC.NUMANode) + "]\n") } } } } // selectedRamInMb = 1 var requiredMemory float64 var freeRam float64 numberOfNumas := len(NumaForCheck) if numberOfNumas < 1 { numberOfNumas = 1 } requiredMemoryMB := selectedRamInMb / numberOfNumas requiredMemory = float64(selectedRamInMb / numberOfNumas) requiredMemoryStr := strconv.FormatFloat((requiredMemory / 1024), 'f', 1, 64) // file.WriteString("requiredMemoryStr: " + requiredMemoryStr + " selectedRamInMb:" + strconv.Itoa(selectedRamInMb) + " \n") for _, node := range numas { for _, CellID := range NumaForCheck { // file.WriteString("CellID: " + strconv.Itoa(CellID) + " node.CellID: " + strconv.Itoa(node.CellID) + "\n") if node.CellID != CellID { continue } numafreeRamMb := node.FreeRAM / 1024 // file.WriteString("requiredMemoryMB: " + strconv.Itoa(requiredMemoryMB) + " node.FreeRAM:" + strconv.Itoa(numafreeRamMb) + " \n") // numafreeRamMb = 0 if numafreeRamMb < requiredMemoryMB { freeRam = float64(node.FreeRAM / (1024 * 1024)) freeRamStr := strconv.FormatFloat(freeRam, 'f', 1, 64) ui.SetTitle(gui.Warning) ui.SetSize(10, 80) ui.SetLabel("Virtual machine configuration can not be optimized.\n" + requiredMemoryStr + " GB RAM are required on NUMA " + strconv.Itoa(node.CellID) + " but just " + freeRamStr + "Gb are available\n\nDo you want to continue?") return ui.Yesno(), nil } } } return true, nil }
func uiNicSelectMenu(ui *gui.DialogUi, data *xmlinput.XMLInputData, guestPortCounter *int, guestPciSlotCounter *int, hnics host.NICList, net *xmlinput.Network, index int) (guest.NICList, error) { list := make([]string, 0) keeper := make(map[string]*host.NIC) indexStrToInt := make(map[string][]int) indexInt := 1 for _, hnic := range hnics { indexStr := strconv.Itoa(indexInt) list = append(list, indexStr, fmt.Sprintf("%-22s%-15s%-68s%-10s", hnic.Name, hnic.PCIAddr, hnic.Desc, uiNUMAIntToString(hnic.NUMANode))) keeper[indexStr] = hnic if indexInt == 1 { // index 0 - element index in the list // index 1 - element counter // index 2 - PCI slot number represented as integer indexStrToInt[indexStr] = []int{1, 0, 0} } else { indexStrToInt[indexStr] = []int{indexInt*2 - 1, 0, 0} } indexInt++ } listLength := len(list) gnics := guest.NewNICList() var disjuncNicVendor string var disjuncNicModel string for { if index > 0 { ui.HelpButton(true) ui.SetHelpLabel("Back") } width := uiHeaderSelectNics(ui) ui.SetSize(listLength+8, width+5) ui.SetTitle(fmt.Sprintf("Select interface for network \"%s\"", net.Name)) nicNumStr, err := ui.Menu(listLength+5, list[0:]...) if err != nil { if err.Error() == gui.DialogNext { if len(gnics) == 0 && net.Optional == false { continue } break } *guestPciSlotCounter -= len(gnics) *guestPortCounter -= len(gnics) return nil, err } hnic := keeper[nicNumStr] // verify that we need to proceed with "disjunction" if net.NicsDisjunction && (hnic.Type == host.NicTypePhys || hnic.Type == host.NicTypePhysVF) && (hnic.Vendor != disjuncNicVendor && hnic.Model != disjuncNicModel) { // back to menu in case "disjunction" entries already exist if host_hwfilter.NicDisjunctionFound(hnic, data.HostNics.Allowed) && disjuncNicVendor != "" { msg := fmt.Sprintf("'%s' cannot be selected alongside '%s %s'", hnic.Desc, disjuncNicVendor, disjuncNicModel) ui.Output(gui.Warning, msg, "Press <OK> to return to menu.") continue } // set the new entries disjuncNicVendor = hnic.Vendor disjuncNicModel = hnic.Model } delNicCounter := indexStrToInt[nicNumStr][1] // counter for the NIC found,we should remove the NIC object and its references if delNicCounter > 0 { // find the guest NIC object in the guest NICs list if _, index, err := gnics.NicByHostNicObj(hnic); err == nil { // if found : // - remove the object // - decrement guestPortCounter // - decriment guestPciSlotCounter gnics.Remove(index) if *guestPortCounter > 0 { *guestPortCounter-- } if *guestPciSlotCounter > data.GuestNic.PCI.FirstSlot { *guestPciSlotCounter-- } // update the list with the new entry containing deselected NIC list[indexStrToInt[nicNumStr][0]] = fmt.Sprintf("%-22s%-15s%-68s%-10s", hnic.Name, hnic.PCIAddr, hnic.Desc, uiNUMAIntToString(hnic.NUMANode)) // - reset element counter // - reset PCI slot number indexStrToInt[nicNumStr][1] = 0 indexStrToInt[nicNumStr][2] = 0 } // iterate over the map and update entries for nicIndex, data := range indexStrToInt { nicCounter := data[1] if nicCounter > delNicCounter { tmpNic := keeper[nicIndex] nicCounter-- list[data[0]] = fmt.Sprintf("%-22s%-15s%-68s%-9s%d", tmpNic.Name, tmpNic.PCIAddr, tmpNic.Desc, uiNUMAIntToString(tmpNic.NUMANode), nicCounter) indexStrToInt[nicIndex][1] = nicCounter indexStrToInt[nicIndex][2]-- if gnic, _, err := gnics.NicByHostNicObj(tmpNic); err == nil { gnic.PCIAddr.Slot = utils.IntToHexString(indexStrToInt[nicIndex][2]) } } } // clear "disjunction" entries in case gnics slice is empty if gnics.Length() == 0 { disjuncNicVendor = "" disjuncNicModel = "" } continue } // create new guest NIC, set his number and counter indexStrToInt[nicNumStr][1] = *guestPortCounter indexStrToInt[nicNumStr][2] = *guestPciSlotCounter list[indexStrToInt[nicNumStr][0]] = fmt.Sprintf("%-22s%-15s%-68s%-9s%d", hnic.Name, hnic.PCIAddr, hnic.Desc, uiNUMAIntToString(hnic.NUMANode), *guestPortCounter) gnic := guest.NewNIC() gnic.Network = net.Name gnic.PCIAddr.Domain = data.PCI.Domain gnic.PCIAddr.Bus = data.PCI.Bus gnic.PCIAddr.Slot = utils.IntToHexString(*guestPciSlotCounter) gnic.PCIAddr.Function = data.PCI.Function gnic.HostNIC = hnic gnics.Add(gnic) *guestPciSlotCounter++ *guestPortCounter++ } return gnics, nil }
// UiWelcomeMsg prints out appropriate welcome message func UiWelcomeMsg(ui *gui.DialogUi, name string) { msg := "Welcome to the " + name + " deployment procedure!" ui.SetSize(6, len(msg)+5) ui.Msgbox(msg) }
func UiVmConfig(ui *gui.DialogUi, driver deployer.HostinfoDriver, xidata *xmlinput.XMLInputData, pathToMainImage string, sconf *image.Storage, conf *guest.Config) error { var installedRamMb int var maxRAM int var err error list := make([]string, 0) index := 1 if xidata.CPU.Configure { cpuStr := fmt.Sprintf(" %-9s | %d-%d", "CPU", xidata.CPU.Min, xidata.CPU.Max) list = []string{cpuStr, strconv.Itoa(index), "1", strconv.Itoa(xidata.CPU.Default), "1", "30", "6", "0", "0"} index++ } else if xidata.CPU.Default > 0 { conf.CPUs = xidata.CPU.Default } if xidata.RAM.Configure { installedRamMb, err = driver.RAMSize() if err != nil { return utils.FormatError(err) } if xidata.RAM.Max > installedRamMb || xidata.RAM.Max == xmlinput.UnlimitedAlloc { maxRAM = installedRamMb } else { maxRAM = xidata.RAM.Max } ramStr := fmt.Sprintf(" %-9s | %d-%dG", "RAM", xidata.RAM.Min/1024, maxRAM/1024) list = append(list, []string{ramStr, strconv.Itoa(index), "1", strconv.Itoa(xidata.RAM.Default / 1024), "2", "30", "6", "0", "0"}...) index++ } else if xidata.RAM.Default > 0 { conf.RamMb = xidata.RAM.Default } if xidata.Disks.Configure { diskName := "Disk" for i, disk := range xidata.Disks.Configs { if i > 0 { diskName = strconv.Itoa(i) + "_" + strconv.Itoa(i) } diskStr := fmt.Sprintf(" %-9s | %d-%dG", diskName, disk.Min/1024, disk.Max/1024) indexStr := strconv.Itoa(index) list = append(list, []string{diskStr, indexStr, "1", strconv.Itoa(disk.Default / 1024), indexStr, "30", "6", "0", "0"}...) index++ } } str := " ______________________________________\n| Resource | Maximum | Allocated |" installedCpus, err := driver.CPUs() if err != nil { return utils.FormatError(err) } index-- if index > 1 { MainLoop: for { ui.SetSize(11, 46) ui.SetTitle("Virtual Machine configuration") ui.HelpButton(true) ui.SetHelpLabel("Back") resultIndex := 0 result, err := ui.Mixedform(str, false, list[0:]...) if err != nil { return err } if len(result) < index { continue } if xidata.CPU.Configure { selectedCpus, err := strconv.Atoi(result[resultIndex]) if err != nil { continue } if uiCpuNotOK(ui, selectedCpus, installedCpus, xidata.CPU.Min, xidata.CPU.Max) { continue } conf.CPUs = selectedCpus resultIndex++ } if xidata.RAM.Configure { selectedRamMb, err := utils.FloatStringToInt(result[resultIndex], 1024) if err != nil { continue MainLoop } if uiRamNotOK(ui, selectedRamMb, installedRamMb, xidata.RAM.Min, maxRAM) { continue } conf.RamMb = selectedRamMb resultIndex++ } if xidata.Disks.Configure { disks := make([]int, 0) for _, disk := range xidata.Disks.Configs { selectedDiskSizeMb, err := utils.FloatStringToInt(result[resultIndex], 1024) if err != nil { continue MainLoop } if uiDiskNotOK(ui, selectedDiskSizeMb, disk.Min, disk.Max) { continue MainLoop } disks = append(disks, selectedDiskSizeMb*1024) resultIndex++ } if conf.Storage, err = config.StorageConfig(pathToMainImage, 0, sconf, disks); err != nil { return err } } break } } return nil }
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 }