Hello 👋 I'm Dan.

I write PHP, Go, and JavaScript. I also care about web performance.

OS X Mavericks Server - Setting Up An Open Directory Master

In most cases I set up Open Directory after doing the initial server and DNS configuration. Most of the services that OS X Server have hooks into the Open Directory database, so why not configure it now then do the other services after.

If you intend on using Open Directory properly (this includes LDAP and Kerberos), then you must ensure your DNS is healthy before continuing. One wrong character can screw up your entire Kerberos realm and trust me, you don’t want to have to go back and fix that mess (I’d rather punch myself in the face). To check the status of DNS on your server, enter the following command:

sudo changeip -checkhostname

If your result is not “The names match. There is nothing to change.” then you’ve got unhealthy (and sad) DNS. Fix it.

So your DNS is all healthy? Great, let’s continue. Open the Server app, but wait! Open Directory isn’t listed there?! Did Apple kill Open Directory?! Nope, see that Advanced section in the list on your sidebar? Mouse over it and click “Show”. You may now breathe normally. Click on the Open Directory button to view its section in the Server app. Even at the best of times the Open Directory tab in Server is pretty boring, but it’s especially boring when the service isn’t even running. Let’s change that and set up an Open Directory Master! Start by clicking that nice On button in the top-right corner.

The 3 options for directory services in OS X Server.

The 3 options for directory services in OS X Server.

This initial setup wizard hasn’t changed visually since Mountain Lion, but it’s worth going through if you never used Mountain Lion Server! Given that we don’t have an existing Open Directory domain, but we want to make one, we’ll go with the first option, “Create a new Open Directory domain”. Click Next.

Create a Directory Administrator.

Create a Directory Administrator.

By default, OS X Server suggests Directory Administrator and diradmin as the name for the Directory Administrator. My preference is to use Master Directory Administrator, and masterdiradmin respectively, as the server is the Open Directory Master. It’s purely a stylistic choice, just make sure you have the details saved somewhere (in 1Password) I should hope). For this example, I’m using a very basic password, in the real world I would use a randomly generated one, maybe something like this: e9uZxrcsY6vwJe3y6CvK. Click Next

Your Organisation Information in Open Directory.

Your Organisation Information in Open Directory.

Next up is your organisation name and contact email address. Given that these details are used in your SSL certificate or CSR, you must ensure these details are correct. Click Next.

Confirm Your Open Directory Settings.

Confirm Your Open Directory Settings.

In your setup, confirm that your details are all correct before clicking the Set Up button. You don’t want to find down the track you entered wrong details. For the curious, before you click Set Up, open a Terminal window and enter:

tail -f /Library/Logs/slapconfig.log

When you click Set Up you’ll see lots of info fly by as it creates the Open Directory domain.

Your Open Directory domain is now alive!

Your Open Directory domain is now alive!

We can now do a quick test using the dscl command to ensure Open Directory is happy. Using those Directory Administrator credentials we used in set up, we can use a feature of dscl called authonly which, as you would expect, tests for authentication only. See the example below:

dscl /LDAPv3/ -authonly masterdiradmin masterpass

This says that datasource we’re using is LDAPv3, and the location of that is We then add the flag -authonly to tell dscl we’re just testing for authentication. Finally, we send over the username and password. Given that the password is being sent as cleartext, only do this when you’re physically at the server during set up (or if you do it remotely, do it with a standard user account, not an administrator account). When you press Return (or Enter) to send the command, you won’t get anything returned if it’s correct. Here’s two examples of authentication failure:

Authentication for node /LDAPv3/ failed. (-14477, eDSInvalidSession)
<dscl_cmd> DS Error: -14477 (eDSInvalidSession)

That was using the wrong password, below is using a user that doesn’t exist in the domain:

Authentication for node /LDAPv3/ failed. (-14090, eDSAuthFailed)
<dscl_cmd> DS Error: -14090 (eDSAuthFailed)

See the difference? You get an eDSInvalidSession with a bad password, and an eDSAuthFailed with a bad username. It’s handy to know the difference between the two errors, it may come in use one day when testing.

If you’re really anal about testing, you can also test authentication with Kerberos. Here’s the structure of the command:

kinit -V -S host/server_hostname@KERBEROS_REALM od_user@KERBEROS_REALM

First off, we’re using the kinit command, which acquires the initial Kerberos ticket (but can also renew old tickets). Our first flag is -V, which gives us some verbosity when testing kinit - I like verbosity when testing, so we’ll use it in our command. Next up is -S host/server_hostname@KERBEROS_REALM, let’s break this down a little more. the -S means we’re using a realm other than krbtgt/LOCAL.REALM, which is appropriate when testing Kerberos on any other system other than the Kerberos server itself. Technically, we can simplify the kinit command, so that will be reflected below. Finally, is od_user@KERBEROS_REALM. At this stage, the only user in the Open Directory domain is masterdiradmin (or the username for your Directory Administrator). Given that we’re currently only using the one Open Directory server, we know that our KERBEROS_REALM will be MAVERICKS.PRETENDCO.COM (all caps your host name).

kinit -V od_user@KERBEROS_REALM

Now that we’ve got our simplified command structure, use the command below in Terminal:

kinit -V masterdiradmin@MAVERICKS.PRETENDCO.COM

You’ll be prompted to enter in the password for the user (you could use -stdinpass and echo the password, but that’s for another day). If all is successful, you should see something similar to below:

Placing tickets for 'masterdiradmin@MAVERICKS.PRETENDCO.COM' in cache 'API:C7F85975-55A4-4930-8DC3-6D668D209087'

The long UUID you see in the cache string is the unique identifier for that ticket session. To check out the details for your ticket, enter:

klist -v

klist will give you minor details about your ticket, but adding the -v flag will increase the verbosity of output, which you could use for troubleshooting (or just general information gathering or learning). Here’s an example of the output you might expect from klist with the verbosity flag:

Credentials cache: API:C7F85975-55A4-4930-8DC3-6D668D209087
        Principal: masterdiradmin@MAVERICKS.PRETENDCO.COM
    Cache version: 0

Client: masterdiradmin@MAVERICKS.PRETENDCO.COM
Ticket etype: aes256-cts-hmac-sha1-96, kvno 1
Ticket length: 368
Auth time:  Oct  6 22:50:57 2013
End time:   Oct  7 08:50:54 2013
Ticket flags: enc-pa-rep, pre-authent, initial, forwardable
Addresses: addressless

Alrighty then, everything appears to be in order! We now have a happy Open Directory Master than is running and accepting connections. Going back to the Server app, you can see a gear in the bottom-left corner of the window where you can change the Global Password Policy, archive the Open Directory Master, or promote a Replica to Master.

We can also get more information regarding Open Directory using serveradmin and the command line. See below for the status:

sudo serveradmin status dirserv

And your output should be as follows:

dirserv:state = "RUNNING"

If you want to get more information regarding the status of Directory Services, do this command:

sudo serveradmin fullstatus dirserv

And your output will be something like this:

dirserv:logPaths:opendirectorydLog = "/var/log/opendirectoryd.log"
dirserv:logPaths:ldapLog = "/var/log/slapd.log"
dirserv:logPaths:passwordServiceServerLog = "/Library/Logs/PasswordService/ApplePasswordServer.Server.log"
dirserv:logPaths:passwordServiceErrorLog = "/Library/Logs/PasswordService/ApplePasswordServer.Error.log"
dirserv:logPaths:kdcLog = "/var/log/krb5kdc/kdc.log"
dirserv:logPaths:slapconfigLog = "/Library/Logs/slapconfig.log"
dirserv:LDAPServerType = "master"
dirserv:state = "RUNNING"
dirserv:ldapSearchBase = "dc=mavericks,dc=pretendco,dc=com"
dirserv:kdcHostedRealm = "MAVERICKS.PRETENDCO.COM"
dirserv:readWriteSettingsVersion = 1

Most of those settings should be pretty obvious, as most of them are log file locations. If you want to get lots more configuration, enter this command:

sudo serveradmin settings dirserv

You’ll get a lot more information regarding the nitty gritty of the Directory Service:

dirserv:selfWrite = yes
dirserv:locales = _empty_array
dirserv:caServer = yes
dirserv:MacOSXODPolicy:Directory Binding = yes
dirserv:MacOSXODPolicy:Configured Security Level:Binding Required = no
dirserv:MacOSXODPolicy:Configured Security Level:Advisory Client Caching = no
dirserv:MacOSXODPolicy:Configured Security Level:Man In The Middle = no
dirserv:MacOSXODPolicy:Configured Security Level:Packet Signing = no
dirserv:MacOSXODPolicy:Configured Security Level:No ClearText Authentications = no
dirserv:MacOSXODPolicy:Configured Security Level:Packet Encryption = no
dirserv:kerberizedRealmList:availableRealms:_array_index:0:dirNodePath = "/LDAPv3/"
dirserv:kerberizedRealmList:availableRealms:_array_index:0:realmName = "MAVERICKS.PRETENDCO.COM"
dirserv:kerberizedRealmList:defaultRealm = "MAVERICKS.PRETENDCO.COM"
dirserv:PWPolicyInfo:requiresMixedCase = no
dirserv:PWPolicyInfo:passwordMinLen = 0
dirserv:PWPolicyInfo:mustChangeAtFirstLogin = no
dirserv:PWPolicyInfo:passwordMustHaveAlpha = no
dirserv:PWPolicyInfo:requiresSymbol = no
dirserv:PWPolicyInfo:passwordNotAccount = no
dirserv:PWPolicyInfo:passwordDisableFailedLogins = 0
dirserv:PWPolicyInfo:passwordHistoryLen = 0
dirserv:PWPolicyInfo:passwordDisableNumDaysInactive = 0
dirserv:PWPolicyInfo:passwordDisableDate = 0.000000
dirserv:PWPolicyInfo:passwordExpireDays = 0
dirserv:PWPolicyInfo:passwordMustHaveNumber = no
dirserv:PWPolicyInfo:passwordDisableNumDays = 0
dirserv:LDAPDefaultPrefix = "dc=mavericks,dc=pretendco,dc=com"
dirserv:defaultKerbRealmName = "MAVERICKS.PRETENDCO.COM"
dirserv:masterConfig:replicas = _empty_array
dirserv:LDAPSettings:useSSL = yes
dirserv:LDAPSettings:LDAPServerBackend = "config"
dirserv:LDAPSettings:LDAPDataBasePath = "/var/db/openldap/openldap-data"
dirserv:LDAPSettings:maxSearchResults = "11000 size.prtotal=unlimited"
dirserv:LDAPSettings:LDAPSSLIdentityName = "mavericks.pretendco.com"
dirserv:LDAPSettings:LDAPTimeoutUnits = "seconds"
dirserv:LDAPSettings:LDAPSearchBase = "dc=mavericks,dc=pretendco,dc=com"
dirserv:LDAPSettings:searchTimeout = 60
dirserv:LDAPSettings:LDAPSSLSerialNumber = "572599038"
dirserv:treeConfiguration:odTree:_array_index:0:PrimaryMaster = "mavericks.pretendco.com"
dirserv:treeConfiguration:odTree:_array_index:0:IPaddresses:_array_index:0 = ""
dirserv:treeConfiguration:odTree:_array_index:0:GUID = "AA4D0B74-0073-41EF-82A7-B22E51ECA938"
dirserv:treeConfiguration:odTree:_array_index:0:ReplicaName = "Master"
dirserv:treeConfiguration:odTree:_array_index:0:treeSource = "PrimaryMaster"
dirserv:treeConfiguration:odTree:_array_index:0:Replicas = _empty_array
dirserv:LDAPServerType = "master"

There’s a lot to see there, and most of it’s not worth going through if you’re going to be running a small network with 1 server. Nonetheless, it’s still interesting to see all the configuration details for Directory Services.

OS X Mavericks Server - DNS

Running DNS services for your OS X Mavericks Server can be pretty easy as long as you know how. For a small network with a nice network setup, you shouldn’t have many complications with DNS. If you’ve been following my guides, the minimum you should have completed is the initial set up. It’s a good idea to have DNS all sorted before moving onto any of the other services, setting up DNS is typically one of the first things I would do if the server was to be the DNS server for the LAN.

Go to the Server app and click on the DNS tab. It’ll look pretty empty when the service isn’t running. We’re going to change that. Click the On button to start the DNS services.

For the basic settings, we’ll configure forwarding servers, and what networks will be able to access this DNS server. If you click on the “Edit” button next to “Forwarding Servers:“, we can add the addresses for which this DNS will send queries to if it does not have the authority to do so.

DNS - My Forwarding Settings.

DNS - My Forwarding Settings.

Depending on your modem or ISP configuration, this can vary. If your modem handles all DNS, all you need to enter is the IP address of your modem. Otherwise, if you want to pass on DNS queries to your ISP, you’ll need to enter the two IP addresses for your ISPs DNS servers. Lastly, you have the option of using public DNS servers, like Google’s. Google use and as primary and secondary DNS servers. I would usually use the ISP DNS servers, but it really depends on your network configuration. My advice is to ask your ISP on what details you should enter, they may have specific requirements depending on your internet connection method.

Given that we are setting up this server as the main DNS server for this network, keep “Perform lookups for” ticked, and select “all clients”. This should be the default, but change it if it’s not the default.”

DNS - Lookups.

DNS - Lookups.

Next, we’re on to records. If you already have records, the DNS service has constructed them for you, if not, continue! Before we start configuring our own DNS records, click the gear in the bottom-left corner of the window and ensure “Show All Records” is ticked. Without that option ticked, it’s a little vague as to what you’re configuring.

If you go to the + (plus) just next to the gear, the only two options you should have is “Add Primary Zone…” and “Add Secondary Zone…”. We’ll click “Add Primary Zone…”. Given that my domain name is pretendco.com, I’ll enter pretendco.com as the name for the Primary Zone. Next, change the “Zone data is valid for” to 6 hours. 6 hours is long enough for cached DNS values. Now, click OK.

DNS - Adding a Primary Zone.

DNS - Adding a Primary Zone.

Wonderful, we now have a Primary DNS zone. It’s time to add an A record (or Machine record). What this essentially means is that you can assign an individual DNS name to an IP address on the network. Click on the + (plus) again, and click “Add Machine Record”. Keep the “Zone” as pretendco.com (or your zone name if it’s different). Given the subdomain (and name) of my server is mavericks, I’m going to make the Host Name mavericks. The “IP Address” should be the IP address of the server In my case, it’s Now, click “Create”.

DNS - Making a Machine (A) Record.

DNS - Making a Machine (A) Record.

Superb, you now have a DNS name for your server and your domain name. Now you can do a DNS lookup to ensure it’s all working OK. Open up Terminal and enter (replace my IP address with your server’s IP address):

dig -x

This does a reverse lookup of the IP address and checks to see what DNS name is associated with that IP address. You should hopefully see something similar to below:

; <<>> DiG 9.8.3-P1 <<>> -x
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27201
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1


;; ANSWER SECTION: 10800 IN	PTR	mavericks.pretendco.com.

125.1.10.in-addr.arpa.	10800	IN	NS	mavericks.pretendco.com.

mavericks.pretendco.com. 10800	IN	A

;; Query time: 0 msec
;; WHEN: Tue Oct  8 21:03:19 2013
;; MSG SIZE  rcvd: 110

Essentially, what this says is:

  • QUESTION: I’m asking what the DNS name of is
  • ANSWER: The DNS name is mavericks.pretendco.com
  • AUTHORITY: This is the DNS name of the Nameserver that answered our query
  • ADDITIONAL: This shows you the IP address of the Nameserver that answered the query
  • SERVER: The IP address of the DNS server that responded to the query.

If you ran this command on the server, the server that responded should be (aka localhost). If not, you probably don’t have the first DNS server for your network interface as Add that in before you continue.

Finally, we need to add an MX (Mail Exchanger) record for the server, so you can send email. To do this, click on the + (plus) at the bottom-left, then click “Add Mail Exchanger Record…”.

DNS - Add an MX Record.

DNS - Add an MX Record.

For your zone, leave it as the default. For “Mail Server”, it should be the host name for the server you’re using. For example, the host name for my server is mavericks.pretendco.com, so that’s what I’ll enter. For “Priority”, if you have one mail server, enter 0. The priority (or weighting) is used for if you have multiple Mail servers and want to spread the load. The closer number to 0 the server is, the higher priority it is. I’ve only scraped the surface of Mail server priority, it’s worth reading up properly for more technical information. Now you’re ready to click “Create”. So click it.

DNS - It's All Configured!

DNS - It's All Configured!

Your DNS configuration is now done! Naturally, more complex environments will require for DNS configuration, but if you’ve just got one server, this should be all you need to do.

OS X Mavericks Server - Setting Up The Basics

So you’ve got OS X Mavericks and you want a server. Mavericks Server has brought a number of changes to the Server side of OS X. Notable changes include Xcode Server, a continuous integration service for teams of developers for Xcode, SMB2 for file sharing, Caching Server for caching of iOS content and speedy delivery, and Profile Manager with changes including distribution of apps and books purchased from the App Store volume licensing program.

To start, you should have OS X Mavericks installed, and Server downloaded. Initially, we will set a static IP address for the server, never use DHCP for a server. I’m going to use, you should use what ever free address is available on your network. Normally, I use .254 for my server (but in this example I already have my server running on .254).

To do this, go to System Preferences (on the server), then click on Network. Select the Ethernet interface (you are using Ethernet right? It’s a must), then next to Configure IPv4, select Manually from the drop-down menu. For my network, I’m entering these details:

  • IP Address:
  • Subnet Mask:
  • Router:
  • DNS Server:,,
My Manually Assigned IPv4 Address for the Server.

My Manually Assigned IPv4 Address for the Server.

Under the DNS Server section, if you intend on using this server as a DNS server, you must have set as the first DNS server. This is so DNS lookups are sent to this server first, then if it is not authoritative, it’ll pass the query on to the next DNS server.

Next, we’re going to set up the hostname for the server. I’m going for mavericks.pretendco.com. Open up your Terminal window, because we’re going to set it up via the command line (you could set it up later via the Server app GUI, but I prefer to do it via the command line before installing Server). First off, we set the HostName of the server.

sudo scutil --set HostName mavericks.pretendco.com

The HostName is the name that is associated with the commands hostname and gethostname. Next, we set LocalHostName.

sudo scutil --set LocalHostName mavericks

This is the local Bonjour host name. Finally, we set the ComputerName, which is the user-friendly name for the system. Some people choose to do the FQDN (or Fully Qualified Domain Name), but my preference is to just give it a nice looking name, given it’s meant to be a user-friendly name. I’m going to go with Mavericks.

sudo scutil --set ComputerName Mavericks

Now, I’m going to install the Server.app. Once you’ve downloaded Server from the Mac App Store, open it to start the initial install. Click through the prompts and enter your administrator username and password, then the Server.app will go through setup of certificates and basic configuration of services.

The stages of Server installation.

Once the setup has been completed, you’ll be shown the Machine section of the Server tree in Server.app

Server App - Main Window.

Server App - Main Window.

Now, let’s ensure DNS is healthy before we start configuring services. DNS is one of the most important parts of OS X Server, and must be healthy if you intend on maintaining a server. Open up a Terminal window and enter the command below:

sudo changeip -checkhostname

Hopefully, you should see something like below:

Primary address     =

Current HostName    = mavericks.pretendco.com
DNS HostName        = mavericks.pretendco.com

The names match. There is nothing to change.
dirserv:success = "success"
The 4 most important lines in a servers life.

The 4 most important lines in a servers life.

Hooray! OK, now, it’s a good time to enable SSH, ARD and Screen Sharing. You have two ways around this. First, you can go through the Server GUI by clicking on the server name under the Server tree, then click on Settings. Now, tick the “Allow remote login using SSH for administrators” box, and the “Enable screen sharing and remote management”. Otherwise, go back to your Terminal window and enter the following commands:

sudo serveradmin settings info:enableARD = yes

That’ll enable Apple Remote Desktop remote management so you can manage and get reports from the server. Next, we’ll enable screen sharing.

sudo serveradmin settings info:enableScreenSharing = yes

If you’re on another Mac on the same network, you should see the server pop up in the Shared list in Finder. Finally, we enable SSH by entering this command:

sudo serveradmin settings info:enableSSH = yes

If you went through the Terminal route of remote access, go back to the Server app and you’ll see those boxes have been ticked for you.

Remote Access options enabled in the Server app.

Remote Access options enabled in the Server app.

Lastly, if you’d like to administer the server through the Server app on another computer, you can do the following:

sudo serveradmin settings info:enableRemoteAdministration = yes

And this concludes the initial set up of OS X Mavericks Server. Stay tuned for more posts on configuring the latest version of Apple’s service application!

FreeRADIUS Monitoring with Nagios

After doing a few setups using my buddy Jedda’s excellent article on configuring basic RADIUS on OS X 10.8 Server, I decided I wanted a way to monitor the customers FreeRADIUS server to ensure it’s up and running, and processing requests. Given that we use GroundWork for monitoring, I decided to write a bash script that verifies the process is running, and that it’s processing authentication requests. Queue code!

Take a look at the code on GitHub

ps aux -o tty | grep "/usr/sbin/radius"

Initially, we do a quick process check to make sure FreeRADIUS is even running. If it’s not running, we exit with a critical warning (there’s no point proceeding any further in the script). This script was written for OS X 10.8 Mountain Lion Server, so adjust the path to radius to your liking.

OK, so we’ve verified the radiusd process is running, now it’s time to try and authenticate using valid login credentials to the FreeRADIUS server (in my case, users in the com.apple.access_radius group).

echo "User-Name=<username>,User-Password=<password>,Framed-Protocol=PPP " | radclient -x -r 1 -t 2 localhost:1812 auth testing123 2> /tmp/radius_error

Running the command radclient by itself doesn’t work, you have to pipe radius authentication attribute/value pairs. We use PPP for the Framed-Protocol as we are providing a username and password and using the Point-To-Point Protocol. It’s worth taking a look at RFC 2865 for more information regarding RADIUS and user authentication.

After authentication and server credentials are supplied, we pass all standard error (stderr) to a temporary log file (stored at /tmp/radius_error) so it doesn’t cause the script to produce any unexpected output. I also assign a variable with the contents of that temporary file so we can see what the error was. An incorrect shared secret will throw a stderr, but wrong credentials will just output to stdout.

The next part of our script is an if statement that checks what our authentication attempt has returned, then process accordingly. We check if it’s successful, wrong shared secret, or wrong authentication details. If there’s any other response, I throw a generic error.

./check_radius.sh -u username -p password -h localhost -p 1812 -s sharedsecret

To run the script, you enter the code above (this assumes you’re running with escalated privileges i.e. sudo -s, otherwise prepend the command with sudo). This should be run on the same server as your FreeRADIUS server, or on an authorised Network Access Server (NAS) client.

GroundWork Configuration

First off, we need a command that does the actual check. See below for the command details:

  • Name: check_by_ssh_radius
  • Type: check
  • Command line: $USER1$/check_by_ssh -H $HOSTADDRESS$ -t 60 -l "$USER17$" -C "sudo $USER22$/check_radius.sh -u $ARG1$ -p $ARG2$ -h $ARG3$ -a $ARG4$ -s $ARG5$"
  • Usage: check_by_ssh_radius!ARG1!ARG2!ARG3!ARG4!ARG5

Next, we need a service that uses the command for the check.

  • Name: ssh_radius
  • Service template: use whichever you prefer
  • Check command: check_by_ssh_radius
  • Command line: check_by_ssh_radius!username!password!radius.server!radius.auth.port!shared.secret

Now add this to a host, and follow this command line as an example (as an entry for the host):


Important Note For Testing

Something which I made the mistake of when testing on the FreeRADIUS server was trying to add a client for When I added this client, the damn server wouldn’t start because there was a duplicate entry! FreeRADIUS automatically sets up the local server as a client (NAS), with the default shared secret of testing123. Once you’ve finished testing, you can edit the clients.conf to disable localhost access to the FreeRADIUS server. Please note that if you intend on running this script on the same server as the FreeRADIUS server, don’t disable localhost access!

Performance Data - A Maybe

I had planned to do performance data but I felt the status function through radclient was too unreliable to query. I’ll possibly look into performance data again in a few months.

RRDtool Graph for Nagios' check_disk Command

Over the past few months I’ve been working more and more with RRDtool, and since we use GroundWork at work, I thought I’d start to better the default graphs that come with GroundWork. One of the graphs I thought needed the most improvement is the graph for check_disk. See the old graph below:

The original GroundWork/RRDtool graph for disk usage.

The original GroundWork/RRDtool graph for disk usage.

The new and improved graph for disk usage!

The new and improved graph for disk usage!

Along with my other graphs, I will be using the Outlined Area Graphs colour set for my graph areas and lines.

Without further ado, here is the code for the graph:

rrdtool graph - \
-E \
-P \
-h 180 \
-l 0 \
--grid-dash 1:2 \
-t "<big><b>Disk Utilisation</b></big>" \
-b 1024 \
-X 0 \
-a PNG \
-v "<b>Disk Usage (MB)</b>" \
DEF:diskCurr=rrd_source:ds_source_0:AVERAGE \
DEF:diskWarn=rrd_source:ds_source_1:AVERAGE \
DEF:diskCrit=rrd_source:ds_source_2:AVERAGE \
DEF:diskMax=rrd_source:ds_source_3:AVERAGE \
CDEF:diskPerc=diskCurr,diskMax,/,100,* \
CDEF:cdefDisk=diskCurr \
CDEF:cdefw=diskWarn \
CDEF:cdefc=diskCrit \
CDEF:cdefm=diskMax \
CDEF:warnPerc=diskWarn,diskMax,/,100,* \
CDEF:critPerc=diskCrit,diskMax,/,100,* \
AREA:diskCurr#54EC48:"<b>Space Used\:</b>\g" \
LINE2:cdefDisk#24CB14: \
GPRINT:diskCurr:LAST:" <b>%.0lf MB</b>\g" \
GPRINT:diskPerc:LAST:" <i><b>(%.0lf%%)</b></i>" \
LINE2:cdefm#4D18E4:"<i>Maximum Capacity\:</i>\g" \
GPRINT:cdefm:LAST:" <i>%.0lf MB</i>\n" \
LINE2:cdefw#C9B215:"Warning Threshold\:\g" \
GPRINT:cdefw:AVERAGE:" <i>%.0lf MB</i>\g" \
GPRINT:warnPerc:LAST:" <i>(%0.lf%%)</i>" \
LINE2:cdefc#CC3118:"<i>Critical Threshold\:</i>\g" \
GPRINT:cdefc:LAST:" <i>%.0lf MB</i>\g" \
GPRINT:critPerc:LAST:" <i>(%.0lf%%)</i>\n" \
-c GRID#C0C0C0 \
-c MGRID#404040 \
  • rrdtool graph - — this will tell rrdtool that weโ€™re making a graph, and the output will go to stdout (needed for GroundWork, otherwise you can put something like disk_usage.png).
  • -E — aka --slope-mode gives the graph a more organic and natural look.
  • -P — uses Pango markup to render all text with HTML, so you can use tags like <b></code> or <code class="inline"><i>. There are more available, you can check out Pango Reference Manual.
  • -h 180 — this sets the height of the graph to 180 pixels.
  • -l 0 — this sets the lowest number (or limit) of the Y-axis to 0, because obviously, a storage device can’t have a negative capacity.
  • --grid-dash 1:2 — gives us nice and small dotted lines for the graph.
  • -t "<big><b>Disk Utilisation</b></big>" — the title for the graph, with Pango-supported HTML to make the title bigger and bolder (as the tags would suggest).
  • -b 1024 — as we are dealing with storage capacity, we measure the data in base2.
  • -X 0 — disables the unit exponent scaling for this graph.
  • -a PNG — formats the output of the graph as a PNG. Depending on what setting you have, it could impact some other settings (i.e. --no-gridfit).
  • -v "<b>Disk Usage (MB)</b>" — this sets a vertical title on the left-side of the Y-axis.
  • DEF:diskCurr=rrd_source:ds_source_0:AVERAGE — this defines a variable called diskCurr which is sourced from the RRD. GroundWork automatically fetches this for you. From the command line, you would manually specify both the path to the RRD, and the data source (i.e. server17.pretendco.com_ssh_disk_boot.rrd:_dev_disk0s2).
  • DEF:diskWarn=rrd_source:ds_source_1:AVERAGE — same as above, but gets the warning level for the disk (in MB).
  • DEF:diskCrit=rrd_source:ds_source_2:AVERAGE — same as above, but gets the critical level for the disk (in MB).
  • DEF:diskMax=rrd_source:ds_source_3:AVERAGE — same as above, but gets the maximum size of the disk (in MB).
  • CDEF:diskPerc=diskCurr,diskMax,/,100,* — this command (CDEF) copies the values of a variable(s), and math can be performed using rpn (Reverse Polish Notation). The standard way of writing this is diskPerc = (diskCurr / diskMax) * 100 as we are calculating the percentage used of the disk. I won’t delve into the complexities of RPN, but take a look at the Wikipedia article.
  • CDEF:cdefDisk=diskCurr — assign another variable called cdefDisk which copies the diskCurr variable.
  • CDEF:cdefw=diskWarn — as above, copy one variable to another.
  • CDEF:cdefc=diskCrit — as above, copy one variable to another.
  • CDEF:cdefm=diskMax — as above, copy one variable to another.
  • CDEF:warnPerc=diskWarn,diskMax,/,100,* — calculate the warning level as a percentage. In standard mathematics, your equation would be warnPerc = (diskWarn / diskMax) * 100.
  • CDEF:critPerc=diskCrit,diskMax,/,100,* — like above, calculate the critical level as a percentage.
  • AREA:diskCurr#54EC48:"<b>Space Used\:</b>\g" — graph the area of the variable diskCurr with the colour #54EC48, then print Space Used: in bold, with a string modifier (\g) to strip whitespace at the end of the string.
  • LINE2:cdefDisk#24CB14: — print a line on the graph that is 2 pixels thick, with the value of cdefDisk and the colour #24CB14. Note the extra colon (:) at the end, this means we’re not printing any string in the legend (below the graph).
  • GPRINT:diskCurr:LAST:" %.0lf MB\g" — print the last value of diskCurr as an integer with MB at the end.
  • GPRINT:diskPerc:LAST:" (%.0lf%%)" — print the percentage of the disk used. Note the double percentage, the first percentage symbol escapes the second symbol (so RRDtool doesn’t think we’re trying to print a number).
  • LINE2:cdefm#4D18E4:"Maximum Capacity\:\g" — draw a line on the graph that represents the maximum capacity of the storage device.
  • GPRINT:cdefm:LAST:" %.0lf MB\n" — print the maximum capacity of the storage device in megabytes (MB).
  • LINE2:cdefw#C9B215:"Warning Threshold\:\g" — draw a line on the graph that represents the warning threshold of space used.
  • GPRINT:cdefw:AVERAGE:" %.0lf MB\g" — print the warning threshold in MB.
  • GPRINT:warnPerc:LAST:" (%0.lf%%)" — print the warning threshold as a percentage.
  • LINE2:cdefc#CC3118:"Critical Threshold\:\g" — draw a line on the graph that represents the critical threshold of space used.
  • GPRINT:cdefc:LAST:" %.0lf MB\g" — print the critical threshold in MB.
  • GPRINT:critPerc:LAST:" (%.0lf%%)\n" — print the critical threshold has a percentage.
  • -c BACK#FFFFFF — change the background colour of the graph to #FFFFFF (white).
  • -c CANVAS#FFFFFF — change the canvas colour (the actual graph itself) of the graph to #FFFFFF (white).
  • -c GRID#C0C0C0 — change the grid colour to #C0C0C0 (light gray).
  • -c MGRID#404040 — change the major grid colour to #404040 (dark gray).
  • -c ARROW#FFFFFF — change the arrow colours to #FFFFFF (white) to hide them.
  • -Y — enables the nice dynamic Y-axis grid that gives you whole numbers and ensures you don’t have too many horizontal lines that could make the graph messy or hard to understand.

You can also take a look at the gist for the code.


PSA: Fake ATO Refund Phishing Email

This morning I received an email purportedly from the Australian Tax Office (ATO) which, at first, excited me (I had just woken up) because I was getting another refund! Hooray! But… there’s always a catch. Upon actually reading the email I noticed several red flags which made me realise that the email is in fact, a phishing email.

The phishing email as seen on my Mac.

The phishing email as seen on my Mac.

First off, the refund amount is listed as AUD. Given the Australian Tax Office operates only in Australia, there is no reason that they would have to specify what currency the refund amount is in, are they all of a sudden going to refund in USD, EUR? I don’t think so. Secondly, the website is cloudaccess.net, not ato.gov.au. The Australian Tax Office would never use another domain for any of their pages.

The last paragraph makes mention of an SSL certificate, yet the resource for the aforementioned link is http, not https (which all secure websites should be). Given how the banks have been training people to look out for the lock for some years now I think this would be a obvious red flag for many people.

The goofballs who made the email even used @ato.com.au as the reply email address. Any Australian resident who uses the internet should know that the Australian Tax Office is a government branch, and will use the .gov.au TLD, not .com.au

For more details regarding the Australian Tax Office and online security, I recommend checking out the ATO’s article titled “Online Security” as it contains examples of past scams, and how to identify a fraudulant email.

Stay safe out there!

Folder Size Monitoring with Nagios and RRDtool

The RRDtool graph in GroundWork.

The RRDtool graph in GroundWork.

Recently at my place of employment we’ve had a few customers have their log folders explode in size and crash their servers. Since we already monitor OS X Servers using GroundWork, I decided to write my own folder size Nagios plugin checks folder sizes that alerts if they get too large, and returns performance data for use with RRDtool.

Bash Hokery

The Bash script called check_folder_size.sh (which can be obtained at the GitHub repo) should be uploaded to any folder on the OS X Server you want to monitor.

To test the script, cd into the directory where the Bash script is, then you can test it doing ./check_folder_size.sh -f /Library/Logs -w 1024 -c 2048.

Your required flags for the Bash script are:

  • f — the path for the folder you want to get the size for (wrap the path in “ double quotes if there’s a space)
  • w — the warning level (in MB).
  • c — the critical level (in MB).

And the one optional flag, which shouldn’t be used for this particular Nagios plugin, is:

  • m — block size for the folder (e.g. k for KB, m for MB and g for GB)

For your service check command line, enter something like this: check_by_ssh_folder_size!/Library/Logs/!m!1024!2048. See below:

  • check_by_ssh_folder_size — this is my command in Nagios for the check.
  • !/Library/Logs — the folder path for sizing up.
  • !m — we want return data in MB.
  • !1024 — the warning level in MB.
  • !2048 — the critical level in MB.

RRDtool Doo-Hickey

Below is the RRDtool create command (this is used in GroundWork, but may be used for other platforms)

$RRDTOOL$ create $RRDNAME$ --step 300 --start n-1yr $LISTSTART$ DS:$LABEL#$:GAUGE:95040:U:U DS:$LABEL#$_wn:GAUGE:95040:U:U DS:$LABEL#$_cr:GAUGE:95040:U:U $LISTEND$ RRA:AVERAGE:0.5:1:8640 RRA:AVERAGE:0.5:12:9480

And below is the RRDtool update command for each check that is performed. Here we update the RRD file with the last check time, the folder size in MB, the warning level and critical level.


Finally, we have the RRDtool graph command that generates a nice, custom graph for visual output of performance data.

rrdtool graph - \
--slope-mode \
--height 180 \
--grid-dash 1:2 \
--title="Folder Size" \
--base 1024 \
--units-exponent 0 \
--vertical-label "Size (in MB)" \
--imgformat=PNG \
DEF:a=rrd_source:ds_source_0:AVERAGE \
DEF:w=rrd_source:ds_source_1:AVERAGE \
DEF:c=rrd_source:ds_source_2:AVERAGE \
CDEF:cdefa=a \
CDEF:cdefw=w \
CDEF:cdefc=c \
AREA:a#54EC48:"Space Used" \
LINE:cdefa#24BC14: \
GPRINT:a:LAST:"Current\: %.0lf MB" \
GPRINT:a:AVERAGE:"Average\: %.0lf MB" \
GPRINT:a:MAX:"Maximum\: %.0lf MB\n" \
LINE2:cdefw#ECD748:"Warning Threshold\:" \
GPRINT:cdefw:LAST:"%.0lf MB" \
LINE2:cdefc#EA644A:"Critical Threshold\:" \
GPRINT:cdefc:LAST:"%.0lf MB\n" \
CDEF:cdefws=a,cdefw,GT,a,0,IF \
AREA:cdefws#ECD748 \
CDEF:cdefcs=a,cdefc,GT,a,0,IF \
AREA:cdefcs#EA644A \
-c GRID#C0C0C0 \
-c MGRID#404040 \

Explanation of the RRDtool graph

  • rrdtool graph - this will tell rrdtool that we’re making a graph, and the output will go to stdout (needed for GroundWork, otherwise you can put something like folder_size.png).
  • --slope-mode - this gives the graph a nice organic look, rather than the default step-like lines.
  • --height 180 - make the graph 180 pixels in height.
  • --grid-dash 1:2 - this will make the grid lines slightly dashed (1:3 ratio will make a dotted line).
  • --title "Folder Size" - gives the graph a nice large title.
  • --base 1024 - as we are graphing storage, we want the numbers in base 2.
  • --units-exponent 0 - this will prevent automatic y-axis scaling (it messes up my graph).
  • --vertical-label "Size (in MB)" - puts a label on the left-hand side of the graph (text is printed vertically).
  • --imgformat=PNG - format the output image as a PNG.
  • DEF:a=rrd_source:ds_source_0:AVERAGE - set a variable a with the value of the folder size in MB.
  • DEF:w=rrd_source:ds_source_1:AVERAGE - set a variable w (warning) with the warning level value.
  • DEF:c=rrd_source:ds_source_2:AVERAGE - set a variable c (critical) with the critical level value.
  • CDEF:cdefa/w/c=a/w/c - define more variables for later calculations.
  • AREA:a#54EC48:"Space Used" - define an area on the graph with the variable (a), and the colour (#54EC48) (colour is made with rgb components) and a legend “Space Used”.
  • LINE:cdefa#24BC14: - graph a line at the top of the main area.
  • GPRINT:a:LAST:"Current\: %.0lf MB" - print the text “Current: XXX MB” to the graph (on the same line as the text “Space Used”) which has the most recent rrd entry.
  • GPRINT:a:AVERAGE:"Average\: %.0lf MB" - print the text “Average: XXX MB” to the graph (on the same lines as the other text so far), which displays the average in MB.
  • GPRINT:a:MAX:"Maximum\: %.0lf MB\n" - print the text “Maximum: XXX MB” to the graph, along with a newline character at the end.
  • LINE2:cdefw#ECD748:"Warning Threshold\:" - draw a warning level line on the graph, with the rgb colour.
  • GPRINT:cdefc:LAST:"%.0lf MB" - print the warning level in MB.
  • LINE2:cdefc#EA644A:"Critical Threshold\:" - draw the critical level line on the graph.
  • GPRINT:cdefc:LAST:"%.0lf MB\n" - print the critical level in MB, along with a newline character.
  • CDEF:cdefws=a,cdefw,GT,a,0,IF - using a calculated define, we can work out if the folder size is larger than the folder size, and if it is, we’ll change the graph colour on the next line.
  • AREA:cdefws#ECD748 - using the calculation above, change the colour of the graph.
  • CDEF:cdefcs=a,cdefc,GT,a,0,IF - like above, do another calculation to see if the folder size is larger than the critical level.
  • AREA:cdefc#EA644A - as above, colour the graph to the appropriate colour if it reaches or goes over the critical threshold.
  • -c BACK#FFFFFF - change the background colour of the graph to white (#FFFFFF).
  • -c CANVAS#FFFFFF - change the colour of the graph canvas to white.
  • -c GRID#C0C0C0 - change the grid colour to a light-ish grey.
  • -c ARROW#FFFFFF - change the colour of the graph arrows to white, to hide them all together.
  • -Y - scale the graph to integers dynamically on the graph’s Y axis.

Once you’ve got this all set up, you should be getting wonderful graphs (like the one above), along with performance data.

My Favourite Album: OutRun by Kavinsky

For the past few months I’ve been listening to the album OutRun by Kavinsky. This album is a great driving album, and a wonderful programming mix. As a fan of 80s and 80s inspired music, this album blends the best of modern French house music, with the classic sounds of 80s electro.

Kavinskyโ€™s production style is very visceral and reminiscent of video game music and film soundtracks of the 80s.

- Last.fm Profile Page

The first track, Prelude, introduces the main character, a young male along with a red Ferrari Testarossa. After the introduction track we get the track 2 in the album, Blizzard, a punchy track with awesome synth-guitar riffs. This is easily one of my favourite tracks of all time, and certainly my favourite of the album. The guitar riffs combined with the hard-hitting bass drum kicks help set the tone of the album and Kavinsky’s style. Next, we get Protovision, another punchy track with an epic bass kick and fantastic synth lines. To me, Protovision is very reminiscent of the first Justice album, the stiff micro-sampled sounds make me think of tracks like Newjack, Phantom and DVNO. Fourth on the album is Odd Look, the first proper song of the album with vocals. Like the two preceding tracks, this song follows the trend of strong bass kicks and epic synth chords that are guaranteed to get anyone moving on the dance floor, or the office.

Next up is my second favourite track on the album, Rampage. Combining the mid and high-range synths with the solid bass drum kick, along with a muffled-sounding piano in the background, this is a fun track. I can imagine this track would be really epic when tied with a tough mission in a game like Call of Duty. After Rampage we get the rap track… Suburbia. While I can appreciate rap and hip-hop, I don’t really like the blend of rap and the 80s electro-synth this album is. Having said that, the story in the rap track does follow the theme of the album, talking about the character and his fast “Mars Red” Testarossa. After the rap track we have another punchy synth track, Testarossa Autodrive. I love the powerful synth riffs in this track, combined with the high-pitched synth that kicks in throughout the track, it’s a winner.

Nightcall, the eighth track in the album has great vocals and a sequenced synth. The robotic vocal doing the first part of each verse reminds me of Daft Punk’s robo-voice. I also find the female voice in the chorus to be hauntingly beautiful, combining great lyrics with a fantastic voice, I get chills every time I hear the chorus. Next up is Deadcrusier, a great warpy synth track with great deep synth riffs proving a nice bassey edge to the track. The warpy sounding synth hits home an epic track. Next is Grand Canyon, another of my favourite tracks. The super hard-hitting high-hats and synth lines make this track and epic track to listen to. I could easily listen to this track over and over again, the repetition of the track is catchy as heck!

After Grand Canyon is the track First Blood, an almost Van Halen influenced track with epic guitar lines. With a rock-themed vocalist and synth-guitar sounds this track is a rock epic. I have a feeling the solo was very Eddie Van Halen inspired. Next up is Roadgame which starts off with a great violin loop which changes pitch throughout the loops in the song. Combined with great synths and bass kicks, this is a fantastic track to bring us near the end of the album. Finally is Endless, the last track of the album brings the poignant story to a close with a nice piano loop and soft synths with a slow kick drum beat. The album is over :(

Oh yeah, and there’s a video game.

Please note that this is my first album review, my writing is sure to get better!

Working with OS X Caching Server's Max Cache Size Limits

The Caching Server pane in Server.app

The Caching Server pane in Server.app

Added in a recent version of OS X Server was the ability to provide an advanced software update feature called Caching Server. This enhanced the previous Software Update server features by including content from iTunes (i.e. iOS app updates and iBooks), along with providing an easy way for automatic server update selection (for those who are unfamiliar with Caching Server’s nifty features, check out the PDF on this page).

During setup you are required to select a volume for the cached updates to be stored. Depending on the size of this volume, the maximum size used slider can be rather useless. For example, when configuring my RAID enclosure (which has 8.8TB of useable space), the slider went from 30GB to 580GB in one step! This kind of limited selection is very frustrating. I want more than 30GB of cached updates, but I don’t want 580GB! Unfortunately, the current GUI slider steps in very high increments. Thankfully for us, using serveradmin through the terminal will save us.

If you want to see what limit Caching Server has set via the command line, you can do sudo serveradmin fullstatus caching then check out the line caching:CacheLimit. This number is shown in bytes and will convert nicely to a base 10 unit (otherwise known as SI), rather than the normal base 2.

For example, if you wanted to set a limit of 100GB, you would use the number 100000000000. That’s a lot of zeroes. Alternatively, 250GB would be 250000000000. To work out your storage conversion needs, I’d recommend checking out this converter here and use the Byte SI Decimal Prefix to convert to bytes.

Now that we’ve decided on how much space we’d like to use for Caching Server, lets tell it what we want. Open up a new Terminal window and using the command serveradmin settings caching:CacheLimit we can specify (in bytes) how much space we want to use. In my case, I wanted to use a maximum of 100GB for Caching Server. To do this, I enter the following:

sudo serveradmin settings caching:CacheLimit = 100000000000

After pressing return and running fullstatus on Caching Server (or opening the Caching tab in the Server app), you can now see that a maximum of 100GB will be used. Naturally, entering a different number will yield a different result in Server app (or the Terminal), but you get the picture.

SABnzbd+ for Status Board

Since making the iStat Server for Status Board script I’ve wanted to make more graphs for Status Board. Lo and behold, I use SABnzbd+ and it has an API. A graph is born:

SABnzbd Categories.

SABnzbd Categories.

The above graph collates all the downloads in the queue and counts them up then graphs them out, it’s pretty self explanatory really. Along side those bar graphs is the total of all items in the queue. Also available is a custom “Do-it-yourself” panel with core information about your SABnzbd+ server.

SABnzbd Info.

SABnzbd Info.

This pane is also pretty self explanatory. At the top you’ve got the version number of SABnzbd+, the current speed of your downloads, the status of the server (i.e. paused, downloading etc), and the size (in GBs) of what’s left to download in the queue. At this point in time, the info pane is only suitable for a 4x4 panel.

Jump over to the GitHub page to take a gander at the code and download it. Getting it set up is pretty easy, but if you’re stuck, I can provide limited support on the GitHub page, or via Twitter.

Please take a look and let me know if you find it useful!