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 }