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.

Advertisements

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.

Your first steps installing Graylog

A new colleague needed some help to setup a Graylog installation. He had never done this before, so he asked for assistance. What follows is a rehash of an email I sent him on how to proceed and build knowledge on the subject:

So initially I had zero knowledge of Graylog. What I did to accustom myself with it was to download an OVA file with a prepared virtual machine and run it via VMware Fusion. The same VM can also be imported to VirtualBox and even to AWS, although they also provide ready AMIs for deployment in AWS.  Links:
Keep in mind that this is a full installation of what Graylog needs to work with and it also comes with a handly little script named “graylog-ctl” that manipulates a lot of configuration. The big catch is that graylog-ctl is not part of any standard Graylog deployment. It only comes with the OVA and the AMI images.
So after I had some fun with it on a VM on my workstation, reading the documentation and testing stuff, I had an initial deployment of the AMI image in AWS. But this is not an installation that can scale.  Which brings us to the next steps:
  • For Graylog to work you need to provide it with a MongoDB and an ElasticSearch database. It is your choice whether these will be clustered for high availability or not, whether they will run in the same machine or not. You control the complete architecture. So in my case I made the following decisions:
  • I am running a MongoDB replica set using three VMs. This is a standard setup as it is described in the MongoDB online documentation. Since it is not password protected, it only accepts connections from the Graylog instance. I used AWS security groups for that.
  • I am using an ElasticSearch cluster with three VMs where the nodes are both data and masters. If you can, use 7 nodes, three masters (lower machines since they do not run queries and do not index any data) and four data nodes (higher end machines). Again, since this is not password protected, I used AWS security groups to allow access only from the Graylog instance.
  • I am running a single Graylog instance on a separate VM. Currently it only listens for syslog stuff.  When the need arises, I will add a two more nodes to increase the availability.  I think I changed as many as four or five lines in the main configuration file. Graylog uses MongoDB to store its configuration, which includes anything you configure via the web interface.
  • Pay extra attention to the versions of ElasticSearch and MongoDB that your Graylog version requires. Use exactly what is mentioned in the documentation. For example in my case I am not running ES 6.x but the latest 5.x.
Now it is time to up your game. Once you see that your installation is working you have to decide whether to password protect access to MongoDB and ElasticSearch and whether to encrypt traffic between all those instances or not. I say give it a go.
I’ve not even touched issues like database management for Mongo and Elastic, backing them up, restoring, deleting indices, etc because this is post from zero to your first week testing Graylog.  There is plenty of stuff out there to take you to the next level, once you get used to the complexity of the software involved.
Should you need any more help, ping me anytime.

terraform, route53 and lots of records

At work we try to manage as much as we can with terraform. This also includes Route53 for zones and records. In a certain situation we had about 14 zones and 1476 records managed in a single state file.

As it happened I needed a zone recreated (but not erased) and this affected about 409 records. Well deleting them with terraform apply took ages. To the point that the temporary STS token expired and botched the process.  So after a little facepalming, I decided to cleanup the zone from the AWS console and then issue a batch of terraform state rm to reconcile the state. Happily, after that, apply took its time (but reasonably) and all was well.

I am thinking that next time I am faced with such a situation, to lock the state file in Dynamo, copy it over from S3, manipulate it locally, unlock and run a plan to see how it all plays out. Or, wherever I can, use a state per zone instead of a state file encompassing a set of zones.

Rule 110 in Haskell

Because WordPress.com does not always render MarkDown properly, you may need to read a copy of this post here.


One of the things I learned by reading AIM 239 is the Game of Life and Cellular Automata. One particular kind of one dimensional cellular automata, Rule 110 popped by my twitter stream the other day, so I thought I could try and code it with the minimal Haskell subset that I can handle.

Rule 110 is special because it is proven to be able to simulate a Turing machine. Head over to its Wikipedia page if you want to learn more about the proof and the interesting story around it.

Rule 110 starts with a string of zeros and ones and a transition table that decides the next state of the automaton. If you put each line of the strings after the other, interesting patterns can emerge. Let’s see the transition state:

Current pattern 111 110 101 100 011 010 001 000
New state for center cell 0 1 1 0 1 1 1 0

If you look closely, you can use a list of eight digits and its index in order to encode the above state transitions:

rule110 = [
  0, -- ((0,0,0), 0)
  1, -- ((0,0,1), 1)
  1, -- ((0,1,0), 1)
  1, -- ((0,1,1), 1)
  0, -- ((1,0,0), 0)
  1, -- ((1,0,1), 1)
  1, -- ((1,1,0), 1)
  0  -- ((1,1,1), 0)
  ] :: [Int]

But what about the transitions of the leftmost and rightmost digit you might think. Let’s assume that their missing neighbor is zero. Therefore, given an initial state and a rule that governs the transitions, we may calculate the next state with:

nextState :: [Int] -> [Int] -> [Int]
nextState state rule =
  [ rule !! x |
    let t = [0] ++ state ++ [0],
    i <- [1..(length(t)-2)],
    let x = (t !! (i-1)) * 4 + (t !! i) * 2 + (t !! (i+1))
  ]

-- construct an infinite sequence of next states
sequenceState :: [Int] -> [Int] -> [[Int]]
sequenceState state rule =
  [state] ++ sequenceState (nextState state rule) rule

Example:

*Main> state = [0,1,1,0]
*Main> nextState state rule110
[1,1,1,0]

One of the most interesting patterns occurs when we begin with the right most digit being 1 and all the rest being zeros:

*Main> state = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1] :: [Int]
*Main> x = take 30 $ sequenceState state rule110
*Main> showState x
                             *
                            **
                           ***
                          ** *
                         *****
                        **   *
                       ***  **
                      ** * ***
                     ******* *
                    **     ***
                   ***    ** *
                  ** *   *****
                 *****  **   *
                **   * ***  **
               ***  **** * ***
              ** * **  ***** *
             ******** **   ***
            **      ****  ** *
           ***     **  * *****
          ** *    *** ****   *
         *****   ** ***  *  **
        **   *  ***** * ** ***
       ***  ** **   ******** *
      ** * ******  **      ***
     *******    * ***     ** *
    **     *   **** *    *****
   ***    **  **  ***   **   *
  ** *   *** *** ** *  ***  **
 *****  ** *** ****** ** * ***
**   * ***** ***    ******** *
*Main>

The output was somehow pretty printed:

showState [] = return ()
showState state = do
  -- putStrLn $ show (state !! 0)
  putStrLn $ [ c | d <- (state !! 0), let c = if d == 0 then ' ' else '*' ]
  showState $ tail state

I wish I can find time and play more with cellular automata. I kind of find a day every five years or so.

Update: Here is a pattern using Rule 90:

                             *
                            *
                           * *
                          *
                         * *
                        *   *
                       * * * *
                      *
                     * *
                    *   *
                   * * * *
                  *       *
                 * *     * *
                *   *   *   *
               * * * * * * * *
              *
             * *
            *   *
           * * * *
          *       *
         * *     * *
        *   *   *   *
       * * * * * * * *
      *               *
     * *             * *
    *   *           *   *
   * * * *         * * * *
  *       *       *       *
 * *     * *     * *     * *
*   *   *   *   *   *   *   *

A Collatz sequence in Haskell

WordPress.com does not always render Markadown properly, so a copy of this post resides here.


I am coninuing my adventure in Haskell. In order to make it a bit more fun, I decided to code a simple yet very intriguing problem, I first heard of when I read AI Memo 239: The Collatz conjecture.

Item 133
Item 133. The Collatz conjecture in AIM 239

Construct a sequence of integers where given an arbitrary interger the value of the next is:
* If the number is even, divide it by two.
* If the number is odd, triple it and add one.

This can easily be coded in Haskell as follows:

collatz :: Int -> Int
collatz 1 = 1
collatz n =
  if (even n)
    then (n `div` 2)
    else (3 * n + 1)

But how can one obtain a sequence of numbers from this? A very clever solution is here where the author implements a variation of takeWhile which includes also the first list item that fails the test the first time. So my question became, can it be done in another way? Yes it can:

collatzSequence :: Int -> [Int]
collatzSequence n =
  if n == 1
    then [1]
    else [n] ++ collatzSequence (collatz n)

Let's see some test runs:

*Main> collatzSequence 5
[5,16,8,4,2,1]
*Main> collatzSequence 50
[50,25,76,38,19,58,29,88,44,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]
*Main> collatzSequence 500
[500,250,125,376,188,94,47,142,71,214,107,322,161,484,242,121,364,182,91,274,137,412,206,103,310,155,466,233,700,350,175,526,263,790,395,1186,593,1780,890,445,1336,668,334,167,502,251,754,377,1132,566,283,850,425,1276,638,319,958,479,1438,719,2158,1079,3238,1619,4858,2429,7288,3644,1822,911,2734,1367,4102,2051,6154,3077,9232,4616,2308,1154,577,1732,866,433,1300,650,325,976,488,244,122,61,184,92,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]
*Main> collatzSequence 512
[512,256,128,64,32,16,8,4,2,1]
*Main> collatzSequence 513
[513,1540,770,385,1156,578,289,868,434,217,652,326,163,490,245,736,368,184,92,46,23,70,35,106,53,160,80,40,20,10,5,16,8,4,2,1]
*Main>

You may have observed we only run it on positive integers. When we run it with negative integers, there are a few more cycles that we need to take into account. Here is the updated sequence function, written with guards:

collatzSequence :: Int -> [Int]
collatzSequence n
  | n == 1 = [1]
  | n == (-2) = [(-2)]
  | n == (-5) = [(-5)]
  | n == (-17) = [(-17)]
  | otherwise = [n] ++ collatzSequence (collatz n)

Test:

*Main> collatzSequence (-50)
[-50,-25,-74,-37,-110,-55,-164,-82,-41,-122,-61,-182,-91,-272,-136,-68,-34,-17]

Now if there was also a way to prove the conjecture…

Please note that in Haskell the unary minus is a function and not an operator, hence, you need to parenthesize. This also works:

*Main> collatzSequence $ -50
[-50,-25,-74,-37,-110,-55,-164,-82,-41,-122,-61,-182,-91,-272,-136,-68,-34,-17]

Update: A friend posted me his own elegant version of the Collatz sequence:

collatz :: Int -> [Int]
collatz 1 = [1]
collatz n
    | even n =  n : collatz (n `div` 2)
    | odd n  =  n : collatz (n * 3 + 1)

main = do
  putStrLn $ show $ collatz 1
  putStrLn $ show $ collatz 6
  putStrLn $ show $ collatz 23