Jan 14, 2015 - Installing PECL without prompt


Okay on my last post I wrote that the expect command to handle PECL install prompt is difficult to put into an Ansible playbook.
I just figured out a much easier solution.

printf "\n" | sudo pecl install zmq channel://pecl.php.net/zmq-1.1.2

This will act like an expect and automatically send “\n” to any prompt. It cannot send different messages conditionally like expect, but if you just want to throw in some Enter-keys, this’ll do the job.

So that’s an easy one-liner to include in my Ansible cookbook!

Jan 14, 2015 - Ansible - Handling Commands


Playing around with Ansible a little more. yum and service module were the easiest to use, and I think it would be the core moduel when provisioning a node. For a typical application I think git module is also a well-used one.
I’ve originally being setting up my servers with a pretty lengthy shell script that installs packages, clones git repos, chmods certain files and directories, and starts up designated services. Something like this:

yum -y install httpd
yum -y install php-devel


git clone http://example.com/git-repo /path/to/git-repo

chown user:user /path/to/git-repo/something
chmod 755 /path/to/git-repo/something

service httpd start

chmod and chown can be dealt with with the file module in Ansible. git clone and yum install and service is as I’ve mentioned.
What’s the install-zmq.sh ? Something like this:

expect -c "
        spawn sudo pecl install zmq channel://pecl.php.net/zmq-1.1.2 
        expect {
                \"Please provide\" { send \"\r\" }

rm /etc/php.d/zmq.ini
echo "extension=zmq.so" | tee /etc/php.d/zmq.ini

The expect, pecl and echo are not simple modules that come out of the box of Ansible, so here is a playbook I came up with.

- hosts: test-server
  sudo: yes
  - name: be sure zmq is installed
    yum: name=zeromq3 state=installed enablerepo=epel
  - name: be sure pecl (php-pear) is installed
    yum: name=php-pear state=installed

  - name: check zmq PECL existence (/etc/php.d/zmq.ini) 
    register: zmq_existence
    shell: cat /etc/php.d/zmq.ini 2> /dev/null
    changed_when: false  
    always_run: yes 
    ignore_errors: yes

  - name: be sure zmq PECL is installed
    shell: /path/to/install-zmq.expect
    when: zmq_existence.stdout.find('zmq.so') == -1

  - name: add zmq.so into /etc/php.d/
    shell: echo "extension=zmq.so" | tee /etc/php.d/zmq.ini
    when: zmq_existence.stdout.find('zmq.so') == -1

I check if the zmq.ini is installed by cating and checking. ignore_errors is set to suppress the failure of cat, and the result will be registered in register: zmq_existence.
The next two tasks will check the existence with when: zmq_existence.stdout.find('zmq.so') == -1, so that it is only executed when the zmq.ini does NOT exist. This is an important point, as it guarantees idempotence of these shell tasks.

The only part I don’t like about this is that I am not able to write the expect command directly in the playbook; I am calling an external shell script. I wish there is a way to handle expects in a smart way inside the playbook - will look into this.

Jan 12, 2015 - How to manage sessions


Most web application frameworks have some session management system, where session data is stored somewhere - either directly on disk, some in-memory storage (memcached), or some RDB (MySQL).
Unfortunately I cannot seem to be satisfied with any of them. They all have some aspect which prevent me from being 100% comfortable in using them.

  1. Disk
    This is the most obvious one. You can’t save on disk, because it won’t scale. Simple as that. That is a deal braker.

  2. In-memory storage (memcached)
    This seems to be used quite often. I do not like this, because storing all users’ session datas on memcached means that once memcached loses its data, say, by even a simple restart - every single user with their data stored on that node will be considered “Not logged in”, and will be bounced back to their login screen.
    And memcached is not designed to guarantee no data loss, so this is bound to happen throughout the history of any application.
    I am not aware of any way to avoid this issue as of now. I mean, if session data can be regenerated purely with client-side data, then what is the meaning of saving it on the server-side, right?

  3. RDB (MySQL) RDBs are better than in-memory storages because they are not bound to lose data (at least for most of the time). Storing and querying session data on a RDB doesn’t sound so bad, since that’s what RDBs are designed for - to insert and pull data.
    But the problem is that RDBs can face scalability issues.
    When you have 10 million requests every day, with a query to the sessions table for every single request, that can pile up to become a bottleneck, preventing other operations on the database to slow down.
    So at least a traditional RDB wouldn’t work. Maybe if you have a dedicated databse purely for session data that would be okay, but I wish I can avoid adding an extra database to manage into my system.

So what would be the best way?
One option may be to use something like Redis, which is an in-memory storage with disk persistence with it. This way I can decrease the impact of the in-memory storage losing data a little.

But I still am yet to arrive at an answer.