How to get names of specific nodes depending on taints in K8S - json

In a Kubernetes cluster, I have a few nodes, master and workers. I want to get the name of nodes which have no taints on them. I know I need to get them using the jsonpath and adding conditions in it, but not sure how exactly.
What can I try next? Taints are in spec and names of the nodes are obviously in metadata, so how can I approach this task?

You can use go-template to do this:
Example:
kubectl get node -o go-template='{{range $element := .items}}{{if (ne (len (or $element.spec.taints "")) 0)}}{{$element.metadata.name}}{{"\n"}}{{end}}{{end}}'
In more readable format:
kubectl get node -o go-template='{{ range $element := .items }}
{{- if (ne (len (or $element.spec.taints "")) 0) -}}
{{ $element.metadata.name}}{{"\n"}}
{{- end -}}
{{ end }}'
Working:
using range, we will loop over the items. In this case, it's the
nodes.
using the len function, we will calculate the length of the
list holding all the taints.
Used or inside the len function for defaulting it to "0" if no taint is found.
If the taint len is not equal(ne) to zero, printing the element name(ie, node name)
you can flip the ne to eq to reverse the behavior.

Related

How to compare a value with the previous object?

I'm using jq to format the log entries from journalctl -o json in a readable way. While that works nicely, I'm missing the journalctl indicator for a reboot. This information isn't directly included in the json format output. But it can be inferred by comparing the _BOOT_ID value of the current object with the one on the previous line. If they are different, the message belongs to another boot session and I need to insert that "-- Reboot --" line.
How can I compare that value in jq?
The following is a simple version of what I'm doing:
journalctl -o json --since today |jq -r '
"\(._SOURCE_REALTIME_TIMESTAMP // .__REALTIME_TIMESTAMP |tonumber |. / 1000000 |strflocaltime("%m-%d %H:%M:%S")) \(.SYSLOG_IDENTIFIER // .UNIT): \(.MESSAGE)"
' |less
It shows a timestamp, unit name, and the message. What I'm looking for is something like the following (where $$previous$$ does not exist):
journalctl -o json --since today |jq -r '
"\(if ._BOOT_ID != $$previous$$._BOOT_ID then "-- Reboot --\n" else "" end)\(._SOURCE_REALTIME_TIMESTAMP // .__REALTIME_TIMESTAMP |tonumber |. / 1000000 |strflocaltime("%m-%d %H:%M:%S")) \(.SYSLOG_IDENTIFIER // .UNIT): \(.MESSAGE)"
' |less
I'd also accept setting variables at the end of one line and accessing them at the beginning of the next line; but variables don't seem to exist, I could only set a property of the current object which won't help.
A solution can be obtained using foreach along the following lines:
jq -nr '
foreach inputs as $entry (null;
$entry
+ if (. != null) and (._BOOT_ID != $entry._BOOT_ID)
then {emit: true} else null end;
if .emit then "-- Reboot --" else empty end,
.foo)
'
You would replace .foo with the filter defining the projection of interest.

Jinja2 if/else on user defined variable

Attempting to make a decision in a template based on the last character of a variable (third level domain hostname) , but the epiphany alludes me. Make a config stanza if value else, do the other.
I set a fact in play:
- name: Set third level domain name to a variable
set_fact:
my_3rd_levelname: "{{ ansible_nodename.split('.')[0] }}"
- name: Ascertain if which server we're on
set_fact:
my_one_or_two: "{{ my_3rd_levelname[-1]|int }}"
...which appears to echo out with debug, save the casting as an int...see below.
TASK [role-test : Echo out my_one_or_two] *******************************************************************************************************************
ok: [w.x.y.42] => {
"my_one_or_two": "2"
}
Then in the template.j2...
{# If my_one_or_two is even list server1 first. If not, second. #}
{% if lookup('vars,',my_one_or_two) + my_one_or_two|int is 1 %}
[some config file stanza here]
{% else %}
[some other config file stanza instead]
I've poked and hoped until I can stand it no longer and am reaching out. I've tried just using the raw variable, e.g., {% if my_one_or_two|int == 1 %} along with many other attempts, but I'm stuck. I can't seem to overcome this error:
AnsibleError: template error while templating string: expected token 'name', got 'integer'. String: [the contents of my template]
Any input would be greatly appreciated at this juncture.
Thanks
Okay...leaving this here in case someone else doesn't realize you can use any Python method that the object supports. Here's what I did. Remember the server names end in 1 or 2 and its a String.
Created a varible in /roles/[rolename]/vars...
my_simple_hostname: "{{ ansible_nodename.split('.')[0] }}"
Then used the 'endswith' method to evaluate it....
% if my_simple_hostname.endswith('1') == true %}
[content if true]
{% else %}
[content when false]
{% endif %}

gui_sg_addsignal : How to create generic module hierarchy for signals in a group for Synopsys DVE?

I want to create a signal group with generic TOP name in session file for Synopsys DVE.
My purpose is to use the same tcl file for block and system level debugs by defining correct 'TOP' value.
set TOP "TOP.Block_level"
#set TOP "TOP.SYSTEM_LEVEL.HIER1.HIER2"
set _session_group_1 Group1
gui_sg_create "$_session_group_1"
set Group1 "$_session_group_1"
set a "${TOP}.level1.signal1"
#add_wave $a # Works
# Oringial code
gui_sg_addsignal -group "$_session_group_1" { topA.level1.signal1 topA.level1.signal2 }
# Expected implementation similar to: but fires error that "$TOP.level1.signal1" not found
gui_sg_addsignal -group "$_session_group_1" { $TOP.level1.signal1 topA.level1.signal2 }
Appreciate the solution.
Thanks
The braces ({}) prevent the TCL interpreter from evaluating the variable content of $TOP. You should use double quotes (") as list delimiters or use the list command:
gui_sg_addsignal -group "$_session_group_1" "$TOP.level1.signal1 topA.level1.signal2"
or
gui_sg_addsignal -group "$_session_group_1" [list $TOP.level1.signal1 topA.level1.signal2]

Insert newline character at index in .bash

I'm taking an introductory course to bash at my university and am working on a little MotD script that uses a json-object grabbed from an API using curl.
I want to make absolutely certain that you understand that this is NOT an assignment, but something I'm playing around with to learn more about how to script with bash.
I've found myself stuck with what could possibly be a very simply issue; I want to insert a new line ('\n') on a specific index if the 'quote' value of my json-object is too long (in this case on index 80).
I've been following a bunch of SO threads and this is my current solution:
#!/bin/bash
json_object=$(curl -s 'http://quotes.stormconsultancy.co.uk/random.json')
quote=$(echo ${json_object} | jq .quote | sed -e 's/^"//' -e 's/"$//')
author=$(echo ${json_object} | jq .author)
count=${#quote}
echo $quote
echo $author
echo "wc: $count"
if((count > 80));
then
quote=${quote:0:80}\n${quote:80:(count - 80)}
else
echo "lower"
fi
printf "$quote"
The current output I receive from the printf is the first word of the quote, whereas if I have an echo before trying to do the string-manipulation I get the entire quote.
I'm sorry if it's not following best practice or anything, but I'm an absolute beginner using both vi and bash.
I'd be very happy with any sort of advice. :)
EDIT:
Sample output:
$ ./json.bash
You should name a variable using the same care with which you name a first-born child.
"James O. Coplien"
86
higher
You should name a variable using the same care with which you name a first-born nchild.
You can just use a single line bash command to achieve this,
string="You should name a variable using the same care with which you name a first-born child."
(( "${#string}" > 80 )) && printf "%s\n" "${string:0:80}"$'\n'"${string:80}" || printf "%s\n" "$string"
You should name a variable using the same care with which you name a first-born
child.
(and) for an input line less than 80 charaacters
string="You should name a variable using the same care"
(( "${#string}" > 80 )) && printf "%s\n" "${string:0:80}"$'\n'"${string:80}" || printf "%s\n" "$string"
You should name a variable using the same care
An explanation,
(( "${#string}" > 80 )) && printf "%s\n" "${string:0:80}"$'\n'"${string:80}" || printf "%s\n" "$string"
# The syntax is a indirect implementation of ternary operator as bash doesn't
# directly support it.
#
# (( "${#string}" > 80 )) will return a success/fail depending upon the length
# of the string variable and if it is greater than 80, the command after && is
# executed and if it fails the command after || is executed
#
# "${string:0:80}"$'\n'"${string:80}"
# A parameter expansion syntax for sub-string extraction.
#
# ${PARAMETER:OFFSET}
#
# ${PARAMETER:OFFSET:LENGTH}
#
# This one can expand only a part of a parameter's value, given a position
# to start and maybe a length. If LENGTH is omitted, the parameter will be
# expanded up to the end of the string. If LENGTH is negative, it's taken as
# a second offset into the string, counting from the end of the string.
#
# So in our example we basically extract the characters from position 0 to 80
# insert a new-line and append the rest of the string
#
# The $'\n' syntax allows to include all escape sequence characters be
# included, in this case just the new line character.
Not really in the original question, but adding some extra code to #Inian great answer to allow not to break in the middle of a word, but rather at the last white space in ${string:0:80}:
#!/usr/bin/env bash
string="You should really name a variable using the same care with which you name a first-born child."
if (( "${#string}" > 80 )); then
maxstring="${string:0:80}"
lastspace="${maxstring##*\ }"
breakat="$((${#maxstring} - ${#lastspace}))"
printf "%s\n" $"${string:0:${breakat}}"$'\n'"${string:${breakat}}"
else
printf "%s\n" "$string"
fi
maxstring=${string:0:80}:
Let's get the first 80 characters of the quote.
lastspace=${maxstring##*\ }:
Deletes longest match of *\ (white space is escaped) from front of $maxstring, ${lastspace} will be the remaining string from last white space until end of the string.
breakat="$((${#maxstring} - ${#lastspace}))":
Subtract the length of ${lastspace} with the length of ${maxstring} to get the last index of the white space from ${maxstring}. This is the index where \n will be inserted.
Example output with "hard" break at character 80:
You should really name a variable using the same care with which you name a firs
t-born child.
Example output with a "soft" break at the closest white space from character 80:
You should really name a variable using the same care with which you name a
first-born child.

Extract only one field for a specific flow from JSON

Below is the Json I receive as Response from url.
{"flows":[{"version":"OF_13","cookie":"0","tableId":"0x0","packetCount":"24","byteCount":"4563","durationSeconds":"5747","priority":"0","idleTimeoutSec":"0","hardTimeoutSec":"0","flags":"0","match":{},"instructions":{"instruction_apply_actions":{"actions":"output=controller"}}},
{"version":"OF_13","cookie":"45036000240104713","tableId":"0x0","packetCount":"0","byteCount":"0","durationSeconds":"29","priority":"6","idleTimeoutSec":"0","hardTimeoutSec":"0","flags":"1","match":{"eth_type":"0x0x800","ipv4_src":"10.0.0.10","ipv4_dst":"10.0.0.12"},"instructions":{"none":"drop"}},
{"version":"OF_13","cookie":"45036000240104714","tableId":"0x0","packetCount":"0","byteCount":"0","durationSeconds":"3","priority":"7","idleTimeoutSec":"0","hardTimeoutSec":"0","flags":"1","match":{"eth_type":"0x0x800","ipv4_src":"10.0.0.10","ipv4_dst":"127.0.0.1"},"instructions":{"none":"drop"}},
{"version":"OF_13","cookie":"0","tableId":"0x1","packetCount":"0","byteCount":"0","durationSeconds":"5747","priority":"0","idleTimeoutSec":"0","hardTimeoutSec":"0","flags":"0","match":{},"instructions":{"instruction_apply_actions":{"actions":"output=controller"}}}]}
So, I have for example four flows and I want to extract only the field "byteCount" for a specific flow identify by the ipv4_src and ipv4_dst that i have to give it as input
How can I do this?
json_array := JSON.parse(json_string)
foreach (element in json_array.flows):
if(element.match.hasProperty('ipv4_src') && element.match.hasProperty('ipv4_dst')):
if(element.match.ipv4_src == myValue && element.match.ipv4_dst == otherValue):
print element.byteCount ;
The above is a pseudo-code to find byteCount based on ipv4_src and ipv4_dst. Note that these two properties are within match property, which may or may not contain them. Hence, first check for their existence and then process.
Note: When formatted property, each element in the array is like
{
"version":"OF_13",
"cookie":"45036000240104713",
"tableId":"0x0",
"packetCount":"0",
"byteCount":"0",
"durationSeconds":"29",
"priority":"6",
"idleTimeoutSec":"0",
"hardTimeoutSec":"0",
"flags":"1",
"match":{
"eth_type":"0x0x800",
"ipv4_src":"10.0.0.10",
"ipv4_dst":"10.0.0.12"
},
"instructions":{
"none":"drop"
}
}
Here's how to perform the selection and extraction task using the command-line tool jq:
First create a file, say "extract.jq", with these three lines:
.flows[]
| select(.match.ipv4_src == $src and .match.ipv4_dst == $dst)
| [$src, $dst, .byteCount]
Next, assuming the desired src and dst are 10.0.0.10 and 10.0.0.12 respectively, and that the input is in a file named input.json, run this command:
jq -c --arg src 10.0.0.10 --arg dst 10.0.0.12 -f extract.jq input.json
This would produce one line per match; in the case of your example, it would produce:
["10.0.0.10","10.0.0.12","0"]
If the JSON is coming from some command (such as curl), you can use a pipeline along the following lines:
curl ... | jq -c --arg src 10.0.0.10 --arg dst 10.0.0.12 -f extract.jq