Simple HTTP file sharing in bash

Just a little bash function inspired by a post[1], that allows to quickly share file(s) over the network using a one-shot HTTP request. It only requires nc to bind the listening socket.

function share() {
    ! type -a nc &>/dev/null && { echo "This machine doesn't have 'nc'" >/dev/stderr ; return 1 ; }
    [[ $# -ne 1 ]] && { echo "Usage: share <filename>" >/dev/stderr ; return 1 ; }
    [[ ! -f $1 ]] && { echo "No such file : $1" >/dev/stderr ; return 1 ; }
    port=$((8000 + RANDOM%1000))
    if [[ $OSTYPE == "linux-gnu" ]] ; then
        while read ip ; do echo "http://$ip:$port/$1" ; done < <(/sbin/ip addr ls | awk '/inet / {split($2,a,"/");print a[1];}' | sort -n | uniq)
        cat - "$1" <<- EOF | $(type -p nc) -l -p $port -q 0
            HTTP/1.1 200 OK\r
            Content-Length: $(stat -c %s "$1")
            Content-Type: $(file -b --mime-type "$1")
EOF
    # Check André's comment
    elif [[ $OSTYPE == "darwin*" ]] ; then
        ifconfig -u | \
            sed -ne 's/.*inet \([0-9.]*\) netmask .*/\1/p' | \
            sort -nu | while read ip ; do echo "http://$ip:$port/$1" ; done
    cat - "$1" < < EOF | nc -l "$port"
        HTTP/1.1 200 Ok
        Content-Type: application/octet-stream
        Content-Length: $(eval $(stat -s "$1") && echo $st_size)
EOF
    else
        echo "Please provide a patch for other flavor of Linux/*BSD: <contact@floriancrouzat.net>" && return 1
    fi
}

[1] – http://www.vidarholen.net/contents/blog/?p=17

Monitor a Pacemaker Cluster with ocf:pacemaker:ClusterMon and/or external-agent

If you want to monitor your Pacemaker cluster status and get alerted in real time on any cluster transition, you must define an ocf:pacemaker:ClusterMon resource[1].

This resource must be cloned and will run on all nodes of the cluster. It works by using crm_mon[2] in the background, which is a binary that provides a summary of cluster’s current state. This binary has a couple options to send email (SMTP) or traps (SNMP) on any transition to a chosen recipient. You can pass these options from ocf:pacemaker:ClusterMon to the underlaying crm_mon via the extra_options parameter, see [1].

Here is a sample configuration to receive SNMP traps:

primitive ClusterMon ocf:pacemaker:ClusterMon \
        params user="root" update="30" extra_options="--snmp-traps snmphost.example.com --snmp-community public" \
        op monitor on-fail="restart" interval="60"
[...]
clone ClusterMon-clone ClusterMon \
        meta target-role="Started"

For further information and XML examples, see Chapter 7. of Pacemaker Explained[5].

Sadly, since RHEL 6.x and pacemaker-cli-1.1.6-1, both SNMP and ESMTP support are not compiled anymore in crm_mon as advised in the changelogs:

$ sudo rpm -q --changelog pacemaker-cli
* Thu Oct 06 2011 Andrew Beekhof  - 1.1.6-1
[...]
- Do not build in support for snmp, esmtp by default

It means the previous example of an ocf:pacemaker:ClusterMon definition cannot be used anymore as the --snmp-traps parameter doesn’t exist anymore. The same goes for SMTP-related parameters.

Alright, then how to automatically monitor Pacemaker cluster’s transitions and how to get alerted when they occurs ? Of course, paying someone to watch the output of crm_mon -Arf on every cluster is a solution. Not my favorite choice though…

Thankfully, crm_mon[2] is still shipped with the external-agent capability:

  • -E, --external-agent=value
        A program to run when resource operations take place.
  • -e, --external-recipient=value
        A recipient for your program (assuming you want the program to send something to someone).

When triggered, the external agent (-E) is fed with dynamically filled environment variables allowing you to know what transition happened and to react accordingly in your external-agent code. By making clever usage of this capability, you can develop whatever reaction you want and reproduce built-in SNMP support, which I did with a little bash script (pcmk_snmp_helper.sh) that is now included within the extra folder of Pacemaker sources[3].

This notification mechanism (external-agent) and all environnement variables are now documented in chapter 7 of Pacemaker Explained[6]

This “helper” script has been designed to match *my* needs: receive a SNMP trap on each failed monitor operation or on any other event (even successful) that is not a monitor operation (start, stop, …).
It is compliant with pacemaker MIB[4] and sends SNMP v2c traps (only requires snmptrap binary which can be found in net-snmp-utils).

But remember: you can script whatever you want and it will be done on any cluster transition, eg: insert the event into a database, deliver email notifications through SMTP, HTTP-POST something somewhere…

In the end, you will end-up with the bellow configuration.
Just adapt the code of the helper to your needs.

primitive ClusterMon ocf:pacemaker:ClusterMon \
        params user="root" update="30" extra_options="-E /usr/local/bin/pcmk_snmp_helper.sh -e snmphost.example.com" \
        op monitor on-fail="restart" interval="60"
[...]
clone ClusterMon-clone ClusterMon \
        meta target-role="Started"

[1] – http://linux.die.net/man/7/ocf_heartbeat_clustermon
[2] – http://linux.die.net/man/8/crm_mon
[3] – https://github.com/ClusterLabs/pacemaker/blob/master/extra/pcmk_snmp_helper.sh
[4] – https://github.com/ClusterLabs/pacemaker/blob/master/extra/PCMK-MIB.txt
[5] – http://clusterlabs.org/doc/en-US/Pacemaker/1.1-crmsh/html/Pacemaker_Explained/ch07.html
[6] – http://clusterlabs.org/doc/en-US/Pacemaker/1.1-crmsh/html/Pacemaker_Explained/s-notification-external.html

MySQL: SHOW GRANTS for all users, from CLI, with a one-liner

If you ever have to double-check all your MySQL Users permissions database per database, and server by server, it’s a pain in the ass, and as far as SHOW GRANTS only takes one username, you cannot export everything simply. Let’s not discuss about how you could have used PhpMyAdmin, you just can’t, or it has become your full-time job as it will be very long if you have many servers with many databases.
Thanks to a combination of MySQL and bash magics, you still can achieve this with a bash one-liner. You’ll only have to input your eventual MySQL password twice.

mysql -u root -p -P 3306 -s <<< 'SELECT CONCAT("SHOW GRANTS FOR ",user,"@",host,";") FROM mysql.user WHERE host="host.example.com";' | sed -e "s/FOR /&'/" -e "s/@/'&'"/ -e "s/;/'&/" | mysql -u root -p -P 3306 -s

This sample one-liner limits the users connecting from a remote host, but if you remove the WHERE part, you can have all grants for all known users.

Note: you have to input your password twice. The second time, it might be displayed on-screen, but you can be sure it will never be in your bash history.