Tuesday, 6 September 2016

Step by step Ansible and Vagrant quick start tutorial

I am learning Ansible and Vagrant, and had a lot of issues getting things running on Ubuntu 14.04.

I did manage to get a simple playbook working with Vagrant.  Hopefully, the entries below will save you some hair pulling and cursing.

For a quick intro of what Ansible can do, watch this video https://www.ansible.com/get-started

First things First: Install Vagrant

I want to use Ansible to set up nginx on a Vagrant VM.  So first, we need to install both Ansible and Vagrant.

In order to run Vagrant, you will need to install a virtual machine provider, such as virtualbox.

You can install virtualbox with:
$ sudo apt-get install virtualbox 
On my 14.04 machine, this got me virtualbox 4.3.36.  It is not the latest (5.1), but it seems to work fine.

You can download the latest Vagrant from: https://www.vagrantup.com/downloads.html

Then to install:
$ sudo dpkg -i vagrant_1.8.5_x86_64.deb
The Vagrant quick start says:
$ vagrant init hashicorp/precise64
That didn't work for me, I found I had to add the full precise64 virtualbox image's URL:
$ vagrant box add precise64 https://vagrantcloud.com/hashicorp/boxes/precise64/versions/1.1.0/providers/virtualbox.box

Install Ansible

To install the latest Ansible on Ubuntu 14.04, I had to add some additional repositories.
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible 

This gets me the latest Ansible:
$ ansible --version
ansible 2.1.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides

Start up Vagrant

Let's bring up your Precise VM and see if the basics of Vagrant are working.
$ vagrant init precise64
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
Bring up the VM:
 $ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise64'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1473215023932_83230
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2200
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 4.2.0
    default: VirtualBox Version: 4.3
==> default: Mounting shared folders...
    default: /vagrant => /tmp/test
Let's see if we can get into the VM:
$ vagrant ssh
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
New release '14.04.5 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Welcome to your Vagrant-built virtual machine.
Last login: Fri Sep 14 06:23:18 2012 from 10.0.2.2
vagrant@precise64:~$
Excellent!

Now let's see if we can SSH into the VM the normal way.  Note that in the output of the "vagrant up", it told us the SSH port for this VM is 2200.  The default password for the "vagrant" user is, you guessed it, "vagrant"! (no quotes of course)
$ ssh vagrant@127.0.0.1 -p 2200
The authenticity of host '[127.0.0.1]:2200 ([127.0.0.1]:2200)' can't be established.
ECDSA key fingerprint is 11:5d:55:29:8a:77:d8:08:b4:00:9b:a3:61:93:fe:e5.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[127.0.0.1]:2200' (ECDSA) to the list of known hosts.
vagrant@127.0.0.1's password:
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
New release '14.04.5 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Welcome to your Vagrant-built virtual machine.
Last login: Wed Sep  7 02:29:18 2016 from 10.0.2.2
There we go, now we can SSH into the VM directly, we are ready for Ansible.

Getting Ansible to talk to the VM

In order to get Ansible to access the VM, you will need to create a hosts or inventory file telling it what user, port, IP to access the VM.  So use your favourite editor and make a file "hosts" with the following contents:
[vagranthost]
127.0.0.1 ansible_port=2200 ansible_user=vagrant ansible_password=vagrant 
Now, you can put this into your global /etc/ansible/hosts file, but having it locally gives you more options down the road.  Consider, if you have all your hosts in the global file, and then you use the "hosts: all" command in an Ansible playbook, it will literally run against ALL the hosts defined in that global file.  The downside of having separate hosts (or inventory) files is you do have to always use the "-i <filename>" running any Ansible command.  Otherwise Ansible will default to only looking at hosts defined in the global hosts file.

Note: Please do not put your password into your hosts file.  I've done it here only because this is just a test VM's password.

Now that we have the hosts file, let's do a ping test:
$ ansible vagranthost -i hosts -m ping
127.0.0.1 | SUCCESS => {
    "changed": false,
    "ping": "pong"
} 
Voila!

Simple Playbook

Let's make a simple playbook that does a ping, updates apt cache, and then installs nginx, copies over a hello world html file, and starts nginx.  Again, use your favourite editor and create playbook.yaml with the following contents:

---
- hosts: vagranthost
  tasks:
  - name: test ping
    ping:

  - name: apt update
    become: yes
    apt: update_cache=yes

  - name: install curl
    become: yes
    apt: name=curl state=latest

  - name: install nginx
    become: yes
    apt: name=nginx state=latest

  - name: start nginx
    become: yes
    service: name=nginx state=started

  - name: copy index
    become: yes
    copy: src=hello.html dest=/usr/share/nginx/www/index.html
Let's also make hello.html in this same directory:
<html>
<body>
<h1>Hello world from inside the vagrant vm!</h1>
</body>
</html> 

Run the Playbook!

Moment of truth, let's run this against our VM:
$ ansible-playbook -i hosts playbook.yaml

PLAY [vagranthost] *************************************************************

TASK [setup] *******************************************************************
ok: [127.0.0.1]

TASK [test ping] ***************************************************************
ok: [127.0.0.1]

TASK [apt update] **************************************************************
ok: [127.0.0.1]

TASK [install curl] ************************************************************
changed: [127.0.0.1]

TASK [install nginx] ***********************************************************
changed: [127.0.0.1]

TASK [start nginx] *************************************************************
changed: [127.0.0.1]

TASK [copy index] **************************************************************
changed: [127.0.0.1]

PLAY RECAP *********************************************************************
127.0.0.1                  : ok=6    changed=4    unreachable=0    failed=0
 
Let's check that nginx is actually started and serving the hello world homepage by using curl.
$ ansible vagranthost -i hosts -m shell -a "curl -s http://127.0.0.1"
127.0.0.1 | SUCCESS | rc=0  
That's nice, but how do we access this nginx server hosted inside the VM?  Simple, let's make Vagrant forward that port.

Edit Vagrantfile and add Ansible playbook and port forward
config.vm.network :forwarded_port, guest: 80, host: 12345
You can put this anywhere in between "Vagrant.configure .... end".

Now do a vagrant reload to restart the VM.  After the VM restarts, you can see the hello world page from your localhost by visiting:
$ curl -s http://localhost:12345
<html>
<body>
<h1>Hello world from inside the vagrant vm!</h1>
</body>
</html>
Try visiting http://localhost:12345 from your browser, hurray!

Even faster way, using Vagrant Provisioning

So far, we've set up this VM by using Ansible directly.  But Vagrant actually can do much of this behind the scenes.  Add the following to your Vagrantfile, again you can put this anywhere in between "Vagrant.configure .... end".
config.vm.provision "ansible" do |ansible|
    ansible.playbook = "playbook.yaml"
end
Also change the playbook.yaml's hosts value from vagranthost to all:
$ head playbook.yaml
---
- hosts: all
  tasks:
  - name: test ping
    ping:

  - name: apt update
    become: yes
    apt: update_cache=yes

Destroy the old VM:
$ vagrant destroy -f
==> default: Forcing shutdown of VM...
==> default: Destroying VM and associated drives...
Now, when you ask Vagrant to up the machine, it will also run the Ansible playbook!
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'precise64'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_default_1473218743683_49067
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 80 (guest) => 12345 (host) (adapter 1)
    default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2200
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Remote connection disconnect. Retrying...
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 4.2.0
    default: VirtualBox Version: 4.3
==> default: Mounting shared folders...
    default: /vagrant => /tmp/test
==> default: Running provisioner: ansible...
    default: Running ansible-playbook...

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [default]

TASK [test ping] ***************************************************************
ok: [default]

TASK [apt update] **************************************************************
ok: [default]

TASK [install curl] ************************************************************
changed: [default]

TASK [install nginx] ***********************************************************


TASK [start nginx] *************************************************************
changed: [default]

TASK [copy index] **************************************************************
changed: [default]

PLAY RECAP *********************************************************************
default                    : ok=7    changed=4    unreachable=0    failed=0

Tada!  Great success!

You don't have actually to destroy the VM actually, you can run vagrant provision at any time, and as many times as you want.

$ vagrant provision

==> default: Running provisioner: ansible...
    default: Running ansible-playbook...

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [default]

TASK [test ping] ***************************************************************
ok: [default]

TASK [apt update] **************************************************************
ok: [default]

TASK [install curl] ************************************************************
ok: [default]

TASK [install nginx] ***********************************************************
ok: [default]

TASK [start nginx] *************************************************************
ok: [default]

TASK [copy index] **************************************************************
ok: [default]

PLAY RECAP *********************************************************************
default                    : ok=7    changed=0    unreachable=0    failed=0

Final Tips and Lessons Learned


  1. You can always use "-vvvv" in an Ansible command to get really really verbose debug output to see behind the scenes what is happening.
  2. The Ansible commands "become_user" and "become_method" don't do anything unless you have "become: yes" in the playbook (either that task, or globally)!
  3. Some Ansible commands are not backward compatible, for the many tutorials on the web, always note the version of Ansible they are running.  The above is for Ansible v2.1.1.0, Vagrant 1.8.5, Virtualbox 4.3.36_Ubuntur105129 on Ubuntu 14.04.
  4. Ansible and Vagrant are awesome and very powerful, but there are a lot of growing pains and the devil is always in the details.  I hope this entry has helped you in some small way, cheers!


Saturday, 14 May 2016

Volkswagen, do you get customer service at all?

In the summer of 2015 my husband and I bought a certified 2012 VW Golf TDI.  It is great on gas, and has lots of torque which makes it fun to drive, not to mention it is very practical and can hull a tonne of stuff.  Then in the fall of 2015, the VW Dieselgate happened.  In the following months, my coworkers made fun of me and accused me of being a planet hater and a squirel killer, because of my VW TDI's terrible terrible emission lies.

Like many unfortunate TDI owners, I was waiting to see what VW was going to do with our now unresellable and potentially uncertifiable cars.

Sometime in the Winter of 2015, I get a letter from my VW dealership, "You've been specially selected to receive a $1000 credit at this particular VW dealership!"  Wow, how nice of them I thought.  I can get at least get some winter tires for free I guess.  Then I read the fine print, which told me that I can only use 10% of this card at a time towards my bill at the dealership.  So if I spend $1000, I'd get $100 off, and have to pay $900 out of pocket.  That means in order to get the full amount of credit on this card, I'd have to spend $9000 at this dealership!  Wow, what a great deal!  Thanks VW!

By the time I got this offer, I'd already heard of rumours of US TDI owners may be getting $5K back and what not.  So when I got this offer and saw the deal it presented us, I was pretty disgusted.  I thought VW Canada was really screwing us over on this one.  But the Internet didn't explode with anger, so I soon realized this must have been just my particular VW dealership trying to make me feel better.  Haha, with an offer that good, I wish they didn't "specially" select me at all!

Then, about a month ago, I got the official VW Canada offer, $500 credit for use at any VW dealership, and $500 on a prepaid credit card.  Alright, it isn't $5K, but I guess it's better than nothing.  I signed up for it online, filled in my VIN, the car's mileage, etc.

I receive the credit package in the mail some days later, and once again, there is some fine print.

This time it says you have to bring these cards in to the dealership to get them activated (why?!?) and you must bring the title, proof of registration or lease agreement.  I thought, yeah but this dealership is just around the corner from me, I bought the car from them.  They have me in their system, they know who I am, I think it'll be fine, they don't really need all those things.  That's probably just in case you go to some random VW dealership.  I'll just drive in and activate the cards.  Now the reason I don't have things like the title/registration with me is because the VW is actually my husband's primary car, so the title is in the car and not in my hands.

I drive to the dealership today, thinking it'll be easy.  They can just look me up in their system, I was happy to provide my driver's license to prove my identity.

The place is pretty empty, only one representative at the customer counter.  Okay, he asks me how he can help me.  I tell him I am there to activate the cards.  He says okay, show me the blah blah blah documents.  I tell him I don't have them with me, I say you have the information in your system, and you can just look me up.  He says no, in fact, they need to see the car, verify the VIN, check the mileage, etc.  I am like, I already told you the mileage when I filled in the online form, and check the VIN? What for? I bought the car here, you know who I am, I am in your system, the car, the VIN, everything.  No maam, there are certain rules to this offer, and you have to show the documents.  I ask, can my husband come in and do it, since he is the primary driver of the VW?  Nop, he cannot, because I signed up for the offer (cause my husband could care less about this stuff!)

Ugh... thank you VW for making this potentially good will buying offer, now a PAIN IN THE ASS. Oh yeah, I told the service rep this, and he throws back, in the coldest, least interested manner, "I am sorry if you feel that way".  Yup, I am sorry too, sorry I ever bought a VW.

You know VW, I can apply for a platinum credit card online, without ever having to drive anywhere, and the cards will show up at my door, and I can call a number, and activate it over the phone.  Why in the world do I need to physically go into the dealership when they already have my information?

Volkswagen Canada, what is it you are trying to do with this credit offer?  Are you trying to get some good will with your customers?  Or are you trying to piss them off even further?  Because you are certainly achieving your goals on the latter.