Problems with SED in Ansible playbook - sed

I'm installing Docker on some hosts and using Ansible playbook to do this. However, we have a startup script for Consul that breaks when docker is installed, as Docker adds a virtual NIC and adds an extra value to the variable.
Original Variables
NODEIP=`hostname -I`
NODE=`hostname -I |sed 's/[.]/-/g'`
I can manually change them to the following and this works.
NODEIP=$(hostname -I | grep -o "[^ ]\\+" | awk /^10\./"{print $1}")
NODE=$(hostname -I | grep -o "[^ ]\+" | awk /^10\./"{print $1}" |sed "s/[.]/-/g")
However, I need to add these to an Ansible playbook. I've modified the variable for NODE and it gets updated in the script, but NODEIP does not. See sample playbook code below.
name: Fix consul startup script for Docker virtual network interface
shell: sed -i 's/NODEIP=`hostname -I`/s_.*_NODEIP=$(hostname -I | grep -o \"[^ ]\\+\" | awk /^10\./\"{print \$1}\")' filename
shell: sed -i '/NODE=`hostname -I |sed/s_.*_NODE=$(echo $NODEIP|sed 's/[.]/-/g')_' filename
I'm going insane trying to get this to work properly. Can anyone help?

Whenever you run an ansible-playbook, it will gather_facts by default. This task will populate your ansible-playbook execution with the variables listed here: Ansible facts
In your case, you are looking for:
NODEIP={{ ansible_default_ipv4.address }}
NODE={{ ansible_hostname }}

Below code should solve your requirement
- name: Command for NodeIP
shell: hostname -I | grep -o "[^ ]\\+" | awk /^10\./"{print $1}"
register: NODEIP
- name: Command for NodeName
shell: hostname -I | grep -o "[^ ]\+" | awk /^10\./"{print $1}" |sed "s/[.]/-/g"
register: NODE
Above code will store command output to NODEIP and NODE variables respectively.
To learn more about usage of ansible return values, refer https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html

Thanks to all for the input. Here's what I ended up coming up with (had to escape some characters with backslashes). Delighted it works
- name: replace NODEIP variable in consul startup script
lineinfile:
path: filename
regexp: '^NODEIP='
line: "NODEIP=$(hostname -I | grep -o \"[^ ]\\+\" | awk /^10\\./\"{print $1}\")"
backrefs: yes
- name: replace NODE variable in consul startup script
lineinfile:
path: filename
regexp: '^NODE='
line: "NODE=$(hostname -I | grep -o \"[^ ]\\+\" | awk /^10\\./\"{print $1}\" |sed \"s/[.]/-/g\")"
backrefs: yes

Related

Check number of active meetings in Big Blue Button from command line

I want to check how many active meetings there are on the BBB server at any one time from the command line. I have tried
$ bbb-conf --network
but not getting anywhere. I have also checked the number of active connections to port 80 and 443
$ netstat -anp | grep :443 | grep ESTABLISHED | wc -l
but I'm not sure if I can trust that figure.
I know I can use the isMeetingRunning call from the API but I'm just looking for command line.
Any ideas would be appreciated
The following bash script, which can be run from command line on the same machine as the BigBlueButton server, will process the response to the BBB API getMeetings call.
#!/bin/bash
APICallName="getMeetings"
APIQueryString=""
X=$( bbb-conf --secret | fgrep URL: )
APIEndPoint=${X##* }
Y=$( bbb-conf --secret | fgrep Secret: )
Secret=${Y##* }
S=$APICallName$APIQueryString$Secret
Checksum=$( echo -n $S | sha1sum | cut -f 1 -d ' ' )
if [[ "$APIQueryString" == "" ]]
then
URL="${APIEndPoint}api/$APICallName?checksum=$Checksum"
else
URL="${APIEndPoint}api/$APICallName?$APIQueryString&checksum=$Checksum"
fi
wget -q -O - "$URL" | grep -o '<meetingID>' | wc -w
Tested on a live BBB machine.
Note:
The APICallName and APIQueryString can be modified to provide interface to other BBB API calls. See https://docs.bigbluebutton.org/dev/api.html
The command-line sha1sum will output a different result if a newline is appended to its input. This is the reason echo -n is used instead of echo.
In the last line, the script processes the XML output from the API call in a very naïve way, simply counting the number of occurences of the <meetingID> tag. More elaborate processing would probably require parsing the XML.

Set VSTS output variable to be result from bash command

I'm running a task in VSTS which performs some operations on a variable from a previous step and I then need to output the result to be used in future tasks. I have the following in a command line task running on a linux build host but am having no luck when trying to use the result later with $(podName3).
COMMAND="$(echo '$(pods)' | grep -oh -P '[^ ]*' | grep schema)"
##vso[task.setvariable variable=podName3]"$COMMAND"
I have tried several variations on this to no avail and need some direction as this has stumped me for too long now
Seems the syntax is incorrect.
Just try to below format:
COMMAND="$(echo '$pods' | grep -oh -P '[^ ]*' | grep schema)"
echo "##vso[task.setvariable variable=podName3]$COMMAND"
Or add a powershell task and run below commands to set the variable:
$COMMAND="$(echo '$env:pods' | grep -oh -P '[^ ]*' | grep schema)"
Write-Host "##vso[task.setvariable variable=podName3]$COMMAND"
More information please see Define and modify your variables in a script
I created a command line tool & an Azure DevOps task for this: https://marketplace.visualstudio.com/items?itemName=riezebosch.setvar
It just lets you pipe the output of a command into the tool and output it as the magic variable string. It's written in Go and cross compiled so works on all major platforms and all different shells.
Your example:
echo '$pods' | grep -oh -P '[^ ]*' | grep schema | setvar -name podName3
You only need to include the setvar task prior to this script task in order to get the tool on the agent.
Adding a PSA to this post, looks like they changed the way the variables are accessed now - you have to access variables like this: $(variable)
COMMAND=$(echo '$pods' | grep -oh -P '[^ ]*' | grep schema)
echo "##vso[task.setvariable variable=podName3]$(COMMAND)"

Ansible command quotes

I would like to have the following command integrated in an Ansible playbook task:
cut -f 1 -d: /etc/passwd | xargs -n 1 -I {} bash -c ' echo -e "\n{}" ; chage -l {}'.
Any quote inside breaks the whole command. How I can avoid it to make it run the whole string?
Many thanks in advance.
You can simply use the YAML literal block string syntax. In that way you don't need to escape any quotes. Instead, you can pass your shell command as is.
Example:
- name: test task
shell:
cmd: |
cut -f 1 -d: /etc/passwd | xargs -n 1 -I {} bash -c ' echo -e "\n{}" ; chage -l {}'
tags: test
You can escape them with \”
example: "hello=\"hi\""

Using /proc/<pid>, how can I identify a network port number's application?

I'm trying to identify what application is running on port 56474 without having root access. I know the application was started by me.
Example:
netstat -tunap
tcp 0 0 0.0.0.0:56474 0.0.0.0:* LISTEN -
I've tried using /proc/pid scripts to walk all using grep on ls -l /proc/pid/fd results. Here is my attempt. NOTE: Not sure if I was heading the right direction
for I in `find /proc/*/fd -exec ls -l {} \; 2>/dev/null | awk -F"->|:" '/socket/ {print $4}' | sort -u | sed -e 's/\[//g' -e 's/\]//g'`; do grep $I /proc/*/net/tcp; done
I had no success. Not sure if there is a way. Thanks.
NOTE: Added another answers as lsof was not satisfactory.
This should work:
#! /bin/bash
port=56474
hex_port=$(echo "obase=16; $port" | bc )
inode=$(cat /proc/net/tcp | grep ":$hex_port" | awk '{print $10}')
for i in $(ps axo pid); do
ls -l /proc/$i/fd 2> /dev/null | grep -q ":\[$inode\]" && echo $i
done
Explanation:
Once we have the port number converted to Hexadecimal, we can get the inode number from /proc/net/tcp (10th field), then we loop through /proc/pids/fd and find a symlink pointing to the inode.
If you're sure the application was started by you then you can use lsof:
/usr/sbin/lsof -nP | grep :56474 | awk '{print $2}'
Another technique to resolve pids and ports of all running apps without root:
1.) Get the pids of running apps. Either use the ActivityManager or parse a ps console output.
2.) iterate through /proc/$pid/net/status files and get the matching uid for a pid.
cat /proc/*pid*/net/status | grep Uid:
3.) Call and parse the output of tcp, tcp6,udp, udp6 files to match ports and uids:
cat /proc/net/tcp
...
4.) match the uids of both matchings, get a port-to-pid map without su access.
Cheers,
goethe

Grep one file and remove contents of the grep with sed -i on a second file

I am trying to grep ip addresses from one file and remove the contents of the grep from a second file with a single command.
The masterfile has
header x.x.x.x
header x.x.x.x
header2 y.y.y.y
header2 y.y.y.y
header3 z.z.z.z
header3 z.z.z.z
The tempfile has
x.x.x.x
x.x.x.x
y.y.y.y
y.y.y.y
z.z.z.z
z.z.z.z
Attempt
grep "header" masterfile | sed 's/^.* //' | sed -i "" '/$/d' tempfile
Would also like to remove the empty line after the sed command removes an entry.
If I understand it correct, you need the following:
grep -v -F -f <(grep '\<header\>' masterfile | cut -d' ' -f2) tempfile
or
grep -v -F -f <(sed 's/^header *//' masterfile) tempfile
For your input, it'd produce:
y.y.y.y
y.y.y.y
z.z.z.z
z.z.z.z
In order to save the changes to tempfile, you could redirect the command output to another file and move it to the desired file:
grep -v -F -f <(sed 's/^header *//' masterfile) tempfile > tmp && mv tmp tempfile
EDIT: You seem to be sh which doesn't support Process Substitution. In that case, you can use the following:
grep '\<header\>' master | cut -d' ' -f2 | grep -v -F -f - tempfile
Produce a sed script from the first file and feed it to a second sed instance.
sed 's%^header \(.*\)%/^\1\$/d%' masterfile |
sed -i "" -f - tempfile
On Linux, -f - says to read the script from standard input. On some other platforms, this does not work; then, you'll have to save the script to a temporary file (or maybe you have /dev/fd/1 or /dev/stdin).