Multi-screen with Ubuntu Unity

This tweet has to have been the most popular thing I have ever said. At time of posting it has gained 80 retweets, 25 favourites and many replies/questions.

Work recently bought me a new workstation, so the 1st thing I always do is to dual boot with Ubuntu.

Some might consider me an edge case user. Though as a developer, I like a rather particular set-up. That is, 3 wide screen monitors with the central one rotated 90 degrees for my IDE.

This is something that Windows gets right without having to dig about installing things. While Linux distros have always struggled (in my experience).

Because my tweet gained quite a few questions, I thought it best to reply to them here for everybody to see.

@ankitvad asks what specs. I use for Ubuntu.
Titanium Rimless Glasses from Spex4Less.com
Couldn’t resist, sorry :)

Dell Alienware X51
CPU: i7
Memory: 8GB
Graphics card: nVidia GeForce GTX 660
Storage: 1TB HDD (Windows) 120GB SSD (Linux)
Mouse: Logictech M570 trackball
OSs: Window 7 SP1, Ubuntu 12.10 64bit
Monitors: 2 x 22″ Dell, 1 x 22″ LG

All 3 monitors are connected to the one graphics card. Two by DVI and one by HDMI.

As I said, this is a working system from a fresh install without updates being applied or any 3rd party packages installed. So the default graphics driver is doing quite well these days :)

The only downside to this is that the default graphics driver is dog slow and won’t let me play games on Steam ;) The next step will be to get the nVidia binary driver working.

Symfony2 pagination

Using Symfony2, DQL and knplabs/knp-paginator-bundle – how to get around “Cannot count query which selects two FROM components, cannot make distinction”

Chroot SFTP home dir

Example user ‘iain’

sudo mkdir -p /chroot/iain/home/iain
sudo useradd -M -d /home/iain iain
sudo passwd iain
sudo chwon iain: /chroot/iain/home/iain

sudo nano -w /etc/ssh/sshd_config
# At the end of the file, add:

Match User paypoint
    ChrootDirectory /chroot/iain
    AllowTCPForwarding no
    X11Forwarding no
    ForceCommand internal-sftp

sudo /etc/init.d/ssh restart

Making an entity repository container aware in Symfony2.1

I had a need to add ACL rules to entities at the repository level.

My biggest struggle was getting dependancy injection working.

This is what I finally came up with after a fresh mind and an instant coffee:

Adding extra fields to FOSUserBundle / SonataUserBundle

Sadly, this isn’t really documented (at time of writing).

Adding new protected variables to your User.php entity will not actually create database entries when you try to do a doctrine:schema:update.

While one still needs to have the protected variables in this entity class, along with getters and setters, the actual creation work is within UserBundle/Resources/config/doctrine/User.orm.xml

Here is an example for adding a foreign key:

<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
        http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

    <entity name="Application\Sonata\UserBundle\Entity\User" table="fos_user_user">

        <id name="id" column="id" type="integer">
            <generator strategy="AUTO" />
        </id>

        <many-to-one field="client" target-entity="Myvendor\MyBundle\Entity\Client" orphan-removal="">
            <join-columns>
                <join-column name="client_id" referenced-column-name="id" nullable="1"/>
            </join-columns>
        </many-to-one>

    </entity>

</doctrine-mapping>

Ubuntu 12.04 LTS on Bytemark VM

If, like me, you can’t wait for Ubuntu 12.04.1 to be released, you can force an upgrade of your favourite OS OS.

sudo apt-get update;
sudo do-release-upgrade -d

If you are going from the previous LTS 10.04, then the -d is important. Otherwise there would be no upgrade to offer.

The upgrade process should go smoothly enough. Except for when it comes to the kernel.

Bytemark VM’s make use of kernels that sit outside of the VM itself.

I didn’t realise this until I tried to fix syslog doing this:

Jun 26 10:30:01 banana kernel: Cannot read proc file system: 1 - Operation not permitted.
Jun 26 10:31:02 banana kernel: last message repeated 1745888 times
Jun 26 10:32:03 banana kernel: last message repeated 1722636 times
Jun 26 10:33:04 banana kernel: last message repeated 1621724 times
Jun 26 10:34:05 banana kernel: last message repeated 1761707 times

Even if you update grub, it’ll be ignored. Instead, follow the instructions here: http://www.bytemark.co.uk/support/technical_documents/kernelchange?tags=VirtualMachine

At the time of writing, I chose 3.2.0-kvm-i386-20110111 as it’s fairly close to the kernel being used by other Ubuntu 12.04 machines I have.

Your mileage may vary, but I hope this helps somebody else with the same trouble.

Updating a WordPress database with new domain details

Further to my original quick db update queries, I found the need for a more in-depth approach.

A WordPress site my father works on has weekly backups, but he wanted to see that they actually worked.
To do so, I set up a subdomain vhost on my bytemark server and set about getting the back to work with it.

One of the most annoying/lazy/strange things about WordPress is that it uses serialised arrays within database fields. This makes a simple search and replace fail if you need to do anything more than update the two fields here.

This script works for the database set-up for my father. It may require further tweaks if additional plugins store absolute paths or URLs.

It also could do with a heavy dose of refactoring, but it works for my needs at this point in time :)

<?php
$argv = (isset($argv)) ? $argv : array(1 => 'wp3/wp-config.php');
if (!isset($argv[1]))
{
	die("Please tell me where wp-config.php is\n");
}

$oldURL = 'http://oldDomainName.com';
$newURL = 'http://backup.of.my.wordpress.site.com';

$oldPath = '/home/chem9598/public_html/';
$newPath = '/var/www/backup_wordpres_site/codebase/htdocs/';

$configFile = $argv[1];
include_once($configFile);

$db = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);

/*
* 1.1) wp_options - simple options
*/
echo "<br />1.1) wp_options - simple options: ";
$updateOptionsSql = "UPDATE wp_options SET option_value = REPLACE(option_value, '" . $oldURL . "', '" . $newURL . "') WHERE option_name IN ('siteurl', 'home');";
$updateOptionsRes = mysql_query($updateOptionsSql, $db);
if (!$updateOptionsRes)
	echo mysql_error($db) . "<br />";
else
	echo mysql_affected_rows ($db) . " rows affected<br />";


/*
* 1.2) wp_options - serialised array options
*/
echo "<br />1.2) wp_options - serialised array options: ";
$selectOptionsSql = 'SELECT * FROM wp_options WHERE option_value LIKE "%' . $oldURL . '%"';
$selectOptionsRes = mysql_query($selectOptionsSql, $db);
if (!$selectOptionsRes)
	echo mysql_error($db) . "<br />";

$options = array();
while($selectOptionsRes && $row = mysql_fetch_assoc($selectOptionsRes))
{
	$options[] = $row;
}

foreach ($options as $option)
{
	if (substr($option['option_value'], 0, 2) == 'a:')
	{
		$optionValue = unserialize($option['option_value']);

		updateArray($optionValue, $oldURL, $newURL);

		$option['option_value'] = serialize($optionValue);
		$updateOptionsSql = "UPDATE wp_options SET option_value = '" . mysql_escape_string($option['option_value']) . "' WHERE option_id = " . $option['option_id'];
		$updateOptionsRes = mysql_query($updateOptionsSql, $db);
		if (!$updateOptionsRes)
			echo mysql_error($db) . "<br />";
		else
			echo ".";
	}
}
echo "<br />";


/*
* 1.3) wp_options - file path
*/
echo "<br />1.3) wp_options - file path: ";
$selectOptionsSql = 'SELECT * FROM wp_options WHERE option_value LIKE "%' . $oldPath . '%"';
$selectOptionsRes = mysql_query($selectOptionsSql, $db);
if (!$selectOptionsRes)
	echo mysql_error($db) . "<br />";

$options = array();
while($selectOptionsRes && $row = mysql_fetch_assoc($selectOptionsRes))
{
	$options[] = $row;
}

foreach ($options as $option)
{
	if (substr($option['option_value'], 0, 2) == 'a:')
	{
		$optionValue = unserialize($option['option_value']);

		updateArray($optionValue, $oldPath, $newPath);

		$option['option_value'] = serialize($optionValue);
		$updateOptionsSql = "UPDATE wp_options SET option_value = '" . mysql_escape_string($option['option_value']) . "' WHERE option_id = " . $option['option_id'];
		$updateOptionsRes = mysql_query($updateOptionsSql, $db);
		if (!$updateOptionsRes)
			echo mysql_error($db) . "<br />";
		else
			echo ".";
	}
}
echo "<br />";


/*
* 2.1) wp_posts - guid
*/
echo "<br />2.1) wp_posts - guid: ";
$updatePostsSql = "UPDATE wp_posts SET guid = REPLACE(guid, '" . $oldURL . "', '" . $newURL . "');";
$updatePostsRes = mysql_query($updatePostsSql, $db);
if (!$updatePostsRes)
	echo mysql_error($db) . "<br />";
else
	echo mysql_affected_rows ($db) . " rows affected<br />";


/*
* 2.2) wp_posts - post_content
*/
echo "<br />2.2) wp_posts - post_content: ";
$updatePostsSql = "UPDATE wp_posts SET post_content = REPLACE(post_content, '" . $oldURL . "', '" . $newURL . "');";
$updatePostsRes = mysql_query($updatePostsSql, $db);
if (!$updatePostsRes)
	echo mysql_error($db) . "<br />";
else
	echo mysql_affected_rows ($db) . " rows affected<br />";


function debug($var)
{
	echo "<pre>";
	print_r($var);
	echo "</pre>";
}

function updateArray(&$array, $find, $replace)
{
	foreach ($array as $key => &$value)
	{
		if (is_array($value))
		{
			updateArray($value, $find, $replace);
		}
		else
		{
			$array[$key] = str_replace($find, $replace, $value);
		}
	}
}

PPTP tunnels and if-up.d

Current project requires a couple of VPN tunnels to be set up. An IPsec and a PPTP.
The IPsec will wait for another day, the PPTP is set up and ready to go.
One thing that wasn’t quite right with the tunnel though, is the static route created by PPTP missed out a large chunk of the server’s network.

Starting the tunnel sets up the routing rule of 192.168.100.111 to be sent to the tunnel.

This meant that if I wanted to get to 100.10, it wasn’t being sent.

The way around this was to add a new route: route add -host 192.168.100.10 dev ppp0

Works great from the CLI, nothing happens when added to /etc/network/interfaces or /etc/network/if-up.d/foobar.

Found out (trial and error) that it was trying to add the route as soon as the tunnel was created. This doesn’t work as the tunnel takes a few seconds to wake up.

Work around was to add a ‘sleep 5′ to /etc/network/if-up.d/foobar before the route command line.

Creating race conditions isn’t nice, but it works :(

Symfony 1.4 Doctrine 1.2 MS SQL Server

Web server: Linux (Ubuntu on my dev setup), Apache, PHP 5.3, Symfony 1.4, Doctrine 1.2.
Database server: Microsoft Windows 2008 Server, MS SQL Server

Trying to get Symfony to talk to the database server has been a painful experience for the last few days. But perseverance has paid off.

Lots of Googling with trial & error has resulted in actually achieving a development setup that will mirror the eventual production setup.

Short version:

  1. Follow the FreeTDS and ODBC setup instructions of http://jamesrossiter.wordpress.com/2011/03/08/connecting-to-microsoft-sql-server-using-odbc-from-ubuntu-server/
  2. Use the following in config/databases.yml
all:
  doctrine:
    class: sfDoctrineDatabase
      param:
        dsn: dblib:dbname=datasourcename;host=sqlserver;
        username: ###
        password: ###

In the above snippit, replace ‘datasourcename’ with whatever you used in /etc/odbc.ini and replace ‘sqlserver’ with the name used in /etc/freetds/freetds.conf & /etc/odbc.ini

It’s late and I’ve been struggling to get this working for some time. I may expand this entry in the future if required.

References and insperation:
1) http://blog.acjacinto.com/2011/11/compiling-php-with-mssql-servers-native.html
2) http://www.microsoft.com/download/en/details.aspx?id=28160
3) http://jamesrossiter.wordpress.com/2011/03/08/connecting-to-microsoft-sql-server-using-odbc-from-ubuntu-server/
4) http://trac.symfony-project.org/wiki/HowToConnectToMSSQLServer

 

Google calendar in Mozilla Thunderbird on Ubuntu 11.10

Via the Ubuntu Software Centre:

  1. Search for thunderbird
  2. Click on the search result “Thunderbird Email” and then on the “More Info” button
  3. Enable at least the “Calendar Extension for Thunderbird – Google Calendar support (xul-ext-gdata-provider)”
  4. Install the add-ons
  5. Open your Google Calendar in your web browser
  6. In the left-hand column, under “My calendars”, hover over the calendar of choice and click the down arrow that appears after the calendar name
  7. Select “Calendar settings”
  8. Close to the bottom of the page will be the “Calendar ID” (in my case it is my full email address. Make a note of this ID.
  9. Start up Thunderbird upon completion.
  10. File -> New -> Calendar
  11. Select “On the Network” and click Next
  12. Select “CalDAV”
  13. In the Location field enter: https://www.google.com/calendar/dav/calendar.id.noted.in.point.8/events
  14. Click Next then enter a name for the calendar and set an email account against it
  15. When prompted, enter your username and password for accessing this calendar