Agility in planning (not)

I’ve read about the inflexibilities of Gosplan while going through Red Plenty. These days I am reading Confessions of a Nuclear War Planner and it gives me an opportunity to examine inflexibilities in thinking on the western bloc side:

The price of bringing all the theatre and component service plans into harmony with each other, into one plan, was the total elimination of any flexibility in carrying it out.

Yes no flexibility at all in a military machine where the no plan survives first contact with the enemy is dated around the same time (1963). In this case the inflexibility was due to the lack of staff and computer time available to complete alternatives. This is similar to Gosplan’s problems: they had so many inputs to their models, that their planning for the current year was completing around October of said year.

Ambition in planning, lack of resources and definite inflexibility in taking another route because of already committed resources. Wow project management does not change at all, in any field and in any bloc.

I am 20% into the book and I am scared. It seems to me that we have survived out of pure luck.

(Random incoherent thoughts; I know.)

Advertisements

In sed matching \d might not be what you would expect

A friend asked me the other day whether a certain “search and replace” operation over a credit card number could be done with sed: Given a number like 5105 1051 0510 5100, replace the first three components with something and leave the last one intact.

So my first take on this was:

# echo 5105 1051 0510 5100 | sed -e 's/^\([0-9]\{4\} \)\{3\}/lala /'
lala 5100

which works, but is not very legible. So here is taking advantage of the -r flag, if your modern sed supports it:

# echo 5105 1051 0510 5100 | sed -re 's/^([[:digit:]]{4} ){3}/lala /' 
lala 5100

So my friend asked, why not use \d instead of [[:digit:]] (or even [0-9])?

# echo 5105 1051 0510 5100 | sed -re 's/^(\d{4} ){3}/lala /' 
5105 1051 0510 5100

Why does this not work? Because as it is pointed in the manual:

In addition, this version of sed supports several escape characters (some of which are multi-character) to insert non-printable characters in scripts (\a, \c, \d, \o, \r, \t, \v, \x). These can cause similar problems with scripts written for other seds.

There. I guess that is why I still do not make much use of the -r flag and prefer to escape parentheses when doing matches in sed.

Confessions of a Necromancer

Confessions of a NecromancerConfessions of a Necromancer by Pieter Hintjens

I knew of Hintjens’s work (Xitami, ZeroMQ, etc) but not much more of him. The book popped up in a Slack I am a member of while discussing Torvalds’s decision to take a step back and work on himself.

Hintjens writes a technical memoir. At least that is the first part of the book. And because he writes stuff about the era of computing I grew up into, I like it. He reminded me of technologies, tricks and methods I had long forgotten. I even learned new old stuff that I had never come across.

And the there is the second part of the book. The most important and most interesting one. What can I say about it? Not much I am afraid. I can only declare my respect for his effort to document the process and his voyage towards the end. I envy his clarity, even though I cannot even begin to imagine the cost for it to be maintained during the cancer treatment process.

Highly touching.

View all my reviews

PS: I am trying to see whether using Goodreads to write my thoughts on books I read is a thing that I like.

vagrant, ansible local and docker

This is a minor annoyance to people who want to work with docker on their vagrant boxes and provision them with the ansible_local provisioner.

To have docker installed in your box, you simply need to enable the docker provisoner in your Vagrantfile:

config.vm.provision "docker", run: "once"

Since you’re using the ansible_local provisiner, you might skip this and write a task that installs docker from get.docker.com or wherever it suits you anyway, but I prefer this as vagrant knows how to best install docker onto itself.

Now obviously you can have the provisioner pull images for you, but for any crazy reason you want to pass most, if not all, of the provisioning to ansible. And thus you want to use among others the docker_image module. So you write something like:

- name: install python-docker
  become: true
  apt:
    name: python-docker
    state: present

- name: install docker images
  docker_image:
    name: busybox

Well this is going to greet you with an error message when you up the machine for the fist time:

Error message

TASK [install docker images] ***************************************************
fatal: [default]: FAILED! => {“changed”: false, “msg”: “Error connecting: Error while fetching server API version: (‘Connection aborted.’, error(13, ‘Permission denied’))”}
to retry, use: –limit @/vagrant/ansible.retry

Whereas when you happily run vagrant provision right away:

TASK [install docker images] ***************************************************
changed: [default]

Why does this happen? Because even though the installation of docker makes the vagrant user a member of group docker, this becomes effective with the next login.

The quickest way to bypass this is to make that part of your first run of ansible provisioning as super user:

- name: install docker images
  become: true  
  docker_image:
    name: busybox

I am using the docker_image module only as an example here for lack of a better example with other docker modules on a Saturday morning. Pulling images is something that is of course very easy to do with the vagrant docker provisioner itself.

default: Running ansible-playbook…

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [default]

TASK [install python-docker] ***************************************************
changed: [default]

TASK [install docker images] ***************************************************
changed: [default]

PLAY RECAP *********************************************************************
default : ok=3 changed=2 unreachable=0 failed=0

Vagrant, ansible_local and pip

I try to provision my Vagrant boxes with the ansible_local provisioner. The other day I was using the pip ansible module while I was booting the box, but was getting errors while installing packages. It turns out that the pip version I had when I created the environment needed an upgrade. Sure you can run a pip install pip --upgrade from the command line, but how do you do so within a playbook? Pretty easy it seems:

---
- hosts: all
  tasks:
    - name: create the needed virtual environment and upgrade pip
      pip:
        chdir: /home/vagrant
        virtualenv: work
        virtualenv_command: /usr/bin/python3 -mvenv
        name: pip
        extra_args: --upgrade

    - name: now install the requirements
      pip:
        chdir: /home/vagrant
        virtualenv: work
        virtualenv_command: /usr/bin/python3 -mvenv
        requirements: /vagrant/requirements.txt

(Link to pastebin here in case the YAML above does not render correctly for you.)

I hope it helps you too.

Happy sysadmin day

Hello and happy SysAdmin day. The baby swing bellow is from 2011. While at rest it looks like a safe swing, it is not. The chains latch too close to the middle and it is very easy for the seat to revolve around a second horizontal axis while swinging. You can understand how I know.

It is SysAdmin day today. We make sure the chains latch properly so your software runs without extra revolutions.

You’re welcome :)

baby swing

 

unbound, python and conditional replies based on source IP address

We’re using unbound internally for DNS resolution. It works smoothly and allows for some DNS tricks when you want to implement some split-brain trickery, but not a complete split-brain deployment.  The other day we needed to send out conditional replies based on the IP address of the querying machine.  Unbound comes with a python module but it has some of the weirdest, unhelpful documentation ever.  I am not alone in believing this.

It is very hard to figure out the source IP address of a DNS query using the unbound python library. My first pointer on how to do so was on ServerFault.  I have uploaded my own version of an operate function at pastebin. The code in question that you need to consider is:

# Find out source IP address
rl = qstate.mesh_info.reply_list
while (rl):
  if rl.query_reply:
    q = rl.query_reply
    break
  rl = rl.next

# Careful with this conditional
try: addr = q.addr
except NameError: addr = None

The try … except handling is needed because I found out that sometimes the q.addr may not be defined and thus further down the line you may be bitten by an abnormal exit of your script.

Update: two friends have suggested that I change the while loop with a more Pythonic list comprehension:

q = next((x for x in qstate.mesh_info.reply_list if x.query_reply), None)
try: addr = q.query_reply.addr
except NameError: addr = None

One of them actually has a pretty cool pastebin about it.