myxce/src/frontend/xcecli/common/output/page_print_hosts.go
2026-05-21 03:41:57 +00:00

345 lines
9.6 KiB
Go

package output
import (
"fmt"
"strings"
"xcecli/models"
)
// HostsPagePrinter
type HostsPagePrinter struct {
*BasePagePrinter
}
// NewHostsPagePrinter
func NewHostsPagePrinter(opt ...BasePageOption) *HostsPagePrinter {
return &HostsPagePrinter{
BasePagePrinter: newBasePagePrinter(opt...),
}
}
// PrepareForPrinting
func (p *HostsPagePrinter) PrepareForPrinting(firstPage interface{}) {
hosts, ok := firstPage.(*models.HostsResponse)
if !ok {
fmt.Println("error: wrong data type to HostsPagePrinter")
return
}
// set field formats
p.fieldFormats = p.prepareFieldFormats()
// init column widths
p.initColumnWidths(hosts)
// prepare headers
p.prepareHeaders()
}
// prepare field formats
func (p *HostsPagePrinter) prepareFieldFormats() []*fieldFormat {
// here define the default fields based on the host data
var fieldFormats []*fieldFormat
if p.fields == "" {
// default fields
defaultFields := []string{
models.HEADER_HOST_NAME,
models.HEADER_HOST_STATUS,
models.HEADER_HOST_NCPUS,
models.HEADER_HOST_MAX_SLOT,
models.HEADER_HOST_NUM_RUN,
models.HEADER_HOST_NUM_SSUSP,
models.HEADER_HOST_NUM_USUSP,
models.HEADER_HOST_HOST_TYPE,
}
for _, field := range defaultFields {
fieldFormats = append(fieldFormats, &fieldFormat{name: field, align: "-"})
}
} else {
// parse user specified fields
for _, field := range strings.Split(p.fields, ",") {
fieldFormats = append(fieldFormats, parseFieldFormat(field))
}
}
return fieldFormats
}
// init column widths
func (p *HostsPagePrinter) initColumnWidths(hosts *models.HostsResponse) {
// init column widths to header length
for _, format := range p.fieldFormats {
p.columnWidths[format.name] = len(format.name)
if format.width > 0 {
p.columnWidths[format.name] = format.width
}
}
// calculate the max width of the first page data
for _, host := range hosts.Data.Rows {
for _, format := range p.fieldFormats {
width := 0
switch format.name {
case models.HEADER_HOST_NAME:
width = len(host.HostName)
case models.HEADER_HOST_STATUS:
width = len(host.HostStatus)
case models.HEADER_HOST_HOST_TYPE:
width = len(host.HostType)
case models.HEADER_HOST_NCPUS:
width = len(fmt.Sprintf("%d", host.NumCPUs))
case models.HEADER_HOST_MAX_SLOT:
width = len(fmt.Sprintf("%d", host.MaxSlot))
case models.HEADER_HOST_NUM_RUN:
width = len(fmt.Sprintf("%d", host.NumRun))
case models.HEADER_HOST_NUM_SSUSP:
width = len(fmt.Sprintf("%d", host.NumSSusp))
case models.HEADER_HOST_NUM_USUSP:
width = len(fmt.Sprintf("%d", host.NumUSusp))
}
if !p.wideFormat && width > 15 {
width = 15
}
if width > p.columnWidths[format.name] && format.width == 0 {
p.columnWidths[format.name] = width
}
}
}
}
// PrintPage
func (p *HostsPagePrinter) PrintPage(page interface{}) {
hosts, ok := page.(*models.HostsResponse)
if !ok {
fmt.Println("error: wrong data type to HostsPagePrinter")
return
}
p.pageCount++
if p.verbose {
printHostsVerboseOutput(hosts)
return
}
if p.formatJson {
p.printJsonPage(hosts)
return
} else {
// print header (if needed)
p.printHeader()
// print data rows
rows := p.formatRows(hosts, true)
for _, row := range rows {
fmt.Fprintln(p.w, strings.Join(row, "\t"))
}
p.w.Flush()
}
}
// format data rows
func (p *HostsPagePrinter) formatRows(hosts *models.HostsResponse, truncatFlag bool) [][]string {
var rows [][]string
if p.wideFormat {
truncatFlag = false
}
for _, host := range hosts.Data.Rows {
isUnavail := host.HostStatus == "UNAVAIL"
row := make([]string, 0, len(p.fieldFormats))
for _, format := range p.fieldFormats {
width := p.columnWidths[format.name]
align := format.align
switch format.name {
case models.HEADER_HOST_NAME:
row = appendOrDefault(row, FormatStringField(host.HostName, width, truncatFlag, true), "-")
case models.HEADER_HOST_STATUS:
row = appendOrDefault(row, FormatStringField(host.HostStatus, width, truncatFlag, true), "-")
case models.HEADER_HOST_HOST_TYPE:
if isUnavail {
row = append(row, FormatStringField("UNKNOWN", width, truncatFlag, true))
} else {
row = appendOrDefault(row, FormatStringField(host.HostType, width, truncatFlag, true), "-")
}
case models.HEADER_HOST_NCPUS:
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumCPUs), "0")
}
case models.HEADER_HOST_MAX_SLOT:
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.MaxSlot), "0")
}
case models.HEADER_HOST_NUM_RUN:
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumRun), "0")
}
case models.HEADER_HOST_NUM_SSUSP:
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumSSusp), "0")
}
case models.HEADER_HOST_NUM_USUSP:
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumUSusp), "0")
}
}
}
rows = append(rows, row)
}
return rows
}
// print JSON page
func (p *HostsPagePrinter) printJsonPage(hosts *models.HostsResponse) {
// if the format is JSON, directly convert the current page to JSON
headers := make([]string, len(p.fieldFormats))
for i, format := range p.fieldFormats {
headers[i] = format.name
}
rows := p.formatRows(hosts, false)
p.PrintJsonPageGeneric(rows, headers)
}
func printHostsVerboseOutput(hosts *models.HostsResponse) {
for _, host := range hosts.Data.Rows {
isUnavail := host.HostStatus == "UNAVAIL"
fmt.Printf("HOST %s\n", host.HostName)
// table 1
headers := models.HostDetailHeaders
row1 := make([]string, 0, len(headers))
widths1 := make([]int, len(headers))
for i, h := range headers {
var val string
switch h {
case models.HEADER_HOST_STATUS:
val = host.HostStatus
case models.HEADER_HOST_CPUF:
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%.2f", host.CPUFactor)
}
case models.HEADER_HOST_JLU:
val = "-"
case models.HEADER_HOST_MAX:
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.MaxSlot)
}
case models.HEADER_HOST_NJOBS:
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.NumRun)
}
case models.HEADER_HOST_RUN:
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.NumRun)
}
case models.HEADER_HOST_SSUSP:
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.NumSSusp)
}
case models.HEADER_HOST_USUSP:
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.NumUSusp)
}
case models.HEADER_HOST_RSV:
val = "-"
case models.HEADER_HOST_DISPT_WINDOW:
if str, ok := host.DisptWindow.(string); ok {
val = str
} else {
val = "-"
}
default:
val = "-"
}
widths1[i] = max(len(h), len(val))
row1 = append(row1, FormatStringField(val, widths1[i], false, true))
}
tp1 := TablePrinter{Headers: headers, Rows: [][]string{row1}, ColWidths: widths1}
tp1.Print()
fmt.Println("")
fmt.Println("CURRENT LOAD USED FOR SCHEDULING:")
// table2
headers2 := append([]string{""}, models.HostLoadSchedulingHeaders...)
var totalVals, reserveVals []string
if isUnavail {
totalVals = []string{"Total", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"}
reserveVals = []string{"Reserved", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"}
} else {
totalVals = []string{"Total", "0.0", "0.0", "0.0", "1%", "0.0", "33", "1", "1137", "51G", "3.9G", "6.8G", "8", "0.0"}
reserveVals = []string{"Reserved", "0.0", "0.0", "0.0", "0%", "0.0", "0", "0", "0", "0M", "0M", "0M", "-", "-"}
}
widths2 := make([]int, len(headers2))
for i := range headers2 {
widths2[i] = max(len(headers2[i]), len(totalVals[i]))
widths2[i] = max(widths2[i], len(reserveVals[i]))
}
rowTotal := make([]string, len(headers2))
rowReserve := make([]string, len(headers2))
for i := range headers2 {
rowTotal[i] = FormatStringField(totalVals[i], widths2[i], false, true)
rowReserve[i] = FormatStringField(reserveVals[i], widths2[i], false, true)
}
tp2 := TablePrinter{Headers: headers2, Rows: [][]string{rowTotal, rowReserve}, ColWidths: widths2}
tp2.Print()
fmt.Println("")
// Table 3
fmt.Println("LOAD THRESHOLD USED FOR SCHEDULING:")
headers3 := append([]string{""}, models.HostLoadSchedulingHeaders...)
loadSched := []string{"loadSched", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"}
loadStop := []string{"loadStop", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"}
widths3 := make([]int, len(headers3))
for i := range headers3 {
widths3[i] = max(len(headers3[i]), len(loadSched[i]))
widths3[i] = max(widths3[i], len(loadStop[i]))
}
rowSched := make([]string, len(headers3))
rowStop := make([]string, len(headers3))
for i := range headers3 {
rowSched[i] = FormatStringField(loadSched[i], widths2[i], false, true)
rowStop[i] = FormatStringField(loadStop[i], widths2[i], false, true)
}
tp3 := TablePrinter{Headers: headers3, Rows: [][]string{rowSched, rowStop}, ColWidths: widths2}
tp3.Print()
fmt.Println("")
fmt.Println("CONFIGURED AFFINITY CPU LIST: all")
}
}
func max(a, b int) int {
if a > b {
return a
}
return b
}