Ansible: how to skip a specific host or group in a playbook

If you search the Ansible documentation, you’ll probably end up using a when in your playbooks to skip a host.

I found out that it makes more sense to me to skip hosts from the hosts declaration, by prepending them with a !:

- name: check on which hosts this would run
  remote_user: root
  hosts: all !bastion
  - name: say hello
      msg: "hello {{ ansible_hostname }}"

My hosts file looks like:





Running the playbook with the usual commandline:

ansible-playbook -i hosts playbook.yaml

produces the expected result: the debug module is only run on webservers (ws) and databases (db), not on the bastion hosts (bastion).

I hope this will help some other sysadmin out there :)

Firefox Beta PPA on Linux Mint 18.2

I wanted to test out a more recent version of Firefox on Linux Mint 18.2, so I went over to grab the Ubuntu PPA.

I ran the installation commands (as root):

add-apt-repository ppa:mozillateam/firefox-next
apt-get update
apt-get install firefox

But apt wouldn’t update the package, because the default package priorities (check /etc/apt/preferences.d/*.pref) won’t allow the use of Ubuntu packages over Mint packages.

Fair enough, I created a new file /etc/apt/preferences.d/firefox.pref containing:

Package: firefox
Pin: origin
Pin-Priority: 900

Package: firefox
Pin: release o=Ubuntu
Pin-Priority: 900

And updated to the beta (currently 55.0b12).

Enjoy the 10 fixed bugs and the exciting 127 new bugs to discover!

Workaround for javaws jnpl error “Cannot grant permissions to unsigned jars.”

There’s an emergency and you’re trying to log on that ancient KVM/iLO/iDRAC and you’re getting an error like:

net.sourceforge.jnlp.LaunchException: Fatal: Application Error: Cannot grant permissions to unsigned jars.

Quick workaround:

Find the file. In my case it is located in /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/

Then find the row:

jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024

Comment it out, copy it, delete the MD5 string.

#jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
jdk.jar.disabledAlgorithms=MD2, RSA keySize < 1024

Save the file. Try again. It should work.

Some more pointers if the problem persists:

Disk I/O errors on Adaptec ASR8805 raid controller

We have an Adaptec ASR8805 controller on one of the servers we manage. For various reasons we need to shrink a logical volume that is sitting on a RAID 6 logical device created and exposed by this controller, but we can’t because we’re getting seek errors:

Buffer I/O error on device dm-2, logical block 3330419721
sd 6:0:1:0: [sdb]  Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
sd 6:0:1:0: [sdb]  Sense Key : Hardware Error [current] 
sd 6:0:1:0: [sdb]  Add. Sense: Internal target failure
sd 6:0:1:0: [sdb] CDB: Read(16): 88 00 00 00 00 06 34 11 69 00 00 00 01 00 00 00
end_request: critical target error, dev sdb, sector 26643360000
sd 6:0:1:0: [sdb]  Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE

From what the controller is reporting, the RAID 6 is healthy, and all the physical drives SMART information seems ok(ish).

It turns out, no background checking of the RAID 6 parity has been enabled, and that is probably the problem, as reported by this article.

To get a “quick” fix (it’s a 24T array), I started:

# arcconf task start 1 logicaldrive 1 verify_fix

when it’ll be finished, I’ll enable the background check with:

# arcconf consistencycheck 1 on

I really hope this saves time to some fellow admin out there :)

How to display IOwait percentage in Prometheus

Prometheus has a few quirks, dealing with cpu time is one of these. this article explains how to deal with cpu time, and these are the rules I made for my own Prometheus/Grafana dashboard:

avg by (instance) (irate(node_cpu{mode="iowait"}[1m])) * 100

this rule groups by instance the iowait average for the system (all cpus)

avg by (instance) (irate(instance=~"hostname.*", node_cpu{mode="iowait"}[1m])) * 100

while this rule is like the one above, with the difference that you can filter which systems are reported, by hostname

hopefully this will be useful for someone out there :)

How to run a Flask application in Docker

Flask is a nice web application framework for Python.

My example looks like:

from flask import Flask

app = Flask(__name__)

def hello_world():
  return 'Hello, World!'

According to Flask documentation, to run the application we need to run flask run. So our Dockerfile will run this command and we’ll pass an environment variable with the application name when we start the container:

FROM python:3-onbuild
CMD [ "python", "-m", "flask", "run", "--host=" ]

The --host= parameter is necessary so that we will be able to connect to flask from outside the docker container.

Using the -onbuild version of the Python container is handy because it will import a file named requirements.txt and install the Python modules listed in it, so go on and create this file in the same directory, containing the single line, flask.

Now we can build our container:

docker build -t flaskapp .

This might take a while. When it ends, we’ll be able to run the container, passing the FLASK_APP environment variable:

docker run -it --rm --name flaskapp \
  -v "$PWD":/usr/src/app -w /usr/src/app \
  -e LANG=C.UTF-8 -e \
  -p 5000:5000 flaskapp

As you can see I’m mounting the local directory $PWD to /usr/src/app in the container and setting the work directory there. I’m also passing the -p 5000:5000 parameter so that the container tcp port 5000 is available by connecting to my host machine port 5000.

You can test your app with your browser or with curl:

$ curl
Hello, World!

I hope this will be useful to someone out there, have fun! :)