Ubuntu: setting up redis-server (reloaded)

Monday, November 28. 2011

I blogged about setting up redis before, here's a small update to the situation:

If you're running Ubuntu 9.10 or 10.04.x, the most recent release available through aptitude is 1.x. Version 1.x doesn't include many things (pubsub, etc.) which are available in 2.x. So this leaves you with two options!


Compiling redis-server is simple (aka, make && sudo make install), a few things were missing (last time I checked):

Using a PPA!

The PPA (Personal Package Archive) concept is great. In a nutshell, it allows anyone to publish packages for various (Ubuntu) distributions. You upload a definition (sort of) and leverage Canonical's build farm, etc.. There are a few downsides to Launchpad: it's confusing, your PPA only holds the latest version of your build and overall publishing packages could be a lot easier. Which is why I'm so thankful for everyone who takes the time to publish.

Chris Lea seems to build most of the software I need. And he put all packages online in various Launchpad PPAs! Kudos to him!

Here's how you get setup!

Discover the Launchpad PPA:

server# sudo add-apt-repository ppa:chris-lea/redis-server

Update sources and install redis!

server# sudo apt-get update
server# sudo apt-get install redis-server

Done! ;-) All things (start script, configs) included!


In case that's too much type or you're looking for some automation, I also have a chef-recipe to get this done!

Trying out BigCouch with Chef-Solo and Vagrant

Monday, April 4. 2011

So the other day, I wanted to quickly check something in BigCouch and thanks to Vagrant, chef(-solo) and a couple cookbooks — courtesy of Cloudant — this was exceptionally easy.

As a matter of fact, I had BigCouch running and setup within literally minutes.

Here's how.


You'll need git, Ruby, gems and Vagrant (along with Virtualbox) installed. If you need help with those items, I suggest you check out my previous blog post called Getting the most out of Chef with Scalarium and vagrant.

For operating system to use, I suggest you get a Ubuntu 10.04 box (aka Lucid).

Vagrant (along with Ruby and Virtualbox) is a one time setup which you can use and abuse for all kinds of things, so don't worry about the extra steps.


Clone the cookbooks in $HOME:

$ git clone http://github.com/cloudant/cloudant_cookbooks

Create a vagrant environement:

$ mkdir ~/bigcouch-test
$ cd ~/bigcouch-test
$ vagrant init

Setup ~/bigcouch-test/Vagrantfile:

Vagrant::Config.run do |config|
  config.vm.box = "base"
  config.vm.box_url = "http://files.vagrantup.com/lucid32.box"

  # Forward a port from the guest to the host, which allows for outside
  # computers to access the VM, whereas host only networking does not.
  # config.vm.forward_port "http", 80, 8080

  config.vm.provisioner = :chef_solo
  config.chef.cookbooks_path = "~/cloudant_cookbooks"
  config.chef.add_recipe "bigcouch::default"

Start the vm:

$ vagrant up

Use BigCouch

$ vagrant ssh
$ sudo /etc/init.d/bigcouch start
$ ps aux|grep [b]igcouch

Done. (You should see processes located in /opt/bigcouch.)


That's all — for an added bonus you could open BigCouch's ports on the VM use it from your host system because otherwise this is all a matter of localhost. See config.vm.forward_port in your Vagrantfile.

Giganews VPN on Ubuntu

Sunday, February 20. 2011

This article briefly describes how you can setup the Giganews VPN (PPTP) on Ubuntu. I'm gonna assume 10.04 (that's what I tested with) and the gnome desktop.

Does this sound familiar: The VPN connection 'xxxxx' failed because there were no valid VPN secrets.

If so then I'm hoping this article will help you.

What is a VPN for?

The use-case for a VPN — and this is for basically any VPN (not just Giganews' service) — is security. For example, for online banking when you use public WIFI at airports, train stations or your favorite coffee place.

Unless the VPN service itself is blocked, a VPN also provides real and unfiltered Internet access. No bogus blocks or censorships because your goverment thought they need to protect you.

From a development perspective using different VPNs also allow me to easily test location-based services. And it doesn't stop there — for example since I work for people in the U.S. we often run into issues with services which we use which do things different to me because of my location. A VPN in the U.S. fixes that for me.

And there are more and more use-cases once you think about it.

Continue reading "Giganews VPN on Ubuntu"

Zend Framework: Writing an IN-Clause with Zend_Db

Sunday, December 19. 2010

I'm currently running a little database analysis to see how many of our users might be affected by Gawker's breach of security the other week. Since we use Zend Framework, Zend_Db is our weapon of choice.

Running the queries I noticed, that Zend_Db doesn't seem to support an IN-clause with a straight fetchAll().

The IN-clause is only supported when I wrap my statement with Zend_Db_Select, which is something I rarely do. Part of the reason is that I still don't feel comfortable writing my SQL in a DSL which doesn't really do anything besides wrapping a string into an object and IMHO it doesn't add to readability either.

And the other reason is that I don't plan to run this import against any other database than MySQL. Which is why I don't see the need for abstraction either.


The following code fails:

// $db = Zend_Db::factory($config);
$sql    = "SELECT foo FROM bar WHERE foo IN(?)";
$params = array(1,2,3,4);
$db->fetchAll($sql, $params);

The warning

PHP Warning:  mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in
prepared statement in /opt/library/Zend/Db/Statement/Mysqli.php on line 204

The exception

Mysqli statement execute error : No data supplied for parameters in prepared statement


My solution is simple:

$sql    = "SELECT foo FROM bar WHERE foo IN (?)";
$params = array('foo', 'bar', 'foobar', "foo\bar", '\bar', "'foobar'");
$query  = str_replace('?', substr(str_repeat('?, ', count($params)), 0, -2), $sql);
$db->fetchAll($query, $params);

I'm expanding a single ? to as many ?'s as necessary. The reason why I did this, is that I wanted to be able to use Zend_Db's quoting. The data I'm dealing with is really messy and I didn't feel like repairing it.

Of course there may be other and maybe more simple ways to do it.


That's all, happy hacking.

(Update, 2010/12/19 10:05 PM: Refined my example. Apparently people don't read the text (= blog post) around the code. :-))

Magento: Loading the product from a template

Wednesday, November 24. 2010

When I wrangle with Magento Commerce and customize anything, every other bit is of course tied to a product's ID, or sometimes entity ID.

The challenging part is that whenever you're in a template in Magento, the scope is very different from the previous one. This is sometimes frustrating, but when you think of it — it makes sense. That is, in Magento! ;-)

Magento works in blocks and each block is basically a class file, of course $this is never the same. So for example the scope of a block that renders a product page is different from something like Mage_Sales_Block_Order_Item_Renderer_Default (used to display a row of an order).


I recently had to customize the display of an item in an order in the customer's account.

To do so, I had a nifty helper which is tied to a product's ID. Unfortunately, I was only able to retrieve the SKU, quantity ordered and all sorts of other things right away — but the product's ID was not available.

So how do you load a product otherwise? Simple! Using the SKU!

// app/design/frontend/default/my-template/template/sales/order/items/renderer/default.phtml
$_sku     = $this->getItem()->getSku();
$_product = Mage::getModel('catalog/product')->loadByAttribute('sku', $_sku);
$_product->getEntityId(); // here is your ID

So yeah — Mage_Catalog_Model_Product = very helpful. And of course there are a bunch of other attributes to load products by. Well, just about any attribute. Just dig around the docs, or var_dump() a product object on a product page to see what else is available.


Quick and dirty — I just blogged this because it took me 25 minutes to find that model and the loadByAttribute() method.

And hopefully by blogging this, I'll never ever forget.