Kubernetes: Display Pods by age in ascending order - sorting

I use below command to sort the pods by age
kubectl get pods --sort-by={metadata.creationTimestamp}
It shows up pods in descending order. How can we select sorting order like ascending?

Not supported by kubectl or the kube-apiserver as of this writing (AFAIK), but a workaround would be:
$ kubectl get pods --sort-by=.metadata.creationTimestamp | tail -n +2 | tac
or if tac is not available (MacOS X):
$ kubectl get pods --sort-by=.metadata.creationTimestamp | tail -n +2 | tail -r
If you want the header:
$ echo 'NAME READY STATUS RESTARTS AGE' | \
kubectl get pods --sort-by=.metadata.creationTimestamp | tail -n +2 | tac
You might just have to adjust the tabs on the header accordingly. Or if you don't want to use tail -n +2 you can use --no-headers. For example:
$ kubectl get pods --sort-by=.metadata.creationTimestamp --no-headers | tac

It Is Quite EASY: Once you have used --no-headers option, the HEADER will not be part of output (ascending ordered-listing of pods) and you can simply reverse sort the outcome of the command.
Here's the complete command to get exactly what is expected:
kubectl get po --sort-by={metadata.creationTimestamp} --no-headers | tac

Sorted kubectl output and awk provide the table view with a header. Installation of extra tools is not needed.
# kubectl get pods --sort-by=.status.startTime | awk 'NR == 1; NR > 1 {print $0 | "tac"}'
An approach with JSON processor offered by paulogrell works also but could require more effort: for some Linux distributions you'll need to download and compile jq from source code. As for the jq command line I'd suggest to add the "name" to the map parameters and sort by "timestamp":
# kubectl get pods -o json | jq '.items | group_by(.metadata.creationTimestamp) | map({"name": .[0].metadata.name, "timestamp": .[0].metadata.creationTimestamp, "count": length}) | sort_by(.timestamp)'

I believe the Kubernetes API doesnt support this option yet, but as a workaround you can use a JSON processor (jq) to adjust its output.
Ascending
kubectl get pods -o json | jq '.items | group_by(.metadata.creationTimestamp) | map({"timestamp": .[0].metadata.creationTimestamp, "count": length}) | sort_by(.count)'
Descending
kubectl get pods -o json | jq '.items | group_by(.metadata.creationTimestamp) | map({"timestamp": .[0].metadata.creationTimestamp, "count": length}) | sort_by(.count) | reverse'
Hope this helps

A simpler version that works on MacOS and retains arbitrary headers:
kubectl get node --sort-by=.metadata.creationTimestamp | { read -r headers; echo "$headers"; tail -r; }

If you are looking for a way to find the latest pod, try:
kubectl get pod --selector='app=my-app-name' \
--sort-by='.metadata.creationTimestamp' \
-o=jsonpath='{.items[-1].metadata.name}'

Related

Get logs from all pods in namespace using xargs

Is there anyway to get all logs from pods in a specific namespace running a dynamic command like a combination of awk and xargs?
kubectl get pods | grep Running | awk '{print $1}' | xargs kubectl logs | grep value
I have tried the command above but it's failing like kubectl logs is missing pod name:
error: expected 'logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]'.
POD or TYPE/NAME is a required argument for the logs command
See 'kubectl logs -h' for help and examples
Do you have any suggestion about how get all logs from Running pods?
Think about what your pipeline is doing:
The kubectl logs command takes as an argument a single pod name, but through your use of xargs you're passing it multiple pod names. Make liberal use of the echo command to debug your pipelines; if I have these pods in my current namespace:
$ kubectl get pods -o custom-columns=name:.metadata.name
name
c069609c6193930cd1182e1936d8f0aebf72bc22265099c6a4af791cd2zkt8r
catalog-operator-6b8c45596c-262w9
olm-operator-56cf65dbf9-qwkjh
operatorhubio-catalog-48kgv
packageserver-54878d5cbb-flv2z
packageserver-54878d5cbb-t9tgr
Then running this command:
kubectl get pods | grep Running | awk '{print $1}' | xargs echo kubectl logs
Produces:
kubectl logs catalog-operator-6b8c45596c-262w9 olm-operator-56cf65dbf9-qwkjh operatorhubio-catalog-48kgv packageserver-54878d5cbb-flv2z packageserver-54878d5cbb-t9tgr
To do what you want, you need to arrange to call kubectl logs multiple times with a single argument. You can do that by adding -n1 to your xargs command line. Keeping the echo command, running this:
kubectl get pods | grep Running | awk '{print $1}' | xargs -n1 echo kubectl logs
Gets us:
kubectl logs catalog-operator-6b8c45596c-262w9
kubectl logs olm-operator-56cf65dbf9-qwkjh
kubectl logs operatorhubio-catalog-48kgv
kubectl logs packageserver-54878d5cbb-flv2z
kubectl logs packageserver-54878d5cbb-t9tgr
That looks more reasonable. If we drop the echo and run:
kubectl get pods | grep Running | awk '{print $1}' | xargs -n1 kubectl logs | grep value
Then you will get the result you want. You may want to add the --prefix argument to kubectl logs so that you know which pod generated the match:
kubectl get pods | grep Running | awk '{print $1}' | xargs -n1 kubectl logs --prefix | grep value
Not directly related to your question, but you can lose that grep:
kubectl get pods | awk '/Running/ {print $1}' | xargs -n1 kubectl logs --prefix | grep value
And even lose the awk:
kubectl get pods --field-selector=status.phase==Running -o name | xargs -n1 kubectl logs --prefix | grep value

How do i redirect a list of IP addresses to a command line function?

I want to see what countries are trying to access my VPS. I have installed a tool called "goiplookup", which was forked from another effort called "geoiplookup". If I type this at the command line:
goiplookup 8.8.8.8
It returns this:
US, United States
So I figured out how to get a list of IPs that are trying to access my server by using this:
sudo grep "disconnect" /var/log/auth.log | grep -v COMMAND | awk '{print $9}'
Which gives a long list of IPs like this:
1.1.1.1
2.2.2.2
3.3.3.3
I cannot figure out how to get this list of IPs to be processed by the "goiplookup" tool. I tried this:
sudo grep "disconnect" /var/log/auth.log | grep -v COMMAND | awk '{print $9}' | goiplookup
but that did not work. I also tried with no luck:
sudo grep "disconnect" /var/log/auth.log | grep -v COMMAND | awk '{print $9}' | xargs -0 goiplookup
Try this:
sudo grep "disconnect" /var/log/auth.log | grep -v COMMAND | awk '{print $9}' | sort | uniq | xargs -n 1 goiplookup
I added | sort | uniq to ensure each IP only appears once
and xargs -n 1 so that each found IP is processes by goiplookup
I would put it into a file and make a small utility to parse it:
sudo grep "disconnect" /var/log/auth.log | grep -v COMMAND | awk '{print $9}' | sort -u > ./file.txt
cat ./file.txt | while read -r line; do
temp$(echo $line)
goiplookup $temp
done
This will read through the file one line at a time and execute the goiplookup with each IP.
sudo grep disconnect /var/log/auth.log | awk '!/COMMAND/ && !seen[$0]++ {system("geoiplookup \""$9"\""}
Note that geoiplookup only allows one IP per invocation.
The whole thing can be done in awk, but using grep allows the rest to be run unprivileged.
Consider whether grep -w (match whole word) is appropriate, and in awk you can do a similar thing with !/(^|[^[:alnum:]_])COMMAND($|[^[:alnum:]_])/.
I just made a shell script, which works.
#!/bin/bash
readarray -t array < <(sudo grep "disconnect" /var/log/auth.log | grep -v COMMAND | awk '{print $9}' | sort | uniq)
for ip in "${array[#]}"
do
:
country=$(/usr/local/bin/goiplookup -c $ip)
echo "$ip $country"
done

why is jq not working inside bash variable

I have the following code
#/bin/bash
set -e
set -x
requestResponse=$(ssh jump.gcp.xxxxxxx """source dev2 spi-dev
kubectl get pods -o json | jq '.items[] |select(.metadata.name[0:3]=="fea")' | jq .status.podIP
2>&1""")
echo $requestResponse
In the above code source dev2 spi-dev means we have moved to spi-dev namespace inside dev2 cluster. kubectl get pods -o json | jq '.items[] |select(.metadata.name[0:3]=="fea")' | jq .status.podIP 2>&1""") means to print ip address of pod starting with fea. If I do manually kubectl command works. I have also tried escaping fea like \"fea\"
These triple quotes """ are not working as you expect.
Try to change it like this:
ssh jump.gcp.xxxxxxx << EOF
source dev2 spi-dev
kubectl get pods -o json | \
jq '.items[] | \
select(.metadata.name[0:3]=="fea")' | \
jq .status.podIP 2>&1
EOF

Sorted ouput, needs to have text inserted between string

I trying to add text (predefined) between a sorted output and saved to a new file.
I'm using a curl command to gather my info.
$ curl --user XXX:1234!## "http://......"
Then using grep to find IP addresses and sorting so they only appear once.
$ curl --user XXX:1234!## "http://......" | grep -E -o -m1 '([0-9]{1,3}[\.]){3}[0-9]{1,3}' | sort -u
I need to add <my_text_predefined> ([0-9]{1,3}[\.]){3}[0-9]{1,3} <my_text_predefined> between the regex ip address and then saved to a new file.
The script below only get my the ip address
$ curl --user XXX:1234!## "http://......" | grep -E -o -m1 '([0-9]{1,3}[\.]){3}[0-9]{1,3}' | sort -u
123.12.0.12
123.56.98.76
$ curl --user some_user:password "http://...." | grep -E -o -m1 '([0-9]{1,3}[\.]){3}[0-9]{1,3}' | sort -u | sed 's/.*/<prefix> -s & <suffix>/'
So if we need print some text for each IP ... try xargs
for i in {1..100}; do echo $i; done | xargs -n1 echo "Values are:"
if based on IP you would need to take decision put in a loop
for file $(curl ...) do ...
and check $file or do something with it ...

How do I pass multiple query parameters by xargs into httpie?

I tried below to pass a parameters to httpie and it turned into POST method unexpectedly.
1)
$ echo "a1 b1" | xargs -t -n2 bash -c 'http -v https://httpbin.org/anything arg1==$0 arg2==$1'
bash -c http -v https://httpbin.org/anything arg1==$0 arg2==$1 a1 b1
2)
$ echo "arg1==a1 arg2==b1" | xargs -t -n2 bash -c 'http -v https://httpbin.org/anything'
bash -c http -v https://httpbin.org/anything arg1==a1 arg2==b1
The 1st one returns below and seem like there're additional "a1 b1" inhibit proper request.
bash -c http -v https://httpbin.org/anything arg1==$0 arg2==$1 a1 b1
The 2nd one returns seemingly not too far but actual method turned into the POST.
Is there any way to pass multiple parameters to httpie?
Here is a way to accomplish your goal:
echo "a1 b1" |
awk '{print "http -v https://httpbin.org/anything arg1=="$1" arg2=="$2}' |
bash
Even if manually insert the strings like:
$ echo 'http -v https://httpbin.org/anything arg1==a1 arg2==b2' | bash
doesn't work same as below:
$ http -v https://httpbin.org/anything arg1==a1 arg2==b2
I don't get the cause of this happening but simply if I specify the method, It worked.
$ echo "a1 b1" | xargs -t -n2 bash -c 'http -v GET https://httpbin.org/anything arg1==$0 arg2==$1
^^^
and I think I got the caused it's due to stdin so it can be avoid by --ignore-stdin option.

Resources