1

From

kubectl get pods -o wide

The output looks similar to

some-pod-name-with-numbers-123             1/1     Running   0          6d4h      192.168.0.23   node-name-abcdeft-host.domain   <none>           <none>
some-pod-name-with-numbers-1234            1/1     Running   0          4h38m      192.168.0.24   node-name-abcdeft-host.domain   <none>           <none>
some-pod-name-with-numbers-1235            1/1     Running   0          2m38s      192.168.0.25   node-name-abcdeft-host.domain   <none>           <none>

I get time elapsed for the pods in a format like: 4d3h15m3s (it looks like the most is two consecutive units, days and hours, hours minutes, minutes and seconds, but I can't guarantee that.

I need to check to see if a pod has been around longer than some threshold X.

I tried to find some way of extracting this field as seconds via kubectl, no luck there. I searched the internet for a pre-canned solution, could not find one.

I'm thinking that I can use awk to convert the string into a numeric seconds so I can then compare if it is > $X, this value is configurable.

2
  • That's tricky since 6d, for example, might include a DST transition and so you might have a day in there that's 23 or 25 instead of 24 hours. There's also leap seconds as less of an issue. Should DST transitions be ignored or, if not, how should they be handled? Or does 6d in your file really mean 6 * 24 hour periods rather than 6 calendar days?
    – Ed Morton
    Aug 14, 2020 at 19:20
  • that's a good point, given this is a notification alert type of system, I'm going to say that we don't need to be absolutely correct and account for leap seconds, daylight savings, or leap days. And take simpler logic instead. Aug 20, 2020 at 0:03

5 Answers 5

2

You don't need to fork an external process just to get the kubernetes elapsed time in seconds. The below GNU awk code has a user defined function fx() which shall do that conversion and from there on you can use it for your comparison purposes.

kubectl get pods -o wide |
awk '
BEGIN {
    a["d"] = 24*(\
    a["h"] = 60*(\
    a["m"] = 60*(\
    a["s"] = 1)));
  }
  {
    print fx($5); # kubernetes time elapsed in seconds 
  }
  function fx(ktym,    f,u,n,t,i) {
    n = split(ktym, f, /[dhms]/, u)
    t = 0
    for (i=1; i<n; i++) {
      t += f[i] * a[u[i]] 
    }
    return t
  }
'

In case you want to go by a user defined function in bash then we can do the following. We have a function fx() which needs one arg, which is the time elapsed in kubernetes format abd it will output a time in seconds.

fx() {
echo "$1" |
sed -Ee '
  s/[1-9][0-9]*[dhms]/&+ /g
  :a;s/[+]([^+].*)/\1+/;ta
  s/.$//
  :loop
    s/d/ 24h*/
    s/h/ 60m*/
    s/m/ 60s*/
    s/s//
  t loop
  s/.*/echo "&" | dc -e "?p"/e
'
}

We are dynamically generating a code for the Linux utility called dc or the desk calculator in the RPN (Reverse Polish Notation).

2
  • Although I already implemented using the sed/awk one-liner, the solutions here are cleaner. When I go back to enhance it, i'll probably use the awk function. Though the unit based array confuses me a little, somehow you defined the array to multiply the units down to seconds. Is there any references or key words to search to find out more about how this works. Aug 20, 2020 at 0:00
  • 1
    The units array are nothing but chained assignments. For ex, a=b=5. This reads as : first b gets assigned the number 5 and then the result of this assignment, which is 5 is then assigned to a. The result of this assignment, which too is 5, is thrown away. Aug 20, 2020 at 16:56
2

In case anyone was looking for a python fucntion like myself, here it is:

def kubctle_dur_to_secs(kubectl_time:str) -> int:
    total_time = 0
    for t_char, sec_in_t in zip( ('d', 'h', 'm', 's'), (86400, 3600, 60, 1) ):
        if t_char in kubectl_time:
            t_index = kubectl_time.find(t_char)
            total_time += int(kubectl_time[:t_index])*sec_in_t
            kubectl_time = kubectl_time[t_index+1:]
    return total_time
1

Spent some time on this, figured out the quickest way to get this was to tokenize the time with a sed replace.

sed -e 's/\([smhd]\)/\1 /g' | awk '{ b=0; for(i=1; i<=NF; ++i) { s=substr($i,1,length($i)-1); u=substr($i,length($i)); if (u=="s") b+=s; else if (u=="m") b+=s*60; else if (u=="h") b+=s*60*60; else if (u=="d") b+=s*60*60*24; else u=""; } if (b>1) printf "%d", b}'

So far I've only observed d,h,m,s units being used in this field, even for pods that are >100days old.

The sed command basically split every unit with a space.
Awk then loop through the fields and split the string into the unit (u) and the numeric string (s).
The chained if-elseif-else statements simply converts the values into seconds based on the unit and adds it to a running total of the time in seconds is kept.

I've placed this command in a script "kube_elapsed_to_seconds" and planning to use another awk on the outside and the system command to run this script on this field.

kubectl get pods -o wide | awk '{ system("echo " $5 " | kube_elapased_to_seconds"); print $0 }'

I'm open to suggestions on how to make this command easier to read or interact better with other non-time related fields like podname and status that might be present.

1

convert the string into a numeric seconds so I can then compare if it is > 3600

3600 seconds is an hour, so you just need to check if we have at least one hour mentioned in the output:

echo 4d3h15m3s | grep -q '[dh]' && echo At least 3600 seconds

To match against the fifth field in the actual output use awk, but this requires that none of the preceding field values contains a space

kubectl get pods -o wide | awk '{ exit ($5 ~ /[dh]/) ? 0 : 1 }' && echo At least 3600 seconds

If you need non-boundary comparisons, you will need to convert the timespec into a number of seconds. Here's a perl version

perl -e '
    %t=(d => 3600*24, h => 3600, m => 60, s => 1);    # Seconds per unit
    @a=split(/([dhms])/, shift);                      # Tokenise string argument
    for ($i = 0; $i < scalar @a; $i += 2) {
        $s += $a[$i] * $t{$a[$i+1]}                   # Add N lots of seconds-per-unit
    };
    print "$s\n"
' 4d3h15m3s
2
  • that was just one example, i may want 5 minutes, or 3 days or 2 minutes and 36 seconds. I'll edit the question to make that clear. I do like how your command is much shorter. It might run into some difficulty if a pod name has the letter d or h in it. Aug 12, 2020 at 21:12
  • Your sample output only had the time period. I don't run Kubernetes so I'm dependent on what you say the command outputs
    – roaima
    Aug 12, 2020 at 22:01
0

For a command that understands those 4d3h15m3s, see dateutils's dadd:

$ TZ=UTC0 dateutils.dadd -f%s 1970-01-01T00:00:00 4d3h15m3s
357303

Here adding that duration to the start of Unix epoch time, and outputting the result as Unix epoch time, in a timezone with 0 offset to UTC.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.