Monday, November 4, 2013

Installing Zabbix on Jelastic

For months, I have looked over several paid and open source server monitoring products, and have seem to landed on Zabbix. It's an enterprise ready, fully open source, fully free, monitor ANYTHING platform. As I have been evaluating Jelastic as a future host for some personal projects, I decided it would be fitting to attempt an installation there. Below you will find the steps I have taken to setup and install Zabbix on the Jelastic platform.

Deploy Zabbix

To kick things off, you need to start by creating a new environment. Log in with your Jelastic credentials. While in the Jelastic dashboard, click the Create environment button. In this case, we only need a VDS and a MySQL* instance. Enter an Environment name and click Create. (*Note for the time being, you may need to enable a public IP in order for the Zabbix server to connect to the database. This will hopefully be corrected soon.)

Once the environment is deployed, you will receive an few emails which include your authentication information for your various servers. Starting with your VDS, you'll need your Login (most likely root), Password, and Public IP. I have found using a standard terminal is much faster than using the web terminal. SSH into your VDS using a command similar to this:

Of course, you'll need to replace the x's with the actual IP address assigned to your VDS instance. Once connected, you'll need to enter your secure password. From there, its time to install the Zabbix server:
# rpm -ivh
# yum install zabbix-server-mysql zabbix-web-mysql
You will need to type 'y' a few times to agree to install the various pieces of the application, but in a few moments, the base of the Zabbix server will be installed.

Initialize the database

While still in the VDS terminal, setting up the database is easy. You will need the Access URL, Login, & Password. Enter the following to get the database setup:

# mysql -h{{Access URL}} -uroot -p{{Password}}   
mysql> CREATE DATABASE zabbix CHARACTER SET utf8 COLLATE utf8_bin;
mysql> CREATE USER 'zabbix'@'%' IDENTIFIED BY '{{secure password}}'
mysql> GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'%';
mysql> EXIT

If you want to be a bit more secure, feel free to replace % with the IP address of your VDS server. That will limit the access to a single IP address. Next, we'll need import the .sql scripts to initialize the database.

# mysql -h{{Access URL}} -uroot -p{{Password}} zabbix < /usr/share/doc/zabbix-server-mysql-2.0.8/create/schema.sql
# mysql -h{{Access URL}} -uroot -p{{Password}} zabbix < /usr/share/doc/zabbix-server-mysql-2.0.8/create/images.sql
# mysql -h{{Access URL}} -uroot -p{{Password}} zabbix < /usr/share/doc/zabbix-server-mysql-2.0.8/create/data.sql

That's it, your base database is now setup and ready to go.

Configure the server

Back on the VDS via the shell (# ssh, you'll want to edit the zabbix_server.conf file with the following settings. DBHost will correspond the Access URL included in your confirmation email:
# vi /etc/zabbix/zabbix_server.conf
DBHost=mysql-{{Your server name}}
DBPassword={{Your secure password}}

Then, start the Zabbix server:
# service zabbix-server start
Now configure PHP by editing the zabbix.conf file. You'll need to validate/adjust the following settings... Of course adjusting the timezone to match yours:
# vi /etc/httpd/conf.d/zabbix.conf
php_value max_execution_time 300
php_value memory_limit 128M
php_value post_max_size 16M
php_value upload_max_filesize 2M
php_value max_input_time 300
php_value date.timezone America/Denver

Finally, start the http server:
# service httpd start 

Configure the web interface

You are all set and ready to launch the server! Point your browser at, replacing the x's with your IP address, of course. If all went well, you'll see the following Welcome page. Click the Next button.

Here you will see the results of the pre-requisites check. You should have a page of OK's. Click Next.

On the Database configuration page, the Database host will be the Access URL received in the email you received from Jelastic. You'll use zabbix as the Database name and User, along with the secure password you setup. Press the Test connection button.

If all went well, you will get a nice little OK over the Test connection button. Click Next.

The default settings on the Zabbix server details page should be fine. Click Next. Click Next on the pre-installation summary as well. Finally, Click Finish

There you have it. Using the IP address of the VDS, you can now log in with the credentials UN: Admin (case sensitive) and PW: zabbix

Of course you are going to want to change the password right away.

All that is left is installing the Zabbix Agents on your Jelastic instances. For now, it seems the only way to accomplish that will be through the use of their VDS instances. Perhaps in a future release, this could be a plugin to enable the use of their standard server type instances. Regardless, I'll leave the task of installing the Zabbix Agents to a future post.

Thursday, October 31, 2013

Getting started with Apigility


During ZendCon 2013, I was excited to hear about a new toolset called Apigility that the folks of Zend Framework have just released. It is an API toolset built on top of ZF2. The exciting thing is that this Apigility takes care of all the API dirty work for us. HAL content, error handling, JSON structure, and so much more!

What I find funny about this toolset, from an implementation standpoint, is that it is not that much different from what we have tooled together ourselves on top of ZF2. Whats better is, we had yet to implement HAL and our error handling logic was still sub-par. So testing this toolset is exciting, in that its another portion of our code that I do not need to implement (well... finish implementing) and maintain.

My focus on this Apigility tutorial will be primarily from the perspective of a Code-Connected REST API's. While the Database-Connected REST API's are fantastic, our internal approach to development has shifted to an API First development strategy. This design decision is implemented by first creating an internal class based API, then leverage Apigility to greatly simplify the creation of a public facing API.

Getting Started - Installation

So, lets dive right in! Before you can begin playing with Apigility, you need to "install" it. The makers of this toolset were kind enough to implement the entire structure and logic flow in just code. This means, no databases to setup, no proxies to configure, no complex routing to setup. Simply bring in the code that is needed and you are ready to go!

There are a number of methods you could use to bring down the code. For me, the simplest was running a Composer script. This requires you have composer installed, but since I did... Move to the directory you wish to place your new API and execute these commands from your favorite terminal:
url -s | php -- 
php composer.phar create-project -sdev --repository-url="" zfcampus/zf-apigility-skeleton /var/www/apigility
For more installation options, check out the README on Apigility's GitHub account. These alternative options include both a downloadable Tarball and a Git clone option.

Next, you will want to place your local instance of Apigility into development mode. This will give you access to all of the nifty tools that streamline the scaffolding of your API. A couple things to keep in mind... You will NOT want to leave your Apigility instance in development mode for your production uses as it exposes many of the configuration options at the hart of your new API. Also, once you have a solid understanding of the structure and makeup of Apigility, you honestly will not need to use the admin interface all that often... of course it does handle a lot of the back end wiring that is needed, so it may be handy to have available, perhaps when you want to iterate the version of your API. To enable development mode, simply type this into your terminal:
php public/index.php development enable
Now we just need to initialize our new application. This can be done by modifying your virtual hosts file or simply spinning up a server using the new to PHP 5.4 built-in php web server. Simply execute this command in your terminal:
php -S 0:8080 -t public/ public/index.php
You can now access Apigility by pointing your web browser at http://localhost:8080!

Installation Summary

Below is the exact code I am using to install Apigility on my local linux box. This is a summary of the above commands, plus a few supplemental commands needed for my specific use case. My webroot is located at /var/www. You may need to make adjustments to this for it to work for you as well.

cd /var/www
mkdir apigility
curl -s | php --
php composer.phar create-project -sdev --repository-url="" zfcampus/zf-apigility-skeleton /var/www/apigility 
rm composer.phar 
cd apigility
php public/index.php development enable
php -S 0:8080 -t public/ public/index.php

Creating Your First API

Once you point your web browser at http://localhost:8080, you will be presented with a welcome screen. Simply hit the Get Started! button:

Next, you'll hit the Create New API button:

Type "Compnay" in the text box then click the Create API button:

Then click the REST Services link:

Followed by the Create New REST Service button.

Here we will name our first REST service. Lets make one that will return a list of employees, along with some basic employee information. Select the Code-Connected tab, enter Employees as the REST Service Name, and click the Create REST Service button.

Your new API structure is now built and ready to be populated with code.

If you were to make a request from the API now (http://localhost:8080/employees), it would return an error about the GET method not being defined.

So lets define the methods for our new API. We'll start by creating the item entity. We'll use the fields employee_id, name, title, & base_salary. Set the class vars as private, add a getter method for each, and the constructor will set each based on an optionally passed in array. We will do all of this in the module/Company/src/Company/V1/Rest/Employees/EmployeesEntity.php file.
namespace Company\V1\Rest\Employees;
class EmployeesEntity{
  private $employee_id;
  private $name;
  private $title;
  private $base_salary;
  public function __construct(array $entity = null){
    if($entity !== null && is_array($entity)){
      foreach(array_keys(get_class_vars(__CLASS__)) as $key){
           $this->$key = $entity[$key];
  public function getEmployeeId(){
    return $this->employee_id;
  public function getName(){
    return $this->name;
  public function getTitle(){
    return $this->title;
  public function getBaseSalary(){
    return $this->base_salary;
Next, we need to edit the module/Company/src/Company/V1/Rest/Employees/EmployeesResource.php file. Normally, you would interface directly with your internal API classes. For the sake of this simple implementation, we will add a getData() method that will return an array of employee information:
private function getData(){
  return array(
    1 => array(
      'employees_id' => 1,
      'name' => 'John Doe',
      'title' => 'Cat Behavior Consultant',
      'base_salary' => 42000
    2 => array(
      'employees_id' => 2,
      'name' => 'Jane Poe',
      'title' => 'Cheif Bottlewasher',
      'base_salary' => 37000
    3 => array(
      'employees_id' => 3,
      'name' => 'Robert Roe',
      'title' => 'Town Crier',
      'base_salary' => 14000
    4 => array(
      'employees_id' => 4,
      'name' => 'Mark Moe',
      'title' => 'Creative director, Unicorn Division',
      'base_salary' => 73000
    5 => array(
      'employees_id' => 5,
      'name' => 'Brett Boe',
      'title' => 'Executive Moonshiner',
      'base_salary' => 58000
Next, we need to modify the fetch method to retrieve the correct employee entity based on the passed employee_id. In this case, we simply:
public function fetch($id){
    return new EmployeesEntity($this->getData()[$id]);
    return new ApiProblem(405, 'Invalid id passed');
Then the fetchAll method. We will get the full dataset and pass it into an ArrayAdapter. We will then pass the adapter into the EmployeesCollection. While it's true we have not implemented any code in the EmployeesCollection, the fact that it extends Zend Paginator gives us the functionality we need to afford API pagination.
public function fetchAll($params = array()){
  $adapter = new ArrayAdapter($this->getData());
  $collection = new EmployeesCollection($adapter);
  return $collection;
Since we are using the ArrayAdapter in the fetchAll method, we'll need to include the ArrayAdapter at the top of the file:
use Zend\Paginator\Adapter\ArrayAdapter;

Finally, we need to define a strategy for hydrating the EmployeesEntity. In this case, we simply need to use the ClassMethods hydrator. In the module/Company/config/module.config.php file, locate the zf-hal -> metadata_map -> Company\\V1\\Rest\\Employees\\EmployeesEntity section and add 'hydrator' => 'ClassMethods', directly after the element rout_name like this:
'zf-hal' =>
  array (
    'metadata_map' =>
    array (
      'Company\\V1\\Rest\\Employees\\EmployeesEntity' =>
      array (
        'identifier_name' => 'employees_id',
        'route_name' => '',
        'hydrator' => 'ClassMethods',

That should be it! You now have a working Apigility Api. In my next post, I'll dig a bit more into tying this directly into your internal Api class structure, as well as some tips on easing the job of interacting with your new API using a great Chrome extension Advanced REST Client.

Monday, August 12, 2013

Speed up your browser with a RAMDisk.

So I stumbled upon this blog post the other day claiming to speed up your browser by 20%... That seems like a lofty claim, but who am I to balk at a potential 20% savings!

After reading the post, I knew I didn't want to use a utility to create a RAMDisk, as I know how easy it is in Linux! I also didn't like the idea of having to update every shortcut and context just to get Chrome working. So, in the end, this is a hybrid of Sebastian's approach, designed for the Linux power user.

I will give this word of warning though. We will be editing a couple critical system files here, so use extreme caution!

Create your RAMDisk:
For me, I was actually able to skip this step. I have already created a RAMDisk while optimizing my SSD. But for the sake of everyone reading, I'll spell out the steps here.

First things always first... backup the file you are about to edit:
sudo cp /etc/fstab /etc/fstab.bak
Now, lets open it:
 sudo gedit /etc/fstab
At the very bottom of the file, add a new line and insert the following:
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0
Then, just save and restart!

Your /tmp directory is now living on it's very own RAMDisk! Enjoy the speed benefits! Now, lets get on to the browsers.

Firefox is comparably easy. A simple configuration change and you are all set. In the address bar, Type the following:
You may need to click on a button with the text "I'll be careful, I promise!" before proceeding.

Next, right click the body and choose: New -> String.

When it asks you for the preference name, enter:
Click OK and it will ask you for the value, enter:
Don't worry, the firefox directory will be created for you automatically. Restart Firefox.

Chrome is a bit trickier... There are not any general configuration files to get chrome to run on the RAMDisk. Most people suggest you append your chrome shortcuts with the option: --disk-cache-dir="/tmp/chrome". My problem with this is that it is not a holistic solution. What happens if you miss one of potentially several links? What happens if you launch it from the command line? The solution is simple... Symlinks! In your command line, type:
sudo gedit /etc/rc.local
And place the following before "exit 0":
#move chrome cache to ramdisk
rm -rf ~/.cache/google-chrome/
mkdir -p -m 777 /tmp/chrome
ln -s /tmp/chrome ~/.cache/google-chrome
Restart your computer.

While I don't have any concrete data, I can tell you that everything feels faster! Load time of the browser is lightning fast! Clicking the back button is much faster (loading the history from ram instead of your harddrive). If anyone has ideas on running, even simi-scientific tests on this, I'd be happy to take that on.

Side effects?
As you may or may not know, RAMDisks are volatile. This means, when you computer restarts, the data held in memory is erased. Anything your browser stores in these cache folders will be lost with each computer restart. I came across one post in my research (I'm sorry, I haven't been able to find it again to link here) that mentioned this can slow down re-visits to you favorite sites by having to re-cache the incoming files, every time you restart. This is not a problem for my tower, as I rarely restart, and I have a UPS which prevents *most* power related restarts. For my laptop, that might be another story. I'll keep you posted if I end up disabling these options in the future.

Another potential concern is loss of ram availability. For me, I have 6GB of ram on my laptop and 8GB on my desktop. While I have on rare occasion come close to that limit, even under heavy utilization, I have still not reached pagefile territory. Besides, the beautiful thing about tmpfs is that is only uses what it needs. Also, I do everything from the browser these days, so any increase in speed there is a win for me!

All of this has got me thinking... what else would benefit from being moved to a ramdisk? I know scratch disks for programs like gimp and other audio/video/rendering/imaging software suites would all benefit, but what else do you think would make a difference?

Monday, May 27, 2013

Essential programs for my Lenovo Z570 with Ubuntu

Leading off from my last blog post about Optimizing Ubuntu 13.10 for the Lenovo Z570, I thought I would talk about what I consider Essential programs & tools in Ubuntu, especially for my laptops.

1. Psensor

First and foremost is Psensor. This is an excellent program for monitor device temperatures. You can even set it to warn you if any of your devices (CPU, GPU, Motherboard, etc.) exceed a set temperature. This tool has not only been invaluable in monitoring my system, but also diagnosing issues. Click here to install Psensor.

2. Indicator-cpufreq

Next, indicator-cpufreq is fantastic for not only viewing your laptop's current processor load, but also limiting it appropriately. So if you are on the go and would like to conserve some power, you can switch it down to powersave. If you are plugged in and are doing something processor intensive, you can set it to performance, or even "turbo". Click here to install indicator-cpufreq.

3. Ubuntu-tweak

Ubuntu tweak is a great little application that is all about making it easier to tweak the settings of Ubuntu and Unity, as well as install many popular titles, like Chrome, that you would otherwise have to search for and install manually. This is a must have for making Ubuntu run the way you want it to! Installing is as easy as adding a ppa and running an install script.
sudo add-apt-repository ppa:tualatrix/ppa
sudo apt-get update
sudo apt-get install ubuntu-tweak

4. Oracle Java 7

Oracle Java vs OpenJDK is one of the great linux debates. For most people, installing Open Java is as simple as clicking on this link for OpenJDK 7 and this link for IcedTea browser plugin. For Oracle Java, it takes a few extra steps to pull it off. You can either manually download and install Oracle Java, or, take advantage of webupd8team's PPA.
sudo apt-get purge openjdk*
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer

5. Other programs

I am confident there are more I am not thinking about at the moment. I'll update this post as I remember them!

Setting up a Postgresql Database Adapter with ZF2

Setting up Database access with Zend Framework 2 can feel a lot more intimidating then it really is. I partially blame the confusing nature of complex documentation along with the lack of good code samples. I am hoping to help with the second part of this equation.

Assuming you are using an MVC structure and placing most of your code in the module structure, you may find that centralizing your database connections is not only essential but also helps in reducing code redundancy. Thankfully, once you understand some of the core features of the ZF2 structure, overcoming obstacles like dependency injection, adapter factories, and global database access can become much less daunting.

So lets dive right in!

The first step to global database domination is setting up the global configurations. In your project's config/autoload directory open or create the file global.php. As with most other ZF2 configuration files, you will be simply returning an array of settings. The first is the "db" configuration array which will look something like this:
'db' => array(
    'driver' => 'Pdo_Pgsql',
    'database' => 'uHackedMe',

The "driver" parameter represents the database driver you plan on using. Official options include: Mysqli, Pgsql, Sqlsrv, Pdo_Mysql, Pdo_Sqlite, and Pdo_Pgsql. The other settings should be pretty self explanatory. For the security conscious among us, you can always implement this logic outside your version control system and include the file. In my case, I simply return include('../../mySecretDbConfigFile.php');

The next step is wiring up the dependency injection that will prevent you from having to manually step through all of the hoops every time you want to run a simple query. That should look something like this:
'service_manager' => array(
    'factories' => array(
        'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',


Essentially, this is setting up a database adapter factory that will pull in it's depended resources based on the db configuration settings, and store it all in the service manager for your happy consumption later on. It is amazing how much these few lines of code help simplify the whole process!

Now depending on your desired level of data abstraction,  you can easily create a table model that extends Zend\Db\TableGateway\AbstractTableGateway or simply access the Adapter you created earlier directly in your model. For the first option, you will want to define a second factory to automate the injection of the Adapter into your table model. You can do this by taping into the getServiceConfig() method of your Module.php files like this:
public function getServiceConfig(){
    return array(
        'factories' => array(
            'YourModule\Model\YourTableModel' => function($serviceManager){
                return new YourTableModel($serviceManager->get('Zend\Db\Adapter\Adapter'));

At this point, inside your table model file, you now have direct access to the database as easily as this:
public function getRecord($id) {
    $row = $this->select(array('id' => (int) $id))->current();
    if (!$row){
        return false;
    return array(
        'id' => $row->id,
        'name' => $row->name,
        'created' => $row->created,


Finally, wherever you are accessing your table model (inside a controller or even another model), just use the service manager to get YourModule\Model\YourTableModel and your data will await you!
$serviceManager = $this->getServiceLocator();
$yourTableModel = $serviceManager->get('YourModule\Model\YourTableModel');
$yourRecord = $yourTableModel->getRecord($recordId);

If creating table gateways is simply not your cup of tea, you can skip the whole AbstractTableGateway step and simply add this into your Model:
$serviceManager = $this->getServiceLocator();
$adapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
$result = $adapter->query('SELECT * FROM `record` WHERE `id` = ?', array($recordId));

When you first start developing like this, it does seem like a whole lot of setup just to get a basic database connection established. But once you understand the process, tools like the serviceManager & pre-baked factory classes sure do make life so much easier!

Sunday, May 26, 2013

Installing & Optimizing Ubuntu 13.04 on the Lenovo Z570

I love my laptop. When purchased, it was a powerhouse of a laptop at a great pricepoint. The trouble with it, back when I first got it, Ubuntu 11.10 did not have good support for this laptop! That prompted me to write my original article: Install Ubuntu 11.10 on Lenovo Z570.

A lot has changed since then, along with 3 versions of Ubuntu. So here is my updated, revised, and even better version of my original installation guide. The great news is that Ubuntu 13.04 has great support for EFI and fully supports the built in WiFi card.

Support for Optimus is still not available out of the box, but tools have made it easier to take advantage of power savings AND 3D graphics.

Also, if you are interested in speed, you MUST replace the old-school HDD with a fast SSD! It was the best $100 upgrade I could have ever spent!

This guide will take you from 0 to GO, optimizing Ubuntu to help you get the most out of your Z570! I cannot take credit for all of the information found here, most of it is information I have found and compiled from many sources over the years. I'll site any sources I still have references for. Finally, as a standard disclaimer, I cannot take responsibility for any problems you might have. These are simply the best options I have found through LOADS of trial and error... More error than trial... LOL.

1. Install Ubuntu 64-bit

I am not going to go into too many details here, as there are countless tutorials for installing Ubuntu on your computer. My only recommendation is that you choose the torrent download, as you will get your .iso SO much faster. Here is a current link for Ubuntu 13.04 64-bit torrent. Here is a page that will have the latest version available. You will also want to check the md5 of your ISO to make sure there are no issues before you turn it into a DVD or USB installer.

2. Install all updates

Launch the "Software Updater" from the unity task bar and install all updates. There will be a lot of updates! On my system, it took about 10 minutes. I recommend that you restart your computer at this point. It may not be required, but, taking only 20 seconds, it's worth the precaution!

3. Get your video card working

If your z570 is like mine, it has Optimus support. Meaning, it has both an integrated Intel video chip, as well as a dedicated nVidia GeForce video card. Out of the box, Ubuntu still does not support the Optimus functionality out of the box. But with the help of a program called Bumblebee, we can get the 3d video support we want via the nvida card, and still keep the battery life we need by using the intel card.

There are two ways to install bumblebee, manually via the terminal, with a bunch of commands, or the easy way, using the Bumblebee Configurator GUI. To install the configurator, simply execute the following in the terminal (Ctrl+Alt+T):
sudo add-apt-repository ppa:alessandrofac93/bumblebee-config-gtk-dev
sudo add-apt-repository ppa:ubuntu-x-swat/x-updates
sudo add-apt-repository ppa:bumblebee/stable
sudo apt-get update
sudo apt-get install bumblebee-config-gui
Then launch the application using sudo:
sudo bumblebee-config
Click the obnoxiously large "Install Bumblebee" button. It will download all of the needed files and install it all for you. If you are ready to configure Bumblebee, simply press the configure button and you'll have all the settings you need. Configuring Bumblebee is outside the scope of this tutorial. I have had very good luck with the default settings.

Restart your computer again. This will ensure your video card drivers are all running correctly.

4. If you have an SSD, optimize it!

Let me reiterate what I said in the introduction. If you want to get the most out of Ubuntu and your Lenovo Z570, or any computer for that matter, invest in a good SSD! It was the best computing choice I've made since switching to Ubuntu in the first place! I now run SSD's on all of my computers. On my desktop, where I need more space, I mount / on a 64GB SSD and /home on a 1TB HDD. You get the best of both worlds!

As far as optimizing your SSD, I found a great guide over at HowToGeek, so I won't try to reinvent the wheel here.

There were a couple things I did notice were missing from the HowToGeek article.

Reduce disk swappiness:
sudo cp /etc/sysctl.conf /etc/sysctl.conf.bak
sudo gedit /etc/sysctl.conf
Then add the following to the last line:

5. Add Multi-media support

Open the Software Center and search for "Ubuntu restricted extras" and install. Or, just click this link.

Run the following to enable the playback of protected DVD's:
sudo /usr/share/doc/libdvdread4/

6. Make a backup image of your squeaky clean install!

Now that you have gone through all of the trouble to get your clean install setup and running smooth, this would be a great opportunity to take a snapshot of your system. My favoured tool is Clonezilla Live. The process is simple, it took about 20 minutes, and is only consuming 2GB of disk space. The best part is,

Closing thoughts

There are lots of other steps I take to "setup" my Ubuntu install, but these are the ones I feel are most widely applicable. What other tips and tricks are you using on you Lenovo Z570?

Sunday, January 20, 2013

Resetting your check engine light

So we bought a 2010 Chrysler Town and Country a little over a year ago. Having run out of our free oil changes, I decided to take matters into my own hands. These days, it seems to cost $35 to get your oil changed, just about anywhere you go. OR, you can buy a good filter and fully synthetic oil for the same price. And, it only takes about 20 minutes from start to finish, once you know what you are doing. The only problem is, after changing your own oil, how in the world do you get that pesky "change oil" message to go away?

As it turns out, resetting the oil service light on the 2008, 2009, 2010 and 2011 Chrysler Town and Country is super easy!

1. Turn the ignition to the "run" position without actually turning the car on.
2. Within 10 seconds, fully depress and release the gas pedal 3 times.
3. Turn the car off and then start the engine to verify the change oil message is gone.

There you have it! You can now take control of your own car maintenance and save some money while you are at it!

Just keep in mind, resetting the check oil indicator is not a substitute for not keeping accurate service records, nor is it a way to get away with not changing your oil! So follow your manufacturer's recommendations (mine is every 5000 miles) and keep good records!