Category Archives: Scripting

Rackspace – Cloud Sever autokill script

#!/bin/bash

# This script auto delete the current instance and ask the
# Autoscale Group to replace the node


###########################################################

CRED_FILE=/opt/autoscale/.credentials
AS_GRP_ID=a17b08b3-0c04-48e8-84a9-3070c29a27fa

###########################################################

# Gather info from credential file
USERNAME=$(grep username $CRED_FILE | awk -F= '{print $2}' | sed 's/ //g')
APIKEY=$(grep api_key $CRED_FILE | awk -F= '{print $2}' | sed 's/ //g')
REGION=$(grep region $CRED_FILE | awk -F= '{print $2}' | sed 's/ //g' | tr '[:upper:]' '[:lower:]')


SERVER_UID=$(xenstore-read name | sed 's/instance-//')

AUTH=$(
curl -sd \
"{
   \"auth\":
   {
        \"RAX-KSKEY:apiKeyCredentials\":
        {\"username\": \"$USERNAME\",
        \"apiKey\": \"$APIKEY\"}        }
}" \
-H 'Content-Type: application/json' \
'https://identity.api.rackspacecloud.com/v2.0/tokens' | python -m json.tool | grep -A 7 token | awk '/id/ { print $2 }' | tr -d '"' | tr -d ","
) 

TOKEN=$(echo $AUTH | awk '{print $1}')
ID=$(echo $AUTH | awk '{print $2}')


curl -sH "X-Auth-Token: $TOKEN" -H "Content-type: application/json" -X DELETE https://$REGION.autoscale.api.rackspacecloud.com/v1.0/$ID/groups/$AS_GRP_ID/servers/$SERVER_UID?replace=true

Scheduled unattended tasks – at

$ at time date

$ at 11 am may 20

# at 02:00 AM Fri
at> yum update glibc
at> echo "Executing scheduled task" | logger
at> shutdown -r +5 "Server is going to be rebooted in 5 minutes for scheduled task. Please save your work ASAP." 
at> <EOT>
job 2 at 2015-02-06 02:00

Ends using CTRL+D that generates the <EOT> bit.

Source: http://www.computerhope.com/unix/uat.htm

Check the processes in the queue

atq

Check content of a job

at -c <job number>

Delete job

atrm <job number>

Also, you can cat/modify the job in /var/spool/cron/atjobs/ or /var/spool/at (in Centos)

If not installed, on Centos, make sure to start also ‘atd‘ service.

# chkconfig atd on && service atd start

WordPress PHP-FPM and Apache (with variables)

Sample setup for Apache virtual host and PHP-FPM pool with variables instead hard coded user details.
This could be handy if your are scripting your deploy (e.g. with Ansible).

In our example we are using the following:

Domain: example.com
SFTP user: example.com
Document root: /var/www/vhosts/example.com/httpdocs/

<VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com

        DocumentRoot /var/www/vhosts/example.com/httpdocs
        <Directory /var/www/vhosts/example.com/httpdocs>
                require all granted
                Options Indexes
                AllowOverride All
        </Directory>

        ErrorLog "logs/example.com-error_log"
        CustomLog "logs/example.com-access_log" combined env=!forwarded
        CustomLog "logs/example.com-access_log" proxy env=forwarded

	# Configure proxy connector
	<Proxy "unix:/dev/shm/example.com-php5-fpm.sock|fcgi://php-fpm">
    		# we must declare a parameter in here (doesn't matter which) or it'll not register the proxy ahead of time
	    	ProxySet disablereuse=off
	</Proxy>
	#
	# Redirect to the proxy connector
	<FilesMatch \.php$>
    		SetHandler proxy:fcgi://php-fpm
	</FilesMatch>


        <Directory /var/www/vhosts/example.com/httpdocs/wp-content/uploads>
            # Important for security, prevents someone from
            # uploading a malicious .htaccess
            AllowOverride None

            SetHandler none
            SetHandler default-handler

            Options -ExecCGI
            php_flag engine off
            RemoveHandler .cgi .php .php3 .php4 .php5 .phtml .pl .py .pyc .pyo
            <Files *>
                    AllowOverride None

                    SetHandler none
                    SetHandler default-handler

                    Options -ExecCGI
                    php_flag engine off
                    RemoveHandler .cgi .php .php3 .php4 .php5 .phtml .pl .py .pyc .pyo
            </Files>
        </Directory>
</VirtualHost>

Create a file called example.com.conf in /etc/php-fpm/pool/

[example.com]

listen = /dev/shm/$pool-php5-fpm.sock
user = $pool
group = $pool
listen.owner = $pool
listen.group = apache
listen.mode = 0666

pm = dynamic
pm.max_children = 35
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 25
slowlog = /var/log/php-fpm/$pool-slow.log
php_admin_value[error_log] = /var/log/php-fpm/$pool-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session/$pool

BASH conditional expressions

-a file

True if file exists.

-b file

True if file exists and is a block special file.

-c file

True if file exists and is a character special file.

-d file

True if file exists and is a directory.

-e file

True if file exists.

-f file

True if file exists and is a regular file.

-g file

True if file exists and its set-group-id bit is set.

-h file

True if file exists and is a symbolic link.

-k file

True if file exists and its “sticky” bit is set.

-p file

True if file exists and is a named pipe (FIFO).

-r file

True if file exists and is readable.

-s file

True if file exists and has a size greater than zero.

-t fd

True if file descriptor fd is open and refers to a terminal.

-u file

True if file exists and its set-user-id bit is set.

-w file

True if file exists and is writable.

-x file

True if file exists and is executable.

-G file

True if file exists and is owned by the effective group id.

-L file

True if file exists and is a symbolic link.

-N file

True if file exists and has been modified since it was last read.

-O file

True if file exists and is owned by the effective user id.

-S file

True if file exists and is a socket.

file1 -ef file2

True if file1 and file2 refer to the same device and inode numbers.

file1 -nt file2

True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not.

file1 -ot file2

True if file1 is older than file2, or if file2 exists and file1 does not.

-o optname

True if the shell option optname is enabled. The list of options appears in the description of the -o option to the set builtin (see The Set Builtin).

-v varname

True if the shell variable varname is set (has been assigned a value).

-R varname

True if the shell variable varname is set and is a name reference.

-z string

True if the length of string is zero.

-n stringstring

True if the length of string is non-zero.

string1 == string2string1 = string2

True if the strings are equal. When used with the [[ command, this performs pattern matching as described above (see Conditional Constructs).

=’ should be used with the test command for POSIX conformance.

string1 != string2

True if the strings are not equal.

string1 < string2

True if string1 sorts before string2 lexicographically.

string1 > string2

True if string1 sorts after string2 lexicographically.

arg1 OP arg2

OP is one of ‘-eq’, ‘-ne’, ‘-lt’, ‘-le’, ‘-gt’, or ‘-ge’. These arithmetic binary operators return true if arg1 is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to arg2, respectively.  Arg1 and arg2 may be positive or negative integers.

 

 

Source http://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html

Dynamic MOTD on Debian

Here a simple script that setup a dynamic MOTD message ‘ubuntu-like’ on Debian servers:

#!/bin/bash

# Script to install Dynamic MOTD on Debian servers

# This version uses figlet

if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root or using sudo"
   exit 1
fi

if [ ! -f /etc/debian_version ] ; then
   echo "This script can run ONLY on Debian OS"
   exit 1
fi

# Install required packages:
# - figlet: ASCII art for hostname
# - lsb-release: get distro details (fallback)
apt-get install figlet lsb-release

# Backup MOTD file
mv -f /etc/motd{,.ORIG}

# Symlink dynamic MOTD file
ln -s /var/run/motd /etc/motd

# Create dynamic motd environment
mkdir /etc/update-motd.d/
cd /etc/update-motd.d/

cat <<'EOF' > 00-header
#!/bin/sh
#
#    00-header - create the header of the MOTD
#
[ -r /etc/os-release ] && . /etc/os-release
OS=$PRETTY_NAME

if [ -z "$OS" ] && [ -x /usr/bin/lsb_release ]; then
        OS=$(lsb_release -s -d)
fi

figlet -f slant $(hostname)
printf "\n"
printf "\t- %s\n\t- OS version %s\n\t- Kernel %s\n" "$OS" "$(cat /etc/debian_version)" "$(uname -r)"
printf "\n"
EOF

cat <<'EOF' > 10-sysinfo
#!/bin/bash
#
#    10-sysinfo - generate the system information
#
date=`date`
load=`cat /proc/loadavg | awk '{print $1}'`
root_usage=`df -h / | awk '/\// {print $(NF-1)}'`
home_usage=`df -h /home | awk '/\// {print $(NF-1)}'`
memory_usage=`free -m | awk 'NR==2{printf "%.2f%%\n", $3*100/$2 }'`
swap_usage=`free -m | awk '/Swap/ { printf("%3.1f%%", "exit !$2;$3/$2*100") }'`
users=`users | wc -w`
time=`uptime | grep -ohe 'up .*' | sed 's/,/\ hours/g' | awk '{ printf $2" "$3 }'`
processes=`ps aux | wc -l`
ip=`ifconfig $(route -n | grep '^0.0.0.0' | awk '{ print $8 }') | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'`


printf "System information as of %s\n\n" "$date"
printf "IP Address:\t%s\tSystem uptime:\t%s\n" "$ip" "$time"
printf "System load:\t%s\tProcesses:\t%s\n" "$load" "$processes"
printf "RAM used:\t%s\tSwap used:\t%s\n" "$memory_usage" "$swap_usage"
printf "Usage on /:\t%s\tUsage on /home:\t%s\n" "$root_usage" "$home_usage"
printf "Local Users:\t%s\tProcesses:\t%s\n" "$users" "$processes"
EOF


cat <<'EOF' > 90-footer
#!/bin/sh
#
#    90-footer - write the admin's footer to the MOTD
#
[ -f /etc/motd.tail ] && cat /etc/motd.tail || true
EOF


chmod +x /etc/update-motd.d/*

clear
echo "Installation completed. Please logout and login again to test."

 

If you are running CentOS7, here the how to for that OS.

BASH – File test operators

(From man bash)

The test command sorts using ASCII ordering.

-a file
              True if file exists.
-b file
              True if file exists and is a block special file.
-c file
              True if file exists and is a character special file.
-d file
              True if file exists and is a directory.
-e file
              True if file exists.
-f file
              True if file exists and is a regular file.
-g file
              True if file exists and is set-group-id.
-h file
              True if file exists and is a symbolic link.
-k file
              True if file exists and its ``sticky'' bit is set.
-p file
              True if file exists and is a named pipe (FIFO).
-r file
              True if file exists and is readable.
-s file
              True if file exists and has a size greater than zero.
-t fd
              True if file descriptor fd is open and refers to a terminal.
-u file
              True if file exists and its set-user-id bit is set.
-w file
              True if file exists and is writable.
-x file
              True if file exists and is executable.
-G file
              True if file exists and is owned by the effective group id.
-L file
              True if file exists and is a symbolic link.
-N file
              True if file exists and has been modified since it was last read.
-O file
              True if file exists and is owned by the effective user id.
-S file
              True if file exists and is a socket.
file1 -ef file2
              True if file1 and file2 refer to the same device and inode numbers.
file1 -nt file2
              True if file1 is newer (according to modification date) than file2, or if file1 exists and file2 does not.
file1 -ot file2
              True if file1 is older than file2, or if file2 exists and file1 does not.

Regex – Grep reference

 

Regex operator

Meaning

.

Matches any single character.

?

The preceding item is optional and will be matched, at most, once.

*

The preceding item will be matched zero or more times.

+

The preceding item will be matched one or more times.

{N}

The preceding item is matched exactly N times.

{N,}

The preceding item is matched N or more times.

{N,M}

The preceding item is matched at least N times, but not more than M times.

Represents the range if it’s not first or last in a list or the ending point of a range in a list.

^

Matches the empty string at the beginning of a line; also represents the characters not in the range of a list.

$

Matches the empty string at the end of a line.

\b

Matches the empty string at the edge of a word.

\B

Matches the empty string provided it’s not at the edge of a word.

\<

Match the empty string at the beginning of word.

\>

Match the empty string at the end of word.

(a|b)

Match a or b

[abc]

Range (a or b or c)

[^abc]

NOT a or b or c

[a-z]

Any letter (lowercase) from a to z

[A-Z]

Any letter (uppercase) from a to z

[a-zA-Z]

Any letter (upper and lowercase) from a to z

[0-9]

Any digit from 0 to 9

A most exhaustive cheat sheet is available here

Dynamic DNS update script

Below a script that I’ve created to update your Dynamic DNS service.

It has been tested on Raspian (Raspberry Pi), Ubuntu 18.04 and Debian 9.

It works with Internet.bs, No-ip.com and CloudFlare

https://bitbucket.org/thtieig/dynip_update/src/master/

Also, for who as a router running DD-WRT, here a quick article about how to set it up.

Enjoy! 😉

How to build a Debian package from source

There are plenty of articles on the net… but here I’m posting my notes about compiling netatalk.

First of all, you need the minimum packages:

apt-get install build-essential dh-make autotools-dev

I needed this on my Raspberry Pi for this article, and I didn’t want to make dirty the system using the common “make / make install” commands.

This are the simple steps I’ve followed (all as root – even if it’s not the best practise).

mkdir /tmp/netatalk
cd /tmp/netatalk
wget http://downloads.sourceforge.net/project/netatalk/netatalk/3.1.7/netatalk-3.1.7.tar.gz
tar xzvf netatalk-3.1.7.tar.gz
cd netatalk-3.1.7

Make sure the folder has this format: <name_of_the_package>-<version> ALL in lowercase!

dh_make -e [email protected] -f ../netatalk-3.1.7.tar.gz

It will ask for the type of the package. To make things easier, just select single entering s.

Edit the file debian/control adding the missing bits (example below):

Source: netatalk
Section: net
Priority: extra
Maintainer: root <[email protected]>
Build-Depends: debhelper (>= 8.0.0), autotools-dev
Standards-Version: 3.9.3
Homepage: http://netatalk.sourceforge.net/
#Vcs-Git: git://git.debian.org/collab-maint/netatalk.git
#Vcs-Browser: http://git.debian.org/?p=collab-maint/netatalk.git;a=summary

Package: netatalk
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: AppleTalk user binaries
 Open Source AFP fileserver capable of serving many Macintosh clients simultaneously as an AppleShare file server (AFP)

Then, add debian/rules adding this line, to pass custom configure parameters:

override_dh_auto_configure:
	dh_auto_configure -- --with-init-style=debian-sysv --with-zeroconf

The <TAB> is what you have to press to indent the code. Without that TAB, the file won’t work properly. Before dh_auto_configure there is a TAB 🙂
MAKE SURE that the syntax gets highlighted like this:

debian_rules

I’ve read that it should be good to run dpkg-depcheck -d ./configure before the next step.
Honestly, I didn’t do that because it requires an extra package called devscripts that installs loads of dependencies, which I didn’t want to add on my Raspberry pi.
In a different situation, I would probably have done that.

Then run:

dpkg-buildpackage -us -uc

…and wait.

If you get something like this…

dpkg-deb: building package `netatalk' in `../netatalk_3.1.7-1_armhf.deb'.
dpkg-genchanges >../netatalk_3.1.7-1_armhf.changes
dpkg-genchanges: including full source code in upload
dpkg-source --after-build netatalk-3.1.7
dpkg-buildpackage: full upload (original source is included)

…you’ve been lucky! And you can cd .. and you should have your package .deb created and ready to be installed with a simple dpkg -i .deb

Good luck! 🙂

NOTE: I’ve noticed that the compile might fail due to ‘acl‘ package missing. I’m not a master in compiling, so what I’ve done is the following

apt-get install acl

Than I’ve modified include/atalk/acl.h start at line 63, adding #define O_IGNORE 0 to make it look like following:

#define O_NETATALK_ACL 0
#define O_IGNORE 0
#define chmod_acl chmod

This trick was from here
Than, you need to commit the change with the following command: dpkg-source --commit and save adding a little description like “patch to compile with no ACLs” or something like that.
This made me possible to finish the building of the package and have the deb.

 


 

UPDATE: Debian jessy systemd

# Packages to install

apt-get install build-essential libevent-dev libssl-dev libgcrypt11-dev libkrb5-dev libpam0g-dev libwrap0-dev libdb-dev libtdb-dev libmysqlclient-dev avahi-daemon libavahi-client-dev libacl1-dev libldap2-dev libcrack2-dev systemtap-sdt-dev libdbus-1-dev libdbus-glib-1-dev libglib2.0-dev tracker libtracker-sparql-1.0-dev libtracker-miner-1.0-dev autotools-dev debhelper 

# How to edit debian/rules

override_dh_auto_configure:
	dh_auto_configure -- --with-init-style=debian-systemd  --without-libevent --without-tdb --with-cracklib --enable-krbV-uam --with-pam-confdir=/etc/pam.d --with-dbus-sysconf-dir=/etc/dbus-1/system.d --with-tracker-pkgconfig-version=1.0

And here the already compiled file netatalk_3.1.8

Backup Raspberry Pi SD on your Mac… and restore.

Plug the SD in your Mac.

In the Terminal, as root, use diskutil to identify your SD.
Generally it’s the last in the list, if you’ve just plugged in.

root:~ # diskutil list

You will see something like this:
diskutil_list_pi_sd

In my case, the SD is /dev/disk4. For this reason, I run the following to unmount the whole disk.

root:~ # diskutil umountDisk /dev/disk4
Unmount of all volumes on disk4 was successful

Once done, you can create the backup using dd utility, but make sure to change the device from /dev/diskX to /dev/rdiskX, adding the “r“.

root:~ # dd if=/dev/<span style="color: #ff0000;">rdisk4</span> of=/path/to/mypibackup.img bs=1m

To restore, of course… invert if (input file) with of (output file)… 🙂

root:~ # dd if=/path/to/mypibackup.img of=/dev/rdisk4 bs=1m