287 lines
7 KiB
Go
287 lines
7 KiB
Go
package utils
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
logger "xcecli/config"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// ParseInt parses a string to an integer
|
|
func ParseInt(s string) (int, error) {
|
|
return strconv.Atoi(s)
|
|
}
|
|
|
|
// ParseTim parse time string
|
|
// support input format:
|
|
// - "15:04" - only hour and minute, use current year, month and day
|
|
// - "01-02 15:04" - month and day with hour and minute, use current year
|
|
// - "03 15:04" - day with hour and minute, use current year and month
|
|
// - "2006-01-02 15:04" - full year, month and day with hour and minute
|
|
// output format: "2006-01-02 15:04"
|
|
func ParseTime(timeStr string) (string, error) {
|
|
// standard output format
|
|
outputFormat := "2006-01-02 15:04 CST"
|
|
|
|
// try formats
|
|
formats := []string{
|
|
"2006-01-02 15:04:05", // full format, strictest
|
|
"2006-01-02 15:04", // full format, strictest
|
|
"01-02 15:04", // month and day with hour and minute, use current year
|
|
"02 15:04", // day with hour and minute, use current year and month
|
|
"15:04", // only hour and minute, use current year, month and day
|
|
}
|
|
|
|
// get current time, for filling missing fields
|
|
now := time.Now()
|
|
|
|
// try each format
|
|
for _, format := range formats {
|
|
parsedTime, err := time.Parse(format, timeStr)
|
|
if err == nil {
|
|
// parse successfully, fill missing fields according to the format
|
|
resultTime := time.Date(
|
|
now.Year(),
|
|
now.Month(),
|
|
now.Day(),
|
|
parsedTime.Hour(),
|
|
parsedTime.Minute(),
|
|
0, 0, time.Local,
|
|
)
|
|
|
|
// adjust year, month and day according to the format
|
|
switch format {
|
|
case "2006-01-02 15:04:05":
|
|
// full format, use parsed year, month and day
|
|
resultTime = time.Date(
|
|
parsedTime.Year(),
|
|
parsedTime.Month(),
|
|
parsedTime.Day(),
|
|
parsedTime.Hour(),
|
|
parsedTime.Minute(),
|
|
parsedTime.Second(), 0, time.Local,
|
|
)
|
|
case "2006-01-02 15:04":
|
|
// full format, use parsed year, month and day
|
|
resultTime = time.Date(
|
|
parsedTime.Year(),
|
|
parsedTime.Month(),
|
|
parsedTime.Day(),
|
|
parsedTime.Hour(),
|
|
parsedTime.Minute(),
|
|
0, 0, time.Local,
|
|
)
|
|
case "01-02 15:04":
|
|
// month and day with hour and minute format, use current year and parsed month and day
|
|
resultTime = time.Date(
|
|
now.Year(),
|
|
parsedTime.Month(),
|
|
parsedTime.Day(),
|
|
parsedTime.Hour(),
|
|
parsedTime.Minute(),
|
|
0, 0, time.Local,
|
|
)
|
|
case "02 15:04":
|
|
// day with hour and minute format, use current year and month and parsed day
|
|
resultTime = time.Date(
|
|
now.Year(),
|
|
now.Month(),
|
|
parsedTime.Day(),
|
|
parsedTime.Hour(),
|
|
parsedTime.Minute(),
|
|
0, 0, time.Local,
|
|
)
|
|
case "15:04":
|
|
// hour and minute format, use current year, month and day
|
|
// already set, no need to change
|
|
}
|
|
|
|
// return standard format time string
|
|
return resultTime.Format(outputFormat), nil
|
|
}
|
|
}
|
|
|
|
// all formats failed
|
|
//return "", fmt.Errorf("invalid time format. Expected formats: HH:MM, DD HH:MM, MM-DD HH:MM, or YYYY-MM-DD HH:MM")
|
|
return "", errors.New("the time format can be [HH:MM, DD HH:MM, MM-DD HH:MM, YYYY-MM-DD HH:MM]")
|
|
}
|
|
|
|
// SystemLimits
|
|
type SystemLimits struct {
|
|
CPULimit int // CPU time limit (seconds)
|
|
FileLimit int // file descriptor limit
|
|
DataLimit int // data segment limit
|
|
StackLimit int // stack size limit
|
|
CoreLimit int // core file size limit
|
|
ProcessLimit int // process limit
|
|
ThreadLimit int // thread limit
|
|
MemLimit int // virtual memory limit
|
|
SwapLimit int // swap limit
|
|
}
|
|
|
|
// NewSystemLimits create a new SystemLimits instance
|
|
func NewSystemLimits() *SystemLimits {
|
|
return &SystemLimits{}
|
|
}
|
|
|
|
// define the command mapping
|
|
var limitCommands = map[string]string{
|
|
"cpu_limit": "ulimit -t",
|
|
"file_limit": "ulimit -n",
|
|
"data_limit": "ulimit -d",
|
|
"stack_limit": "ulimit -s",
|
|
"core_limit": "ulimit -c",
|
|
"process_limit": "ulimit -u",
|
|
"thread_limit": "cat /proc/sys/vm/max_map_count",
|
|
"mem_limit": "ulimit -v",
|
|
"swap_limit": "ulimit -l",
|
|
}
|
|
|
|
// getLimitValue get the value of the specified limit
|
|
func getLimitValue(key string) (int, error) {
|
|
cmd, ok := limitCommands[key]
|
|
if !ok {
|
|
return 0, nil
|
|
}
|
|
|
|
output, err := exec.Command("sh", "-c", cmd).Output()
|
|
fmt.Println("getLimitValue", key, string(output))
|
|
logger.Debug("getLimitValue", zap.String("key", key), zap.String("output", string(output)))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
value := strings.TrimSpace(string(output))
|
|
if value == "unlimited" {
|
|
return 0, nil
|
|
}
|
|
|
|
return strconv.Atoi(value)
|
|
}
|
|
|
|
// GetCPULimit get the CPU time limit
|
|
func (sl *SystemLimits) GetCPULimit() (int, error) {
|
|
if sl.CPULimit == 0 {
|
|
val, err := getLimitValue("cpu_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.CPULimit = val
|
|
}
|
|
return sl.CPULimit, nil
|
|
}
|
|
|
|
// GetFileLimit get the file descriptor limit
|
|
func (sl *SystemLimits) GetFileLimit() (int, error) {
|
|
if sl.FileLimit == 0 {
|
|
val, err := getLimitValue("file_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.FileLimit = val
|
|
}
|
|
return sl.FileLimit, nil
|
|
}
|
|
|
|
// GetDataLimit get the data segment limit
|
|
func (sl *SystemLimits) GetDataLimit() (int, error) {
|
|
if sl.DataLimit == 0 {
|
|
val, err := getLimitValue("data_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.DataLimit = val
|
|
}
|
|
return sl.DataLimit, nil
|
|
}
|
|
|
|
// GetStackLimit get the stack size limit
|
|
func (sl *SystemLimits) GetStackLimit() (int, error) {
|
|
if sl.StackLimit == 0 {
|
|
val, err := getLimitValue("stack_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.StackLimit = val
|
|
}
|
|
return sl.StackLimit, nil
|
|
}
|
|
|
|
// GetCoreLimit get the core file size limit
|
|
func (sl *SystemLimits) GetCoreLimit() (int, error) {
|
|
if sl.CoreLimit == 0 {
|
|
val, err := getLimitValue("core_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.CoreLimit = val
|
|
}
|
|
return sl.CoreLimit, nil
|
|
}
|
|
|
|
// GetProcessLimit get the process limit
|
|
func (sl *SystemLimits) GetProcessLimit() (int, error) {
|
|
if sl.ProcessLimit == 0 {
|
|
val, err := getLimitValue("process_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.ProcessLimit = val
|
|
}
|
|
return sl.ProcessLimit, nil
|
|
}
|
|
|
|
// GetThreadLimit get the thread limit
|
|
func (sl *SystemLimits) GetThreadLimit() (int, error) {
|
|
if sl.ThreadLimit == 0 {
|
|
val, err := getLimitValue("thread_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.ThreadLimit = val
|
|
}
|
|
return sl.ThreadLimit, nil
|
|
}
|
|
|
|
// GetMemLimit get the virtual memory limit
|
|
func (sl *SystemLimits) GetMemLimit() (int, error) {
|
|
if sl.MemLimit == 0 {
|
|
val, err := getLimitValue("mem_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.MemLimit = val
|
|
}
|
|
return sl.MemLimit, nil
|
|
}
|
|
|
|
// GetSwapLimit get the swap limit
|
|
func (sl *SystemLimits) GetSwapLimit() (int, error) {
|
|
if sl.SwapLimit == 0 {
|
|
val, err := getLimitValue("swap_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
sl.SwapLimit = val
|
|
}
|
|
return sl.SwapLimit, nil
|
|
}
|
|
|
|
// GetSystemEnv get the system environment variables
|
|
// return format: ["VAR1=value1", "VAR2=value2", ...]
|
|
func GetSystemEnv() []string {
|
|
// get all environment variables
|
|
envVars := os.Environ()
|
|
|
|
// sort the environment variables to ensure the consistency of the output
|
|
sort.Strings(envVars)
|
|
|
|
return envVars
|
|
}
|