Go routines and channels

I’m having a bit of a dabble with Go, as a by product of working with Elastic Search beats.

One thing I’ve been looking at today is the channels to allow two go routines to communicate with each other and I came up with a fairly cheesy way to play with implementing them.

package main

import "fmt"

func ping(c chan string) {
	for {
		msg := <-c
		if msg == "pong" {
			println(" .... " + msg)
			c <- "ping"
		}
	}
}

func pong(c chan string) {
	for {
		msg := <-c
		if msg == "ping" {
			print(msg)
			c <- "pong"
		}
	}
}

func main() {
	var c chan string = make(chan string)

	go ping(c)
	go pong(c)

	c <- "ping"
	var input string
	fmt.Scanln(&input)
}

Using the go keyword to essentially start the ping and pong in the logical processor and run concurrently. They both get passed a special chan string that acts as a shared channel for them to synchronise against.

The code results in an endless game of ping pong.

ping .... pong
ping .... pong
ping .... pong
ping .... pong
ping .... pong
ping .... pong

There you go. Almost certainly not the best Go ever written, but a start.

Monit

There are lots of monitoring and alerting tools out there and I’m sure everyone has there own preference on which they’re going to use.

We have selected monit for simple monitoring of disk space, tunnels and processes because its simple to setup and does exactly what we’re asking it to do.

I particularly like DSL for defining which checks you want to perform.

As we’re running monit on multiple machines, we’re also evaluating m/monit which centralises the monitoring of all the separate instances in a nice dashboard.

Installing Monit

Our servers are Red Hat so we’re not using yum install monit which will get you stated on on a Fedora machine. Equally the downloads page on the monit site will give you the quick and easy installation for other common platforms.

# create the install folder
sudo mkdir /opt/monit
cd /opt/monit

# get the latest release
wget http://mmonit.com/monit/dist/binary/5.21.0/monit-5.21.0-linux-x64.tar.gz

# unpack
tar -xvf monit-5.21.0-linux-x64.tar.gz
rm monit-5.21.0-linux-x64.tar.gz
mv monit-5.21.0 5.21.0
cd 5.21.0

# put some links in
sudo ln -s /opt/monit/5.21.0/conf/monitrc /etc/monitrc
sudo ln -s /opt/monit/5.21.0/bin/monit /usr/bin/monit

Configuring Monit

Now the links are in we can configure the monit config file monitrc. The actually file has huge amounts of documentation; I’m going to limit this to the key points to get up and running

sudo vi /etc/monitrc

######################
## Monit control file
######################

set daemon  30   # check services at 30 seconds intervals

set logfile syslog

# configure the mmonit to report to
# set mmonit https://monit:monit@10.10.1.10:8443/collector

# configure email alerts (this is using AWS SES)
SET ALERT alerts@mycompany.com
SET MAILSERVER email-smtp.eu-west-1.amazonaws.com port 587
        username "" password ""
        using TLSV1
        with timeout 30 seconds

set mail-format {
from: my_ses_registered_email@mycompany.com
reply-to: my_ses_registered_email@mycompany.com
subject: $EVENT
message:
Monit
=====
Date:    $DATE
Host:    $HOST
Action:  $ACTION
Service: $SERVICE
Event:   $EVENT

Description:
============
$DESCRIPTION.
}

# configure the host connection
set httpd port 2812 and
  use address 0.0.0.0
  allow 0.0.0.0
  allow admin:monit # change the password


# configure checks - for example processes
CHECK PROCESS tunnel_somewhere MATCHING '.*?(autossh.*?(8081))'

# or disk space
CHECK DEVICE root WITH PATH /
  IF SPACE usage > 80% THEN ALERT

# or network connections
check network eth0 with interface eth0
  IF upload > 1 MB/s THEN ALERT
  IF total downloaded > 1 GB in last 2 hours THEN ALERT
  IF total downloaded > 10 GB in last day THEN ALERT

Starting Monit

To start monit user

sudo monit start

If you make changes to /etc/monitrc then you can reload it with sudo monit reload

Using AWS Simple Email Service with Oozie in Cloudera

I’ve moved to a new role where I will be doing a lot more “devops” type work which hopefully comes with more interesting subjects to start writing about.

Oozie and AWS Simple Email Services

The Cloudera cluster I have started working on is hosted in AWS and has all the security bells and whistles turned on; Kerberos, TLS etc.

Recently a support ticket came my way where the Email Action in Oozie was failing, on top of this there was no notification around job success and the Kill action wasn’t sending emails…. more than likely Oozie isn’t correctly configured for email.

As mentioned before, we use TLS everywhere possible and want to use Amazon’s Simple Email Service endpoint to relay the messages through. TLS SMTP isn’t supported directly with Oozie so there is a requirement to put something in the middle. In this case, the something is going to be postfix.

Prerequisites

There are a number of details you’ll need to get from AWS Management Console to get things set up.

In the AWS Management Console, navigate to the SES service and in the right hand side select SMTP settings. This is where you’ll find the endpoint you need to use and you can use the Create SMTP Credentials button at the bottom of the page to create some keys. _ Keep in mind that although these keys look like normal AWS Access Keys, they are actually SMTP keys and are specifically for authenticating with AWS SES _

Now on the left choose Email Addresses and follow the process for validating an email address as required by SES.

Installing and configuring postfix

These steps assume that you’re running a yum flavoured Linux, its pretty much the same if you’re working with Ubuntu if you interchange the package tooling.

First we need to install postfix

sudo yum install postfix -y

The configuration for postfix is in /etc/postfix/main.cf. This is where the relay to AWS SES is going to be happening.

There are a couple of tweaks that needed to be done in this file in addition to adding the relayhost section.

  1. Change the inet_protocols value to only ipv4 - inet_interfaces=ipv4
  2. Change the inet_interfaces, in my case I just commented out the whole line #inet_interfaces=localhost
  3. Add the smtp_tls_CAFile, in my case we’re using a pem file smtp_tls_CAfile = /path/to/tls_cert.pem

Now the relayhost section needs to be added so that it can forward to SES correctly.

In my case, I’m hosted in Ireland (eu-west-1) so my endpoint for SES is email-smtp.eu-west-1.amazonaws.com

relayhost = [email-smtp.eu-west-1.amazonaws.com]:25
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_use_tls = yes
smtp_tls_note_starttls_offer = yes

You can now save main.cf, we’ve finished with that.

You may have noticed the smtp_sasl_password_maps section pointing to a sasl_passwd file. We now need to create that. So create the file /etc/postfix/sasl_passwd and add the following using the credentials created for the SMTP user above.

[email-smtp.eu-west-1.amazonaws.com]:25 <smtpkey>:<smtpsecret>

You can now create the hash of this file, set the ownership and permissions then remove the new sasl_passwd file with the cleartext keys

sudo postmap hash:/etc/postfix/sasl_passwd
sudo chown root:root /etc/postfix/sasl_passwd.db
sudo chmod 0600 /etc/postfix/sasl_passwd.db
sudo rm /etc/postfix/sasl_passwd

Now all you need to do is start the service sudo postfix start

Configuring Oozie

You can configure Oozie in Cloudera Manager. Go to Oozie service -> Configuration. Set oozie.email.smtp.host and set the value to the IP address of the server you’ve installed postfix. (To keep it simple, I installed postfix on the Oozie server itself. I had to use the IP as Oozie doesn’t like localhost)

Set the oozie.email.from.address you’re going to be sending from to the value setup in SES Management Console email address page.

Restart Oozie and Hue then create a test workflow with an Email Action sending an email and run. All being well, the email will be sent and the workflow action will go green. Check the logs of the workflow if it doesn’t work, it should be clear from there.

Wordle Interpretation of CV

Today someone showed me a handle word cloud tool called wordle.

I put the skills from my CV into it and had a play with the output… I think it looks quite cool.

My Wordle Skills List

First go at creating a Garmin watch face

For a while Garmin have been adding “wearable technology” functionality to their watches - notifications from the phone etc. I got a Garmin Fenix 3 for Christmas and had a play with the vast number of watch faces and widgets that were available.

The recent updates have really added some great functionality and I ended up settling on the out of the box digital face as my normal watch face but I still wanted to have a go at creating my own watch.

###Monkey C The programming language used to develop the faces, apps, widgets and data fields is called Monkey C and the IDE is mostly intended to be Eclipse.

Its almost certainly going to be worth your time looking at the Garmin developer site to get the full over view of whats required, but I’m covering the headlines below.

####Getting the SDK First you need to download the Garmin SDK from here. I’m using a Macbook so I’ve dropped it in /usr/local/garmin-sdk.

####Eclipse Add in If you look at the getting started pages here you’ll get all the information about adding the Eclipse add in which will give the you project template and intellisense as well as access to some richer wizards for interacting with the simulator.

I’m not very comfortable using Eclipse so I was pleased to see that there is an Intellij plugin that someone had started.

####Intellij Plug in The IntelliJ plugin is added in the normal way, the details about it are here.

At the time of writing this it was fairly basic and doesn’t have many features, I had to rely on the API docs to get the message signatures of everything I needed to use.

####API Docs The API docs are pretty good for getting the gist of what you want to do. You need to know what you want to do and see if you can rather, but thats no different to any API I guess.

###My First Watch face And so to my first watch face. I wanted to have a clean digital watch without the clutter of bars and tickers. I did want to know my relative step progress and the current battery level though, I’ve been caught out a few too many times.

My understanding from the docs is that your watch face updates minutely in low power mode until the gesture of looking at the watch is detected then it becomes every second. There are some methods which are called during this state change but I didn’t have any need for them.

I’m loading the components programatically so I don’t need much in my layouts file

<layout id="WatchFace">
</layout>

Your watch face must extend the Ui.WatchFace class

class FirstwatchfaceView extends Ui.WatchFace {

  function initialize() {
    WatchFace.initialize();

  function onLayout(dc) {
      setLayout(Rez.Layouts.WatchFace(dc));

  function onUpdate(dc) {
    // clear the display
    dc.clear();
    var font = Gfx.FONT_NUMBER_THAI_HOT;
      // get the info needed
    var activity = ActivityMonitor.getInfo();
    var stats = Sys.getSystemStats()
    var clockTime = Sys.getClockTime();
      var today = Time.today();
    var dateInfo = Time.Gregorian.info(today, Time.FORMAT_MEDIUM);
    var timeString = Lang.format("$1$ $2$", [clockTime.hour, clockTime.min.format("%02d")])
    // get the text size to work out where to position it
    var textDim = dc.getTextDimensions(timeString, font);
    var x = (dc.getWidth() / 2);
    var y = (dc.getHeight() /2) - textDim[1] /2;
    var stepsX = x - textDim[0]/2 ;
    var batteryPercent = Lang.format("$1$%", [stats.battery.format("%02d")]);
    var date = Lang.format("$1$ $2$", [dateInfo.day, dateInfo.month]);
    var percent =  (activity.steps*100)/activity.stepGoal
    // set the whole screen black
      dc.setColor(Gfx.COLOR_BLACK, Gfx.COLOR_BLACK);
      dc.fillRectangle(0, 0, dc.getWidth(), dc.getHeight())
    if (percent > 100) {
       dc.setColor(Gfx.COLOR_GREEN, Gfx.COLOR_BLACK);
         dc.drawText(x,y, font, timeString, Gfx.TEXT_JUSTIFY_CENTER);
      } else {
         dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_BLACK);
         dc.fillRectangle(stepsX, y+1, min(percent, textDim[0]), textDim[1]);
         dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
       dc.fillRectangle(stepsX + percent, y+1, textDim[0]-percent, textDim[1]);
       dc.setColor(Gfx.COLOR_TRANSPARENT, Gfx.COLOR_BLACK);
       dc.drawText(x,y, font, timeString, Gfx.TEXT_JUSTIFY_CENTER);
    }
    dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
    dc.drawText(x, (dc.getHeight() - 10 - (dc.getFontHeight(Gfx.FONT_TINY))), Gfx.FONT_TIN batteryPercent, Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(x, (10 + dc.getFontHeight(Gfx.FONT_TINY)), Gfx.FONT_TINY, date Gfx.TEXT_JSTIFY_CENTER); }

function min(a, b) {
  if (a > b) {
     return b;
   }
   return a;
}

Running in IntelliJ for me is a case of Shift+F10 and the Run Configuration loads the simulator.

In the simulator you can set the levels of activity and change properties of the device such as battery status and GPS etc.

Steps in progress Daily steps in progress

Steps in progress Daily steps in completed