Merge branch 'persistent_ha' into scheduler
This commit is contained in:
commit
a07a74a943
106 changed files with 18528 additions and 637 deletions
|
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
jobfmt "xcecli/common/format"
|
||||
"xcecli/models"
|
||||
)
|
||||
|
|
@ -96,7 +95,7 @@ func (p *ArrayElementsPagePrinter) initColumnWidths(jobs *models.JobsResponse) {
|
|||
case models.HEADER_JOB_NAME:
|
||||
width = len(job.JobName)
|
||||
case models.HEADER_JOB_SUBMIT_TIME:
|
||||
width = len(job.SubmitTime)
|
||||
width = len(fmtUnixTime(job.SubmitTime))
|
||||
}
|
||||
|
||||
if !p.wideFormat && width > 15 {
|
||||
|
|
@ -166,7 +165,7 @@ func (p *ArrayElementsPagePrinter) formatRows(jobs *models.JobsResponse, truncat
|
|||
mainRow = appendOrDefault(mainRow, FormatStringField(job.FromHost, width, truncatFlag, true), "-")
|
||||
case models.HEADER_JOB_EXEC_HOST:
|
||||
var execHosts models.ExecHosts
|
||||
if err := json.Unmarshal([]byte(job.ExecHosts.String()), &execHosts); err == nil && len(execHosts.HostSlots) > 0 {
|
||||
if err := json.Unmarshal([]byte(job.ExecHosts.String()), &execHosts); err == nil && len(execHosts.HostSlots) > 0 && execHosts.HostSlots[0].HostName != "" {
|
||||
firstHost := fmt.Sprintf("%d*%s", execHosts.HostSlots[0].NumSlots, execHosts.HostSlots[0].HostName)
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(firstHost, width, truncatFlag, true), "-")
|
||||
|
||||
|
|
@ -190,21 +189,7 @@ func (p *ArrayElementsPagePrinter) formatRows(jobs *models.JobsResponse, truncat
|
|||
case models.HEADER_JOB_NAME:
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(job.JobName, width, truncatFlag, true), "-")
|
||||
case models.HEADER_JOB_SUBMIT_TIME:
|
||||
// remove the timezone part and parse the time
|
||||
timeStr := strings.Split(job.SubmitTime, " ")[0:2]
|
||||
timeStrWithoutTZ := strings.Join(timeStr, " ")
|
||||
|
||||
if submitTime, err := time.Parse("2006-01-02 15:04:05", timeStrWithoutTZ); err == nil {
|
||||
month := submitTime.Format("Jan")
|
||||
displayTime := fmt.Sprintf("%s %02d %02d:%02d",
|
||||
month,
|
||||
submitTime.Day(),
|
||||
submitTime.Hour(),
|
||||
submitTime.Minute())
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(displayTime, width, truncatFlag, true), "-")
|
||||
} else {
|
||||
mainRow = appendOrDefault(mainRow, fmt.Sprintf("%"+align+"*s", width, "-"), "-")
|
||||
}
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(fmtUnixTime(job.SubmitTime), width, truncatFlag, true), "-")
|
||||
}
|
||||
}
|
||||
rows = append(rows, mainRow)
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func (p *JobsPagePrinter) initColumnWidths(jobs *models.JobsResponse) {
|
|||
case models.HEADER_JOB_NAME:
|
||||
width = len(job.JobName)
|
||||
case models.HEADER_JOB_SUBMIT_TIME:
|
||||
width = len(job.SubmitTime)
|
||||
width = len(fmtUnixTime(job.SubmitTime))
|
||||
case models.HEADER_JOB_CORE_LIMIT:
|
||||
width = len(fmt.Sprintf("%f", job.CoreLimit))
|
||||
case models.HEADER_JOB_MEM_LIMIT:
|
||||
|
|
@ -179,7 +179,7 @@ func (p *JobsPagePrinter) formatRows(jobs *models.JobsResponse, truncatFlag bool
|
|||
|
||||
case models.HEADER_JOB_EXEC_HOST:
|
||||
var execHosts models.ExecHosts
|
||||
if err := json.Unmarshal([]byte(job.ExecHosts.String()), &execHosts); err == nil && len(execHosts.HostSlots) > 0 {
|
||||
if err := json.Unmarshal([]byte(job.ExecHosts.String()), &execHosts); err == nil && len(execHosts.HostSlots) > 0 && execHosts.HostSlots[0].HostName != "" {
|
||||
firstHost := fmt.Sprintf("%d*%s", execHosts.HostSlots[0].NumSlots, execHosts.HostSlots[0].HostName)
|
||||
mainRow = appendOrDefault(mainRow,
|
||||
FormatStringField(firstHost, width, truncatFlag, false), "-")
|
||||
|
|
@ -201,11 +201,7 @@ func (p *JobsPagePrinter) formatRows(jobs *models.JobsResponse, truncatFlag bool
|
|||
mainRow = appendOrDefault(mainRow, fmt.Sprintf("%"+align+"*s", width, "-"), "-")
|
||||
}
|
||||
case models.HEADER_JOB_SUBMIT_TIME:
|
||||
if submitTime, err := parseJobTime(job.SubmitTime); err == nil {
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(formatJobTime(submitTime), width, truncatFlag, true), "-")
|
||||
} else {
|
||||
mainRow = appendOrDefault(mainRow, fmt.Sprintf("%"+align+"*s", width, "-"), "-")
|
||||
}
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(fmtUnixTime(job.SubmitTime), width, truncatFlag, true), "-")
|
||||
|
||||
// normal fields
|
||||
case models.HEADER_JOB_NAME:
|
||||
|
|
@ -223,9 +219,9 @@ func (p *JobsPagePrinter) formatRows(jobs *models.JobsResponse, truncatFlag bool
|
|||
case models.HEADER_JOB_PROJECT_NAME:
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(job.ProjectName, width, truncatFlag, true), "-")
|
||||
case models.HEADER_JOB_START_TIME:
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(job.StartTime, width, truncatFlag, true), "-")
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(fmtUnixTime(job.StartTime), width, truncatFlag, true), "-")
|
||||
case models.HEADER_JOB_END_TIME:
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(job.EndTime, width, truncatFlag, true), "-")
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(fmtUnixTime(job.EndTime), width, truncatFlag, true), "-")
|
||||
case models.HEADER_JOB_CWD:
|
||||
mainRow = appendOrDefault(mainRow, FormatStringField(job.CWD, width, truncatFlag, true), "-")
|
||||
case models.HEADER_JOB_LAUNCH_TYPE:
|
||||
|
|
@ -303,7 +299,7 @@ func printJobsVerboseOutput(jobs *models.JobsResponse, filter []string) {
|
|||
|
||||
// (2) print the submit time info
|
||||
submitLine := ""
|
||||
if submitTime, err := parseJobTime(job.SubmitTime); err == nil {
|
||||
if submitTime, ok := unixToTime(job.SubmitTime); ok {
|
||||
submitLine = submitLine + fmt.Sprintf("%s %s %02d:%02d:%02d: ",
|
||||
submitTime.Format("Jan"), submitTime.Format("02"),
|
||||
submitTime.Hour(), submitTime.Minute(), submitTime.Second())
|
||||
|
|
@ -322,9 +318,20 @@ func printJobsVerboseOutput(jobs *models.JobsResponse, filter []string) {
|
|||
}
|
||||
PrintWrappedLine(w, submitLine, 80, 18)
|
||||
|
||||
// (3) print the start time info
|
||||
// (3) print the pending reason for jobs waiting to be dispatched
|
||||
if job.JobStatus == "PEND" || job.JobStatus == "PSUSP" {
|
||||
if job.PendingReason != "" {
|
||||
fmt.Fprintf(w, " PENDING REASONS:\n")
|
||||
fmt.Fprintf(w, " %s\n", job.PendingReason)
|
||||
}
|
||||
}
|
||||
|
||||
// (4) print the start time info — skip for jobs that haven't started yet
|
||||
startLine := ""
|
||||
if startTime, err := parseJobTime(job.StartTime); err == nil {
|
||||
if job.JobStatus == "PEND" || job.JobStatus == "PSUSP" {
|
||||
goto printEndLine
|
||||
}
|
||||
if startTime, ok := unixToTime(job.StartTime); ok {
|
||||
month := startTime.Format("Jan")
|
||||
day := startTime.Format("02")
|
||||
exec_hostname := ""
|
||||
|
|
@ -380,10 +387,11 @@ func printJobsVerboseOutput(jobs *models.JobsResponse, filter []string) {
|
|||
}
|
||||
PrintWrappedLine(w, startLine, 80, 18)
|
||||
|
||||
printEndLine:
|
||||
// (4) print end line
|
||||
endLine := ""
|
||||
if job.JobStatus == "DONE" || job.JobStatus == "EXIT" {
|
||||
if endTime, err := parseJobTime(job.EndTime); err == nil {
|
||||
if endTime, ok := unixToTime(job.EndTime); ok {
|
||||
endLine = endLine + fmt.Sprintf("%s %s %02d:%02d:%02d: ",
|
||||
endTime.Format("Jan"), endTime.Format("02"),
|
||||
endTime.Hour(), endTime.Minute(), endTime.Second())
|
||||
|
|
|
|||
|
|
@ -5,17 +5,23 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// parseJobTime parses a job time string supporting RFC3339 and space-separated formats.
|
||||
func parseJobTime(s string) (time.Time, error) {
|
||||
if s == "" {
|
||||
return time.Time{}, fmt.Errorf("empty time string")
|
||||
// unixToTime converts a Unix-second timestamp to time.Time.
|
||||
// Returns (time, true) for ts > 0; (zero, false) for unset/zero values.
|
||||
func unixToTime(ts int64) (time.Time, bool) {
|
||||
if ts <= 0 {
|
||||
return time.Time{}, false
|
||||
}
|
||||
for _, f := range []string{time.RFC3339Nano, time.RFC3339, "2006-01-02 15:04:05", "2006-01-02 15:04:05 MST"} {
|
||||
if t, err := time.Parse(f, s); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
return time.Unix(ts, 0), true
|
||||
}
|
||||
|
||||
// fmtUnixTime formats a Unix timestamp as "Jan 02 15:04" for table display.
|
||||
// Returns "-" for zero/unset values.
|
||||
func fmtUnixTime(ts int64) string {
|
||||
t, ok := unixToTime(ts)
|
||||
if !ok {
|
||||
return "-"
|
||||
}
|
||||
return time.Time{}, fmt.Errorf("cannot parse time: %q", s)
|
||||
return formatJobTime(t)
|
||||
}
|
||||
|
||||
// formatJobTime formats a time.Time as "Jan 02 15:04" for table display.
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ package models
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -32,6 +30,7 @@ const (
|
|||
HEADER_JOB_LAUNCH_TYPE = "LAUNCH_TYPE"
|
||||
HEADER_JOB_NUM_PROCESSORS = "NUM_PROCESSORS"
|
||||
HEADER_JOB_INTERACTIVE_URL = "INTERACTIVE_URL"
|
||||
HEADER_JOB_PENDING_REASON = "PENDING_REASON"
|
||||
|
||||
// second line
|
||||
HEADER_JOB_R15S = "r15s"
|
||||
|
|
@ -114,10 +113,10 @@ type QueryJob struct {
|
|||
TermTime string `json:"term_time"`
|
||||
UserPriority int `json:"user_priority"`
|
||||
DependCond string `json:"depend_cond"`
|
||||
SubmitTime string `json:"submit_time"`
|
||||
ReserveTime time.Time `json:"reserve_time"`
|
||||
StartTime string `json:"start_time"`
|
||||
EndTime string `json:"end_time"`
|
||||
SubmitTime int64 `json:"submit_time"`
|
||||
ReserveTime int64 `json:"reserve_time"`
|
||||
StartTime int64 `json:"start_time"`
|
||||
EndTime int64 `json:"end_time"`
|
||||
JobRusage string `json:"job_rusage"`
|
||||
MaxMem float64 `json:"max_mem"`
|
||||
AvgMem float64 `json:"avg_mem"`
|
||||
|
|
@ -210,6 +209,7 @@ var JobFieldsMap = map[string]string{
|
|||
HEADER_JOB_LAUNCH_TYPE: "launch_type",
|
||||
HEADER_JOB_NUM_PROCESSORS: "num_processors",
|
||||
HEADER_JOB_INTERACTIVE_URL: "interactive_job_url",
|
||||
HEADER_JOB_PENDING_REASON: "pending_reason",
|
||||
//job_filter.HEADER_JOB_PRIORITY: "job_priority",
|
||||
}
|
||||
|
||||
|
|
@ -258,16 +258,23 @@ func (e ExecHosts) String() string {
|
|||
|
||||
// UnmarshalJSON customizes the JSON parsing method, compatible with both string "-" and structure formats
|
||||
func (e *ExecHosts) UnmarshalJSON(data []byte) error {
|
||||
// JSON null means no allocation — treat as empty
|
||||
if string(data) == "null" {
|
||||
e.HostSlots = []HostSlot{}
|
||||
e.NumHosts = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// First try to parse as a string
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err == nil {
|
||||
// If the string is "-", return an empty ExecHosts
|
||||
if str == "-" {
|
||||
// Empty string or "-" both mean no hosts
|
||||
if str == "" || str == "-" {
|
||||
e.HostSlots = []HostSlot{}
|
||||
e.NumHosts = 0
|
||||
return nil
|
||||
}
|
||||
// If it's any other string, treat it as a single hostname
|
||||
// Any other non-empty string is a single hostname
|
||||
e.HostSlots = []HostSlot{{HostName: str, NumSlots: 1}}
|
||||
e.NumHosts = 1
|
||||
return nil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue