The little things give you away... A collection of various small helper stuff
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

168 lines
4.5 KiB

  1. #!/bin/bash
  2. columns=("JOBID" "URL" "USER" "PIPENICK" "QUEUED" "STARTED" "LAST ACTIVE") # Duplicated in Python code!
  3. function valid_column {
  4. local candidate="$1"
  5. local column
  6. for column in "${columns[@]}"
  7. do
  8. [[ "${candidate}" == "${column}" ]] && return 0
  9. done
  10. return 1
  11. }
  12. sortcolumns=()
  13. filter=
  14. nocolours=
  15. notable=
  16. while [[ $# -gt 0 ]]
  17. do
  18. if [[ "$1" == "--help" || "$1" == "-h" ]]
  19. then
  20. echo "Usage: archivebot-jobs [--help|-h] [(--sort|-s) COLUMN] [(--filter|-f) COLUMN=VALUE] [--no-colours|--no-colors] [--no-table]" >&2
  21. echo "Prints a table of current AB jobs" >&2
  22. echo "Options:" >&2
  23. echo " --help, -h: Show this message and exit." >&2
  24. echo " --sort COLUMN: Sort the table by a column. This can be used multiple times to refine the sorting." >&2
  25. echo " --filter COLUMN=VALUE: Filter the table for rows where a COLUMN has a certain VALUE. If specified multiple times, only the last value is used." >&2
  26. echo " --no-colours: Don't colourise the last activity column if it's been a while." >&2
  27. echo " --no-table: Raw output without feeding through column(1); columns are separated by tabs." >&2
  28. echo "The COLUMNs are the names of each column, printed in capital letters in the first line of the output." >&2
  29. exit 0
  30. elif [[ "$1" == "--sort" || "$1" == "-s" ]]
  31. then
  32. sortcolumns+=("$2")
  33. shift
  34. elif [[ "$1" == "--filter" || "$1" == "-f" ]]
  35. then
  36. filter="$2"
  37. shift
  38. elif [[ "$1" == "--no-colours" || "$1" == "--no-colors" ]]
  39. then
  40. nocolours=1
  41. elif [[ "$1" == "--no-table" ]]
  42. then
  43. notable=1
  44. else
  45. echo "Unknown option: $1" >&2
  46. exit 1
  47. fi
  48. shift
  49. done
  50. # Validate sortcolumns and filter
  51. if [[ "${filter}" ]]
  52. then
  53. if [[ ! "${filter}" == *=* ]]
  54. then
  55. echo "Invalid filter: ${filter}" >&2
  56. exit 1
  57. fi
  58. if [[ "${filter}" == *$'\n'* ]]
  59. then
  60. echo "Invalid filter: newlines not allowed" >&2
  61. exit 1
  62. fi
  63. column="${filter%%=*}"
  64. if ! valid_column "${column}"
  65. then
  66. echo "Invalid filter column: ${column}" >&2
  67. exit 1
  68. fi
  69. fi
  70. if [[ ${#sortcolumns[@]} -gt 0 ]]
  71. then
  72. for column in "${sortcolumns[@]}"
  73. do
  74. if ! valid_column "${column}"
  75. then
  76. echo "Invalid sort column: ${column}" >&2
  77. exit 1
  78. fi
  79. done
  80. else
  81. # Default sort order
  82. sortcolumns+=("JOBID")
  83. fi
  84. if [[ "${notable}" ]]
  85. then
  86. column=("cat")
  87. else
  88. column=("column" "-t" $'-s\t')
  89. fi
  90. jobdata="$(curl -s -H "Accept: application/json" "http://dashboard.at.ninjawedding.org/logs/recent?count=1" 2>/dev/null)"
  91. pipelinedata="$(curl -s -H "Accept: application/json" "http://dashboard.at.ninjawedding.org/pipelines" 2>/dev/null)"
  92. if [[ -z "${jobdata}" || -z "${pipelinedata}" ]]
  93. then
  94. echo "Error retrieving job or pipeline data" >&2
  95. exit 1
  96. fi
  97. { echo "${jobdata}"; echo "${pipelinedata}"; echo "${filter}"; } | python3 -c \
  98. '
  99. if True: # For sensible indentation
  100. import json
  101. import sys
  102. import time
  103. def time_ago(diff):
  104. if diff <= 0:
  105. return "now"
  106. elif diff < 60:
  107. return "<1 min ago"
  108. elif diff < 86400:
  109. return (f"{diff // 3600:.0f}h " if diff >= 3600 else "") + f"{(diff % 3600) // 60:.0f}mn ago"
  110. else:
  111. return f"{diff // 86400:.0f}d {(diff % 86400) // 3600:.0f}h ago"
  112. def coloured_time_ago(diff):
  113. if diff >= 300:
  114. return "\x1b[0;31m" + time_ago(diff) + "\x1b[0m"
  115. else:
  116. return time_ago(diff)
  117. jobdata = json.loads(sys.stdin.readline())
  118. pipelinedata = json.loads(sys.stdin.readline())
  119. filter = sys.stdin.readline().strip()
  120. pipelines = {p["id"]: p["nickname"] for p in pipelinedata["pipelines"]}
  121. columns = ("JOBID", "URL", "USER", "PIPENICK", "QUEUED", "STARTED", "LAST ACTIVE") # Duplicated in Bash code!
  122. jobs = []
  123. currentTime = time.time()
  124. for j in jobdata:
  125. jobs.append([
  126. j["job_data"]["ident"],
  127. j["job_data"]["url"],
  128. j["job_data"]["started_by"],
  129. pipelines[j["job_data"]["pipeline_id"]] if j["job_data"]["pipeline_id"] in pipelines else "unknown",
  130. currentTime - j["job_data"]["queued_at"],
  131. currentTime - j["job_data"]["started_at"],
  132. currentTime - j["ts"],
  133. ])
  134. # Filter
  135. if filter:
  136. column, value = filter.split("=", 1)
  137. assert column in columns
  138. columnIdx = columns.index(column)
  139. jobs = [job for job in jobs if job[columnIdx] == value]
  140. # Sort
  141. sortColumns = ('"$(printf "'%s', " "${sortcolumns[@]}")"')
  142. assert all(column in columns for column in sortColumns)
  143. sortColumnIdxs = tuple(columns.index(column) for column in sortColumns)
  144. jobs = sorted(jobs, key = lambda job: tuple(job[columnIdx] for columnIdx in sortColumnIdxs))
  145. # Print
  146. print("\t".join(columns))
  147. for job in jobs:
  148. job[4] = time_ago(job[4])
  149. job[5] = time_ago(job[5])
  150. job[6] = (coloured_time_ago if not "'${nocolours}'" else time_ago)(job[6])
  151. print("\t".join(job))
  152. ' | "${column[@]}"