From e8edb1240f8488485bff5c8fc3be405353ef7a74 Mon Sep 17 00:00:00 2001 From: Cyril Galibern Date: Wed, 21 Jan 2026 15:15:00 +0100 Subject: [PATCH] [worker, api] Migrate instance action begin and end timestamp to RFC3339Nano format (API 1.0.11) - Replace `ParseTimeWithTimezone` with `time.Parse` using RFC3339Nano format for `Begin` and `End` timestamps in worker. - Remove unused `ParseTimeWithTimezone` utility from `cdb`. - Add RFC3339Nano format descriptions for `Begin` and `End` fields in API schema. - Update Swagger spec and bump API version to 1.0.11. --- api/api.yaml | 4 +- api/codegen_server_gen.go | 69 +++++++++++++++--------------- api/codegen_type_gen.go | 24 ++++++----- cdb/util.go | 34 --------------- worker/job_feed_instance_action.go | 6 +-- 5 files changed, 55 insertions(+), 82 deletions(-) diff --git a/api/api.yaml b/api/api.yaml index c1f46a0..30d3647 100644 --- a/api/api.yaml +++ b/api/api.yaml @@ -5,7 +5,7 @@ servers: info: title: opensvc collector api - version: 1.0.10 + version: 1.0.11 paths: /feed/daemon/ping: @@ -382,6 +382,7 @@ components: description: the opensvc client data version begin: type: string + description: begin action timestamp in RFC3339Nano format cron: type: boolean session_uuid: @@ -394,6 +395,7 @@ components: type: string end: type: string + description: end action timestamp in RFC3339Nano format status_log: type: string status: diff --git a/api/codegen_server_gen.go b/api/codegen_server_gen.go index 7026085..667efd0 100644 --- a/api/codegen_server_gen.go +++ b/api/codegen_server_gen.go @@ -249,40 +249,41 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+xaW28buRX+KwTbhwSYlWQ7bQH1ydkkXbfF2o2c9sE2BIpzNOJmhpyQHMVKoP9e8DYX", - "iaOL1woWSJ4SDznn8p3vHB6e0VdMRVEKDlwrPP6KSyJJARqk/Yvx/1QgV5MVp+5PPMafzBOcYE4KwGOs", - "zFqCFV1AQcwmvSrN85kQORCO1+t1giWoUnAFVuir0cj8QwXXwLX5LynLnFGimeDD35Tg5lkj8M8S5niM", - "/zRsLB26VTW8kWKWQ+G0pKCoZKURg8f4NUnRe/hUgdJ4neBXo7NvofUDJ5VeCMm+QOrUXnwLte+EnLE0", - "BW50/uXbAHzFNUhOcjQBuQSJ3koppNH/DiB9Q6AQ/Ibx7JJSKDWkR5lUSlGC1MwxRsx+A6qnn5leiEpP", - "qeBzlpmFrkE5UxqJOXLbkSGoQnpBNJLwqWISFLq5ntyioaAXwzlAOnQ7h15ggpmGQm0LbgnESSC40pLx", - "zPjrHxApyQqvmwfutRh0qUUHKU10pZBmBShNilKhzyzP0QyQhLkEtYAUzYVEXKTQBXZi3/wB7T5od+G5", - "DlXLmnVJnYBNgEj9fMs4IrOlLYvBtT3mJ3gGGYvLorKjpK6eCQaeRt8oiV5EFxQoxQSfVhWLv+mw2bE0", - "zUUWXe4VuQSpPEzdcOgFIFECV0uKaM6Aa5QSTVB4YSvm9rSwlErx+M55mYQoNIoClh65Da99bLzBDsMg", - "JBfZnOWGbR6Hhy1WJZ4N/vhop1mXHD14bPhgd8W0vGHq47bQNI59D/KFSCGPrvjU7uWJhKyP2Yp9AbMw", - "F7IgGo8x4/rivAkW4xoysMW+UtA2rLWyBJ4KuR8eG6G2sV6/l10LCr4mBqEYnFdcacIpvAclKknhis/F", - "NrzMP62ztrv8EVZq93I8AUhewX5fzethc8yFzYIhD+GXtAhaww+R2UsILUqRi2y1X6MPk4VyVyQmdaXZ", - "oDjR7V6xebHXtlMXGGtRoybm1K8iBZOxO/ypSbOrpbJZf8DZluBr+7+f6zN542Qqy/hRIorCdwJba6ks", - "p/b027WojjvUgC+j++Y5PE4L8hivDm61cxpurmoiM9DxDYXgTAsJ6VT6bJ9SUfGe3ULSBSgtiYbjzlJJ", - "Prd6oroczlY62q4oKko4Dr0jky5GzBuhdLfn3iZLHdd4X0fzSmnwnVFvs9bedWDLFir7AbrbveUzNYwn", - "rBsO0Ma93bWjG6K+skgXhGcb6Rf1XkjEfIk9BIT+cithyUSlplWZEg3plOgOz83Dn8z1JKblKe+cLBy+", - "fgcE90TDX2q36zhowvJt6y7RoioI/0kCScksBwSPZU64vWIhVQJlc0aRFkgvmEKC0kpK4BQMvfUC7nnp", - "NA7uebRs1Hzoqr1dAPrl9vYm3GaoybsXd+/f/fy384uzhwRNwPap6K8vUQYcTH1L0WzldArJMsaRcrdz", - "c++JW4dixrWKp2Y6hxgmaiGkTjahUVVRELnaEI6M3AFCVxpNfrn+8O839/zX61vk4oXmUhRtw7ToNzNB", - "8Gj68XtuXCorWQoFymzKBSU5++Ki8gIG2SBBlWI8M6+a5n8JyF+T7zmHTGhm9/4dKQAUgfVi8OplNGSb", - "5HO0qQMZMItxryT0I8kgcpxLGj+DbKbn+ZGZ5sZz0d4+23Ew7W699pREV5OblLUueclOcQwRtVI6lowt", - "pA7qq8L+g1qrllNdra0FeCRFaaiPR4PR4GwvDfpLjr2V00oyvZoYa52qGVGMXlau9bBe2Ku/edroWmhd", - "utEBkSDDbvfXu8CEf/7vNsxgrQi7uiljvU7qy4/PaVyXXJHnQLWQiJSsFcMxPjOuj+xBXgI3q2N8MRgN", - "Rti1TdaTYSqoGtYbvmLftxlgbYpdpXiM/wF68plkmTWtMxI+P3JiuXcKdP2v1sw3Rppa/dBsaga1+/Ze", - "tAasu/eaTZZ6JFO2fatmOaP4wTxzIzI3qhqWoWETSm+X2fduclV3SX2jQ1umunhH+kJHWFD6tUhXzzck", - "3la07iaHlhWst4J+vh/FnlnyOsHno1fbaBVM2YLfRSnM/BI/pPTA+1WmUG1oO1Px+K6To3cP6+RrJw/v", - "HtYPTYBJZoDcjm9zuj8hwnvDOglHzukD61U9f2g3ptk2G0eHZOPoD5Plz0aa0NcPm8FznDavwXR3hCO3", - "0ZKcoIwtgYerlKnPOwgUpjSXYbh6Cgp54YeT5hm1bs5vIweFB2/mwPyeGZjgsorQ7C1Pn0ayKsKxt3YO", - "/4egWZQGYJz9UYbaZager4XWMV6NPthhABISUQnmf0EACgKQEXBANepM709Dlqiqp1In7qhpzA2jtj5A", - "nihM+5qMiRaymbCcD86aAPk2KCWaDA6IT91wtH8qchcHvNkybP+UxLh0yrge06iMdkTUI6PsoBmpilJQ", - "al7l+Qq9UCtOF1JwUamXrh093y+p+Qwdqgx6QTYlfb9Fx/TowzR8FD2szthZtHlHITeorxx3dzA5fMg5", - "UXVpvhM9taT0+XTqamLxb41johEwKCK3ydhIxRLkagfaEyfvNFh7Y58KdHCDaLLnpzffb1J2f8hzeGL6", - "9vDQpOx86zwNWToqfvdx/60yszWQ9FO1rkESdCU5IiVrfSzZGrz9t176XYO3XfAG7b3juCeNzSgpyYzl", - "zM5nH9YOVbkMXUclczzGQ0Ev8Pph/f8AAAD//36dzP/OKgAA", + "H4sIAAAAAAAC/+xaW3PbuhH+Kxi0D8kMjyRbaTtVn5yLe9x2Ytdy2gfbo4HAFYUTEmAAULGS0X8/gwtv", + "IijJjpU5M8lTYgDcy7ffLpZLfcVUZLngwLXCk684J5JkoEHavxj/bwFyPV1z6v7EE/zJrOAIc5IBnmBl", + "9iKs6BIyYg7pdW7W50KkQDjebDYRlqBywRVYoa9GI/MPFVwD1+a/JM9TRolmgg9/U4KbtVrgnyUs8AT/", + "aVhbOnS7anglxTyFzGmJQVHJciMGT/BrEqNr+FSA0ngT4Vejk++h9QMnhV4Kyb5A7NSOv4facyHnLI6B", + "G51/+T4AX3ANkpMUTUGuQKJ3Ugpp9J8DxG8JZIJfMZ6cUQq5hvhRJuVS5CA1c4wR89+A6tlnppei0DMq", + "+IIlZqNtUMqURmKB3HFkCKqQXhKNJHwqmASFri6nN2go6Hi4AIiH7uTQC4ww05CpruCGQByVBFdaMp4Y", + "f/0CkZKs8aZecI+FoIstOkhpoguFNMtAaZLlCn1maYrmgCQsJKglxGghJOIihjawU/vkT2j3QbsLz01Z", + "taxZZ9QJ2AaIVOsd44hMVrYslq7tMT/Cc0gY74Jgl5HTVLMBMY6uz9+Mx+O/vydcGMszokMoUdmysCq9", + "EQYed9UBj79BWU70MuisAqWY4LOiYHH4gI3Jjq1ZKpLgdq/IFUjlw9P2US8BiRy4WlFEUwZco5hogsoH", + "Oo7ZW8pSOcaTW+dlVEa/VlTG0IO+5bXnhDfYwV8KSUWyYKlhucfhvsPmyLPQX1vN9G6TsgePLR/sqZCW", + "t0x97AqNw9j3IJ+JGNLgji8pvTyRkPRllGJfwGx49k0w43p8WgeLcQ0J2EumUNA0rLGzAh4LuR8eG6Gm", + "sV6/l10JKn2NDEIhOC+40oRTuAYlCknhgi9EF17mV6tq0d7+CGu1ezucACQtYL+v5vHycMiF7UIlD+GX", + "tAhaww+R2UsILXKRimS9X6MPk4VyVySmVaXZojjRzR61frDXtmMXGGtRrSbk1HsRg8nYHf5UpNnVytms", + "P+BOjfCl/d+bqhfYuhHzPAgVFVnmO5DOXizzmb11d22qx12mwFfBc4sUHmYZeQhXB7fL+I5dTWQCOnwg", + "E5xpISGeSZ/tMyoK3nNaSLoEpSXRYc/7ayT53OjFqnI4X+tgm6SoyOFx6D0y6ULEvBJKt3v9LlmquIb7", + "SZoWSoPvyHqbxOapA1vFsrIfoLvZ0z5To3rEuuEArd3bXTvaIeori3RJeLKVfkHvhUTMl9hDQOgvtxJW", + "TBRqVuQx0RDPiG7x3Cz+YnrTkJanPHO0cPj6XSK4Jxr+Zbpbx0ETlnatO0PLIiP8FwkkJvMUEDzkKeH2", + "1Q6pHChbMIq0QHrJFBKUFlICp2DorZdwx3OncXDHg2Wj4kNb7c0S0K83N1flWxQ1effi9vr8zd9Oxyf3", + "EZqCe33460uUAAdT32I0XzudQjLzOqPcVMC8b4WtQyHjGsVTM51CCBO1FFJH29CoIsuIXG8JR0buAKEL", + "jaa/Xn74z9s7/v7yBrl4oYUUWdMwLfrNjBA8mH78jhuX8kLmQoEyh1JBScq+uKi8gEEyiFChGE/Mo6b5", + "XwHyr+d3nEMiNLNn/4EUAArAOh68ehkM2Tb5HG2qQJaYhbiXE/qRJBC4ziUN30E209P0kZnmxoLB3j7Z", + "cTHtbr32lERXk+uUtS55yU5xCBG1VjqUjA2kDuqryvMHtVYNp9paGxvwQLLcUB+PBqPByV4a9Jcc+1ZO", + "C8n0emqsdarmRDF6VrjWw3phpwZmtda11Dp3IwsiQZan3V/nJRP+9f+bcvZrRdjdbRmbTVS9/PicxlXJ", + "FWkKVAuJSM4aMZzgE+P6ib3Ic+Bmd4LHg9FghF3bZD0ZxoKqYXXgK/Z9mwHWpthFjCf4n6Cnn0mSWNNa", + "o+jTR05K906fLv/dmDWHSFOpH5pD9YB439lxY7C7+6w5ZKlHEmXbt2KeMorvzZobzbkR2TAvGzahdLfM", + "XruJWdUl9Y0sbZlq4x3oCx1hQenXIl4/33C6q2jTTg4tC9h0gn66H8WeGfYmwqejV120MqZswW+jVM4a", + "Iz8c9cD7XaZQZWgzU/HktpWjt/eb6GsrD2/vN/d1gEligOzGt77dnxDhvWGdllfO8QPrVT1/aLem6DYb", + "R4dk4+gPk+XPRpqyrx/WA+8wbV67YXU1rzYkJyhhK+Dlq5SpzzsIVE5pzsrh6jEo5IUfTppn1Lo9vw1c", + "FB68cvL/AzMwwnkRoNk7Hj+NZEWAY+/sHP4PQbMgDdwXmZ9lqFGGqvFa2TqGq9EHOwxAQiIqwfyvFIBK", + "AcgIOKAatab3xyFLUNVTqRN21DTmhlGdD59HCtO+JmOqhawnLKeDkzpAvg2KiSaDA+JTNRzNn6jchgGv", + "jwybP2ExLh0zro9pVEY7IuqRUXbQjFRBKSi1KNJ0jV6oNadLKbgo1EvXjp7ul1R//i6rDHpBtiX9uEXH", + "9OjDuPwoelidsbNo84xCblBfOO7uYHL5IedI1aX+TvTUktLn07GricW/MY4JRsCgiNwhYyMVK5DrHWhP", + "nbzjYO2NfSrQpRtEkz0/+flxk7L9A6LDE9O3h4cmZetb53HI0lLxzdf998rMxkDST9XaBknQheSI5Kzx", + "saQzePtftfVNg7dd8Jbae8dxTxqbUZKTOUuZnc/ebxyqclV2HYVM8QQPBR3jzf3m9wAAAP//E+1rfEYr", + "AAA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/codegen_type_gen.go b/api/codegen_type_gen.go index 89c9d8e..66650b2 100644 --- a/api/codegen_type_gen.go +++ b/api/codegen_type_gen.go @@ -14,16 +14,20 @@ const ( // Action defines model for Action. type Action struct { - Action string `json:"action"` - Argv []string `json:"argv"` - Begin string `json:"begin"` - Cron bool `json:"cron"` - End string `json:"end"` - Path string `json:"path"` - SessionUuid string `json:"session_uuid"` - Status string `json:"status"` - StatusLog *string `json:"status_log,omitempty"` - Uuid string `json:"uuid"` + Action string `json:"action"` + Argv []string `json:"argv"` + + // Begin begin action timestamp in RFC3339Nano format + Begin string `json:"begin"` + Cron bool `json:"cron"` + + // End end action timestamp in RFC3339Nano format + End string `json:"end"` + Path string `json:"path"` + SessionUuid string `json:"session_uuid"` + Status string `json:"status"` + StatusLog *string `json:"status_log,omitempty"` + Uuid string `json:"uuid"` // Version the opensvc client data version Version string `json:"version"` diff --git a/cdb/util.go b/cdb/util.go index 9de5ba7..9038bcf 100644 --- a/cdb/util.go +++ b/cdb/util.go @@ -3,8 +3,6 @@ package cdb import ( "fmt" "log/slog" - "strconv" - "strings" "time" ) @@ -15,35 +13,3 @@ func logDuration(s string, begin time.Time) { func logDurationInfo(s string, begin time.Time) { slog.Info(fmt.Sprintf("STAT: %s elapse: %s", s, time.Since(begin))) } - -// Todo : to move elsewhere... -// Tz can be either a timezone name (ex: "Europe/Paris") or a UTC offset (ex: "+01:00") -func ParseTimeWithTimezone(dateStr, tzStr string) (time.Time, error) { - const timeFormat = "2006-01-02 15:04:05" - - // Named Tz - if loc, err := time.LoadLocation(tzStr); err == nil { - return time.ParseInLocation(timeFormat, dateStr, loc) - } - - // Offset Tz - tzStr = strings.TrimSpace(tzStr) - if tzStr != "" && (tzStr[0] == '+' || tzStr[0] == '-') { - parts := strings.Split(tzStr[1:], ":") - if len(parts) >= 2 { - hours, errH := strconv.Atoi(parts[0]) - minutes, errM := strconv.Atoi(parts[1]) - if errH == nil && errM == nil { - offset := hours*3600 + minutes*60 - if tzStr[0] == '-' { - offset = -offset - } - loc := time.FixedZone(tzStr, offset) - return time.ParseInLocation(timeFormat, dateStr, loc) - } - } - } - - // Fallback - return time.Parse(timeFormat, dateStr) -} diff --git a/worker/job_feed_instance_action.go b/worker/job_feed_instance_action.go index 4bc78be..2228fa9 100644 --- a/worker/job_feed_instance_action.go +++ b/worker/job_feed_instance_action.go @@ -119,7 +119,7 @@ func (d *jobFeedInstanceAction) updateDB(ctx context.Context) error { if err != nil { return fmt.Errorf("invalid node ID UUID: %w", err) } - beginTime, err := cdb.ParseTimeWithTimezone(d.data.Begin, d.node.Tz) + beginTime, err := time.Parse(time.RFC3339Nano, d.data.Begin) if err != nil { return fmt.Errorf("invalid begin time format: %w", err) } @@ -132,8 +132,8 @@ func (d *jobFeedInstanceAction) updateDB(ctx context.Context) error { } if d.data.End != "" { - // field End is present, process as action end - endTime, err := cdb.ParseTimeWithTimezone(d.data.End, d.node.Tz) + // field End is present, process as an end action + endTime, err := time.Parse(time.RFC3339Nano, d.data.End) if err != nil { return fmt.Errorf("invalid end time format: %w", err) }