December 13, 2009

Day 13 - Redundancy

This article was written by Matt Simmons.

Don't you just hate it when you're in the middle of a cross country flight, and all of a sudden the pilot gets on the intercom and announces that, due to the unfortunate loss of engine #2, you're going to crash and that maybe you should, you know, find peace with your maker or something?

But wait, that doesn't usually happen. Which is sort of funny, because airplane engines die all the time. Seriously. It's so common that the FAA doesn't even keep track of it. These pilots estimate that it happens somewhere between once every thousand hours and once every ten thousand hours. That seems pretty infrequent until you consider that there are, in any given day, around 30,000 commercial flights in the air over the United States. So every day that you wake up, go to work, and read the news, you don't hear about planes falling out of the sky, even though there's an excellent chance that somewhere that same day, a plane lost an engine. If you fly a lot, it might have happened on a flight you were on. You wouldn't know, they don't have to tell you or anything.

It's not a big deal because all but the smallest planes have multiple engines. If one of the two engines goes out, the plane still flies just fine.

A while back, airlines discovered something. Due to a quirk in how statistics work, if you double the number of engines, you also double the number of engine problems. It's only logical. You're not improving the engines by adding more, you're just making it more likely that one of your engines will fail. The useful part of this is that you're also decreasing the likelihood that all of the engines will fail.

If engines die once every hundred flights (completely fake, imaginary number, way too high), and you've only got one engine, you're only going to have an engine fail once every hundred flights. Unfortunately, that's going to be a very interesting flight for those passengers. If, however, you have two engines, you're going to have engine problems every 50 flights, but it's only going to be really tragic once every 10,000 flights or so, on average. This is why lots of big heavy planes that need two engines to fly actually have four engines, which makes it even MORE unlikely that there will be problems. Of course, as I said, there are lots of flights. Eventually, statistics bites you in the butt. If you click that link, you will see that there was actually a flight over the Indian Ocean that suffered five engine failures. And yet it still landed because of other safety features built into the plane.

In IT, we can learn a lot from the airline industry. They're one of the few fields with higher uptime requirements than ourselves, and they've been around for longer than we have. Over the course of their existence, they've learned a thing or two, and one of those things is that if you want your service to be available, you need to be redundant.


IT Infrastructure is really a collection of systems that work together to provide services. Each of these systems fall into Physical, Network, or Host category, and in order to build a truly fault tolerant infrastructure, each one of these layers must have independent redundancies.

The physical infrastructure deals with things such as the site, the server room itself, the rack, and the electricity. If you read that list again, you see a graduation from general (the site) to specific (electricity). This should also be mirrored in our redundancy plans.

One source of power is not enough. Every piece of equipment we use relies on electricity, and if the power fails, we're dead in the water. To combat this, if we're in a data center, we receive two power lines, each fed by completely separate power infrastructure. Each of the servers has two power supplies, which allows the power to be redundant.

As for the data center themselves, they feed you power from two independent systems which are fed by independent battery banks, which are powered by independent generators. High quality data centers use an N+1 or N+2 strategy. This means whenever it takes N pieces of equipment to do what they need, they've got 1 (or 2) more. Planes with 2 engine are N+1. Quad-engined planes are N+2.

If we're not in a high end data center, then we've got to approximate the equivalent of dual power sources. For that, we use Uninterruptible Power Supplies (UPS), which are fed through the standard power infrastructure, but also have a battery backup that takes over when line power fails. It's not as good as having two actual sources of power, but it's better than nothing.

The network infrastructure provides remote access to our resources. The services that we provide as an organization are made available through these systems, and if the network is down, the services are unavailable, regardless of the actual status of the machines.

To ensure that the network resources are always available, we use defense in depth.

Two uplink connections should be used when at all possible. In a data center, this means two network drops. In a smaller environment, this means take whatever your required connection is, then double it. If possible, use different providers, so that an outage by one won't affect the other.

For the local machine networks, having a single network connection to the switch is precarious. It's easy to get snagged and pulled loose. Network cards fail. Switch ports fail. If any of those things happen, the machine becomes unavailable. To prevent this from being a problem, modern servers come with two built in network cards. I used to wonder why, then I learned about interface bonding.

Of course, it's not enough to just run both cables to the same switch. That piece of equipment is pretty fragile, too. Switches fail sometimes, and every low and midrange switch I've seen only has one power supply, which means that if your power dies (see above), your network access dies. So get two switches, and run each NIC to its own switch.

Of course, this isn't just limited to ethernet networks. Storage networks are susceptible to the same damage, with possibly more dire ramifications to your data. Every storage networking technology that I'm aware of has the ability to do multipath, which functions analogously to interface bonding.

So now we have fault tolerant infrastructures underlying and connecting our hosts, but what about the hosts themselves? As I've indicated, modern servers are built with redundant parts to be fault tolerant. Many BIOSes have the ability to do RAM mirroring, and almost every server comes with RAID mirrors for the system drive. As important as these improvements are, things still happen. Motherboards blow up, people make mistakes, and even mirrored drives get erased with the wrong command.

To provide for this eventuality, we replicate entire machines. Using the right software, we can cluster our servers so that they act logically as one. This provides an additional level of redundancy that one server just can't give us.

Even redundant servers can't help a truly catastrophic event.

The above picture is the natural enemy of the network administrator. It is the fiber seeking backhoe, and it alone can wreck all of your carefully laid plans. With one small pull of a lever, it's gaping maw can chew through the heaviest armored fiber and take out several city blocks of internet. No providers will be spared. Make your time.

Fortunately, there is one defense. Unfortunately, it isn't easy or cheap.

The answer is, of course, to get a second site, somewhere far away from your primary site, and replicate the entire above configuration there. It's sort of like the equivalent of flying, but bringing another airplane along, just in case.

It takes time and planning to build a redundant, reliable infrastructure, and certainly, not every organization has the need for it, but if you do, you owe it to yourself and your company to do it right. Spend the time, learn, practice, and play. It's the only way to get better at what you do.

Further reading:

December 12, 2009

Day 12 - Managing User Expectations

This article written by Jason Dixon

Show me a carefree Systems Administrator, and I'll show you someone who doesn't interact with users. The typical End-User (userus idiotus) is a lazy creature, disposed towards foolishness and lacking in common sense. Although many of us are equipped with the prescience to avoid them, the Business Office (paycheckus routineous) demands that we cater to their whims and folly.

While it's fun to be a Bastard Operator From Hell, sometimes we just need to get along with our users. Managing those relationships is an important part of daily SA life, one that we frequently take for granted. Besides the fact that some of these folks are decent people, there are usually ancillary benefits (money, sanity, free beer) that go along with keeping them happy. I've developed a few guiding principles over the years that can help any bastard get along with his or her users.

Underpromise, Overdeliver

First, it's vitally important to set user expectations accordingly. Anxious users will expect that their problem is the most important thing on your plate, because it's the obstacle keeping them from getting work done. Resetting their expectations allows you to budget plenty of time to complete the task. And you'll be seen as the rock star Sys Admin that delivered the solution early.

Kevin: Pam, when will the new copier be ready?
Pam: I'm working on it Kev.
Kevin: You said it would be ready by today. And it is today.
Pam: It'll be ready soon.
Kevin: Soon could mean anything. Soon could be three weeks.
Pam: Is that what soon means to you?
Kevin: Sometimes...
Pam: Then come back soon.

Educate Without Patronizing

Believe it or not, there are scores of users who like to fix their own problems. They simply lack the skills to get it done or to avoid making it worse. Many of the common troubleshooting techniques we use each day can be passed on to others (checking cables, rebooting, minor software updates) if we take a few minutes to patiently walk them through it.

Teach, but don't condescend. Just because you have an aptitude for computers doesn't make you a genius. We each have our own areas of expertise. Theirs may be kicking you in the face.

Avoid the Mr. NO

Years ago, I had a bad habit of immediately saying "NO" to strange requests before fully vetting them. After a few minutes I would find myself reconsidering the problem and searching for whatever unorthodox solution presented itself. While the user was generally happy when these situations resolved themselves, the experience was probably confusing at best, and discouraging at worst. In all likelihood, this trigger response was a mechanism I'd developed for queuing up unusual requests.

Just say, "maybe." Your users will appreciate the candor. It gives you time to investigate the matter thoroughly (see: Underpromise, Overdeliver) and instills them with the belief that you're giving it your best shot.

Further reading:

December 11, 2009

Day 11 - Looking for Trouble

This article was written by John Arundel.

Good sysadmins use automation and monitoring, but good sysadmins don't rely only on this. The problem with automated monitoring, as we know from the movie Jurassic Park, is that you only find what you're looking for. Where are those pesky raptors, anyway?

Jurassic Park: when monitoring isn't enough.

The other night I was looking at the process list on a server and saw there were several copies of the nightly backup script running. I found that the script was trying to upload the backup tarball to a remote NAS, and as part of this process, it tried to delete the previous week's tarball. This file didn't exist, so the command was failing, but the script wasn't smart enough to handle this, so it just kept retrying. As a result, the backup never got properly copied offsite, and the machine was starting to become overloaded with backup jobs.

Why is this important? Many monitoring systems would not pick up this condition. Would yours? You may want to improve your monitoring to detect at least the following:

  • Check that the job actually ran by looking at the modified date on the job's logfile.
  • Check that the job terminated (look for a completion message in its log) and check its exit status.
  • If the job creates a file, check for the existence and the size of this file.
  • If something gets copied offsite, check the offsite copy and make sure it exists and matches the source file.

You get the idea. No automated monitoring system is perfect. A great way to improve it is to look at your servers with an open mind, and when you find problems you didn't expect, add monitoring checks to catch them. Jordan's article on Cron Practices is a good place to start improving the reliability of your cron jobs.

I found several other little gotchas in the backup script which needed fixing. It's easy to assume that a script that's been in production for years is free of bugs. That's almost certainly not the case, and many of those bugs won't be found until you go through the script with a critical eye. If you use version control and test-driven development for your scripts, as recommended by Hugh Brown in his Development for Sysadmins article, this will be a big help.

A good sysadmin is a good detective. You should make time as part of your job to pick on a random machine every so often and examine it forensically, like a crime scene. What's here that shouldn't be? Are things working like they're supposed to? Are there any problems with this machine that have gone unnoticed by the automatic monitoring?

Here are some places to look:

  • Logwatch output (ideally, have this mailed to you and read it every day).
  • Root's mailbox: errors from cron jobs will come here, as will mail bounces.
  • The syslog is a great resource, but often very large and hard to read. Try configuring your syslog.conf to send messages from different subsystems (mail, for example) to different logfiles.
  • The process list (ps or top). What's running that you don't expect to see? Is anything using an unusual amount of CPU? Is the machine spending more time in iowait than it should (may indicate a disk problem or a degraded RAID array).
  • The crontab (not all jobs may run as root, so go looking in the /etc/cron.* directories and /var/spool/cron). What jobs are running? Are they working? Should they be there? Is their output logged and monitored?
  • netstat, iostat, and vmstat anomalies.
  • Places you (and I) wouldn't think of. Go snooping. See what catches your eye. A detective looks without preconceptions, so she's ready to spot the unexpected.

I hope the above makes you suspicious and paranoid, in a good way - a way that makes you a better sysadmin. Anything that can go wrong will go wrong, and is going wrong somewhere on your network, right now. If you get into the habit of looking for trouble, you're sure to find it! Finding trouble is better than trouble finding you.

Further reading:

December 10, 2009

Day 10 - Solving Public Network Exposure with VPNs

This article was written by Nick Anderson.

Editor's note: I was going to make pretty diagrams as alternates to the ascii art below, but time ran out, so I wrapped them in cowsay instead. Please enjoy.

Most people are not lucky enough to deal with only private networks. Information needs to be accessible to a wide range of consumers. Whether it's working from home or accessing a website, how do you minimize exposure?

Most websites these days are backed by databases. Websites of any significant size typically have the database on a different host. Most commonly, the Application Server and Database Servers are in the same data-center (Note: I am ignoring geo-redundant scale here). How often do remote applications access a database directly? How often is remote shell access needed for management of a server? Now, how often are nefarious parties trying to shell into a publicly available servers? How can you minimize public exposure to services that do not need to be public facing but need to be accessible remotely?

A common solution is the notion of a Management Network and or Application Network. For our purposes we will combine the Management Network and Application Network into one Private Network. For this illustration we will assume a single public facing web server serving omg-estore.com that interfaces with two databases.

I've run into (and even setup in my earlier days ... shhh don't tell anyone) topologies that look like this.

 _____________________________
/                             \
|   (INTERNET)                |
|   -----------               |
|             |----(www1)     |
|             |---------(db1) |
|             |---------(db2) |
\                             /
 -----------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

www1 is the host that serves omg-estore.com, and db1 and db2 are master and slave databases. (Yes, I have ignored redundant application servers here; stop being so picky). All three machines are directly on the public network and talk to each other over the public network.

For security reasons, you probably don't want your databases accessible to the world, so how do we fix that? We can enable firewall policies: restrict remote shell access to specific ips and only allow database connections from www1. This isn't the best solution, though, as your servers are still on the public network. A firewall misconfiguration can expose your databases, so you should make security choices that are hard to accidentally break in a way that exposes you.

The first thing you should do is push the databases to a private network. This can be done with the simple addition of a dedicated nic or just bringing up a virtual interface (eth0:1) with the private subnet information. I prefer to use a dedicated nic as they can then connect to a fully private switch, and have access to a nics worth of bandwidth for database communications.

The first step:
 ___________________________________________
/                                           \
| (INTERNET)                                |
| -----------            (private net)      |
|           |----(www1)-----|               |
|                           |---------(db1) |
|                           |---------(db2) |
\                                           /
 -------------------------------------------
                               ,__,    /      
                           ____(oo)  /        
                         /(    (..)           
                        * ||--||              

This is much better: the database servers are no longer directly accessible on the internet. This change has decreased our exposed surface area by 2/3. Of course, to manage the db servers or the application server you will have to log in through the public facing application server. This makes the application server the a risk. To decrease exposure further, remote access to the public interface can be disabled.

Before disabling public remote shell access, you'll need to create a new access method. Enter the VPN. If it's not obvious at this point, your database servers should no longer have a public interface. If they do, they should be configured to only listen on the private network, or you should drop all connections on the left over public interface. The goal here is to only expose the services that need to serve public traffic.

The second step:
 ___________________________________________
/                                           \
| (INTERNET)                                |
| -----------            (private net)      |
|           |----(www1)-----|               |
|           |               |---------(db1) |
|           |               |---------(db2) |
|           |----(vpn1)-----|               |
\                                           /
 -------------------------------------------
  \
   \
       __     
      UooU\.'@@@@@@`.
      \__/(@@@@@@@@@@)
           (@@@@@@@@)
           `YY~~~~YY'
            ||    ||

This setup decreases exposure the most. Remote login is disabled on the public interfaces of www1 and vpn1. In order to log into any machines a vpn account is required on vpn1. Once on the vpn, access to the private interfaces of all machines can be gained.

This does not replace the need for continuing to follow best practices inside the private network. Database connections to the db servers should be limited to hosts that really need to connect to them. Host based firewalls can also be configured to limit source addresses of remote shell sessions.

Great! Now that all the theory is in place what software options are available to help us implement this?

First, ensure you choose a private subnet that is not in use anywhere else. Common subnets to avoid include 192.168.0.0/24, 192.168.1.0/24, 192.168.2.0/24, 172.16.0.0/16, 10.0.0.0/8. The first three being commonly used in SOHO equipment (think consumer-grade linksys/netgear home routers). Perhaps something like 192.168.30.0/24. Now that a subnet has been chosen, the VPN needs to be configured.

Luckily, some great open source tools make it pretty simple. OpenVPN is one such example. OpenVPN is an SSL-based VPN, so blocked access from a hotel or corporate firewall is unlikely (this is good for us admins that are on-call 24/7/365). Additionally, the clients are cross platform (Windows, Mac, Linux) and the setup is not difficult. In fact check out OpenVPN Access Server. OpenVPN Access Server is a package that adds a nice web interface and portal for VPN users in addition to giving you simple administration of giving you the VPN. It is free for 2 concurrent connections, if more than 2 concurrent connections are required the cost is five bucks per concurrent connection. Licenses must be purchased in packs of 10 at minimum, so a total cost to allow up to 12 concurrent connections is 50 bucks.

Putting your backend servers on a private, hidden network is an important step in reducing your public network attack surface. Since your private network is, well, private, you'll need to implement an access mechanism to permit you and others to manage the servers in the private network. Using a VPN to this access helps you secure external access to the private network.

Further reading:

December 9, 2009

Day 9 - What Time Is It?

Time is relative. No, I'm not talking about Einstein's relativity theory. Time is relative to geographies and synchronization sources. It's five o' clock, somewhere, right?

Time is a complex thing. Did you know there are a few bazillion time standards? Not just time representations, but actually standards on how to record and observe the passage of time! That's awesome! Further, learning about time standards helps explain why we have leap years and leap seconds.

Why do we care about time? Before we talk about why, let's first introduce some time representation formats.

Time formats for exchange and storage are also complex. ISO 8601 is a widely used and abused time format standard. This standard also supports durations (aka 30 seconds) and intervals (start and end timestamps), though I've never seen anything use ISO 8601 durations or intervals. Timestamps (ie; a point in time) are the focus of today, so we'll ignore durations and intervals. The problem with ISO 8601 is that it is huge and complex and supports a pile of different timestamp representations with all kinds of optional fields. This complexity has lead groups like the W3C and IETF to publish time format specifications that are similar to ISO 8601, but much simpler and reduced.

An example RFC 3339 timestamp looks like: 2009-12-09T00:45:58-08:00 (see RFC 3339 section 5.6). Like ISO 8601, RFC 3339 supports fractional seconds, so the following is also valid: 2009-12-09T00:45:58.335134-08:00.

The RFC does not specify a limit to the precision of the fractional seconds. This fractional seconds field is also the only optional field in RFC 3339; all other values must be present.

Another common time format is RFC-2822 (supercedes RFC-822). RFC-2822 section 3.3 covers time formats. This format has redundant fields and generally appears to be a format for the benefit of humans, not computers. It appears to be backwards compatible with RFC 822 time format. Mentionables about this format are that it uses abbreviated english names for months, does not support fractional seconds, and has some oddities in whitespace suggestions.

Text time formats aren't the only ones you need to be aware of. MySQL supports three time types, none of them superb. None of MySQL's time types support fractional seconds. DATETIME and TIMESTAMP lack timezone storage. DATE doesn't hold times. TIME doesn't hold dates. TIMESTAMP will convert to UTC on write and back to local time on read, but the mysql client needs to explain it's view of timezones external to any read or write. MySQL's leap second support is odd - you won't be able to detect if a stored timestamp is during a leapsecond due to a bug they had to work around in their mysql dump/restore with leap seconds.

Did you know Unix time doesn't support leap seconds? Neither did I. Apparently unix time is based on days since January 01, 1970. Every day, regardless of leap second, is 86400 seconds long, or so I've read. Leap second adjustments are pretty rare, but when they do happen, that 1 second change can make for some confusion during debugging. Next time you hear of a leap second being applied, mark it on your calendar so you don't forget.

Now we're getting into the 'why' that we should care about time. Like the MySQL example there are thousands of cases of software not using standard time formats. Almost every piece of software uses it's own logging time format, which brings me to my next point -

Time formats are a perfect example of what the programming world would say is mixing your data model and your view on that data. In this case, our data model is time, and the view is whatever format present it in. For example, in syslog, you'll see times like "Dec 6 11:51:04" and in Apache you'll see "02/Oct/2009:12:01:16 -0700". Nagios uses "[1253586479]" which is unix epoch.

Any random time format, depending on what it is needed for, can have one of a few problems. First, time formats often omit values: syslog doesn't often have year or timezone. Second, most time formats don't sort when compared: apache logs do not sort because the first value is the day. Finally, few things support or bother to use fractional seconds. Fractional seconds (micro/milli/nanoseconds) may not required for some applications, but it's something to be mindful of. Speaking of fractional seconds, standard libc strptime(3) cannot parse fractional seconds. Further, strptime(3) will not parse time zones.

A lack of common time format means that you can pick any two pieces of software in your system and have a high probability that they don't speak the same time format. This makes it very difficult to compare times across applications without writing custom parsers to convert (with awk, perl, whatever) times to a single format for comparison. This sucks, especially when (mentioned above) some parsing tools don't support time zones and fractional seconds.

The above highlights a common problem: having two tools speak different time languages makes for Great Sadness. I am quite annoyed that most software chooses to use their own randomly-created time format. You should be annoyed, too.

Time formats aren't the only problem. Having two devices out of time sync can cause many debugging headaches. There are even some protocols that require time to be synchronized. Kerberos for example will reject requests with timestamps too far out of sync with the server.

Use NTP to synchronize clocks across your servers.

As discussed above, lots of time formats do not include time zones. For your own sanity, you should standardize on a single time zone. UTC is a good choice as it does not use daylight savings time. Where applications allow, have them always show time in localtime but store time in UTC. If you are bad at converting UTC to localtime in your head, buy two wall clocks for your office and set one to UTC and one to local. Plus, having multiple wall clocks clearly increases the awesomeness of your office.

Lastly, be careful when you change the system time zone (on any operating system). Some processes don't check the timezone changes. For example, apache will continue to log in PST (-0800) even after you change /etc/localtime to use UTC - fixing this requires a restart of apache. The same problem may plague your cron, syslog, and other systems, depending on how they are implemented.

Time is hard. Keep your server and device clocks in sync, try to keep your software using the same time format, use a common time zone across your systems, and if you have the option, use time formats that don't drop things like year.

Further reading:

December 8, 2009

Day 8 - Cron Practices

Cron is just about everywhere. It's configuration and behavior is pretty similar across any platform:
  • every <scheduled time>, it runs your command as some user
  • output gets emailed to MAILTO= or $USER
Cron doesn't do everything I want by default. Here's what I want:
  • to prevent the same job from having overlapping execution.
  • want emailed output only on failures.
  • all output to be logged somewhere.
  • some jobs to timeout if they run too long.
  • randomize startup time to avoid resource contention.
It's easiest to first discuss each of these features individually.

For the rest of this article, we'll show various improvements to the following cron job that does a twice-daily backup of mysql.

0 0,12 * * * backupmysql.sh
The contents of our backupmysql.sh are:
#!/bin/sh

mysqldump ...
For simplicity, we omit the mysqldump arguments. Let's get on to addressing individual problems.

Overlapping jobs - Locks

Overlapping jobs can be prevented using locking. Last year, we covered lock file practices which can be applied to solve this. Simply pick a unique lockfile for each cronjob and wrap your cron job with flock(1) (or lockf(1) on FreeBSD).

Let's prevent two backups from running simultaneously. Additionally, we want to abort if we can't grab the lock. flock(1) defaults to waiting indefinitely, so let's set the wait time to 0 and use "/tmp/cron.backupmysql" as the lockfile:
#!/bin/sh

lockfile="/tmp/cron.backupmysql"
flock -w 0 $lockfile mysqldump ...

Emailed output only on failures

You don't necessarily need an email every time your job runs and succeeds. Personally, I only want to be contacted if there's a failure. In this case, we want to capture output somewhere and only emit the output if the exit status of something is nonzero.
#!/bin/sh

output=$(mktemp)
mysqldump ... > $output 2>&1

code=$?
if [ "$code" -ne 0 ] ; then
  echo "mysqldump exited with nonzero status: $code"
  cat $output
  rm $output
  exit $code
fi
rm $output

All output should be logged somewhere

Regardless of exit status, I always want the output of the job to be logged so we can audit it later. This is easily done with the logger(1) command.
#!/bin/sh

# pipe all output to syslog with tag 'backupmysql'
mysqldump ...  2>&1 | logger -t "backupmysql"

Some jobs need timeouts

Run-away cronjobs are bad. If you use locking as above to prevent overlaps, a stuck or frozen job can prevent any future jobs from running unless something causes the stuck or very-long job to die. For this, we'll need a tool to interrupt execution of a program after a timeout. I don't know if there's a canonical tool for this, so I wrote one for this artcle.

Download alarm.rb.

You'll need ruby for alarm.rb. We can now apply this to our backup script:

#!/bin/sh

alarm.rb 28800 mysqldump ...

This will abort if the mysqldump runtime exceeds 8 hours (28800 seconds). My alarm.rb will exit nonzero on timeouts, so if we use the email-on-error tip from above, we'll get notified on job timeouts.

Randomized startup

If you have lots of hosts all doing backups at the same time, your backup server may get overloaded. You can hand-schedule all your similar jobs to not run simultaneously on multiple hosts, or you can take a shortcut and randomize the startup time.

To do this in a shell script, you'll need something to generate random numbers for you. Doing this explicitly in shell requires a shell that can generate random numbers: bash, Solaris ksh, and zsh support the magic variable $RANDOM which evaluates to a random number between 0 and 32767. You'll also need something to map your random value across your sleep duration, we'll use bc(1) and bash(1) here (Even though zsh's $(( )) math operations support floats, bash seems more common).

#!/bin/bash

maxsleep=3600
sleeptime=$(echo "scale=8; ($RANDOM / 32768) * 3600" | bc | cut -d. -f1)
echo "Sleeping for $sleeptime before starting backupmysql."
sleep $sleeptime

mysqldump ...

Combining everything

Now let's combine all of the above into one super script. Doing all of the above cleanly and safely in bash is not the most trivial thing. Here is the result:

cronhelper.sh

Using cronhelper.sh is simple. It takes options as environment variables. Here's an example:

% TIMEOUT=5 JOBNAME=helloworld cronhelper.sh sh -c "echo hello world; sleep 10"
Job failed with status 254 (command: sh -c echo hello world; sleep 10)
hello world
/home/jls/bin/alarm.rb: Execution expired (timeout == 5.0)

# and in /var/log/messages:
Dec  8 02:58:02 snack helloworld[19565]: hello world
Dec  8 02:58:07 snack helloworld[19565]: /home/jls/bin/alarm.rb: Execution expired (timeout == 5.0)
Dec  8 02:58:07 snack helloworld[19573]: Job failed with status 254 (command: sh -c echo hello world; sleep 10)

Now armed with cronhelper.sh and alarm.rb, we can modify our cron job. Let us choose an 8 hour timeout and a 1 hour random startup delay:

0 0,12 * * * JOBNAME="backupmysql" SLEEPYSTART=3600 TIMEOUT=28800 cronhelper.sh backupmysql.sh
The new cron entry is now:
  • logging any output to syslog
  • only outputting to stdout when there's been a failure (and thus only emailing us on failures)
  • staggering startup across an hour
  • aborting after 8 hours if not finished
  • locking so overlapping runs are impossible
Using the tools above should help you build more reliable and less noisy cron jobs, which makes your systems more reliable and your pager more quiet.

Downloads:

Further reading:

December 7, 2009

Day 7 - Active Directory naming is easy, right?

This article was written by Sam Cogan

Active Directory naming is easy, right? You've just got to pick a name for your domain; any name will do won't it?

This is the view many newcomers to Active Directory (AD) take, and it's the view I had when I was first introduced to AD. It often works, even for a while. Then, a few days or weeks down the line, you start to notice problems, or with greater understanding of how AD works, you realise that perhaps there was a better name. By this time, it is too late - the name is set in stone. Sure, you could rename it with the domain name rename tool (rendom), but it's likely to cause problems. Let's look at why AD naming can be problematic and what we can do to make things better.

Microsoft's decision to tie Active Directory closely to DNS, while making sense, has caused a lot of problems for inexperienced sysadmins. One of the most common problems I hear from new sysadmins working with AD for the first time is, "I setup Active Directory with our company's external domain name, but now no-one can get to the company website or ftp site!"

Why does this happen? If your AD domain is example.com, AD will answer DNS queries for that domain, which likely fails to serve external services properly, such as your corp website at www.example.com.

Using your company's external domain name for DNS seems like the perfect idea at first. Limited understanding of how AD interacts with DNS has lead to a decision that may create problems and administrative overhead. Yes, there are potential solutions to this problem: implementing split brain (aka split view) DNS, changing your AD name, or installing IIS on every domain controller to perform redirects. But it's a scary prospect for a new sysadmin who's boss is about to explode because he can't get to their website and is often enough to put them off AD for good. So yes, you can use your external domain name for AD, but in my opinion, you shouldn't. It causes problems, so why give yourself the headache?

I've found there are a number of excuses people give for using the external domain name for AD, and I've used some of them myself. For example, "We had to use our external domain because we want to use that domain name for our UPN suffix". Truthfully, you can have as many UPN suffixes as you like by adding them in the Domains and Trusts MMC. Inexperience with AD may drive assumptions as above, but after digging into it, you will find that your assumptions may not be correct about what you think you need to use as your AD domain.

So, what AD domain name should we use? There are two common schools of thought on this subject: either something like example.local, or use a subdomain of your external domain (like corp.example.com, if you own example.com). Alternately, you can use a different external domain name, but this is not recommended for the general case.

The use of the .local extension came about because it allowed the separation of the AD domain from the registered internet domain (ie; example.com) without having to buy another domain. It's also easy to get an SSL certificate for a .local domain from a trusted SSL vendor, should you need one for internal resources. The alternative is to chose a real, unowned TLD to build your domain on, but you have the obvious risk of that domain being owned by someone else.

Maybe we have a good domain decision, now, with no extra cost? Maybe not! There are problems with using the .local domain. First, it's not a reserved TLD. While it's unlikely, it's possible that IANA could choose to delegate this TLD, opening it up for registration and causing potential name conflicts. Second, the use of .local can also cause problems if you have Apple computers on the network, as it is used by the Bonjour service. Finally, because .local domains are not controlled by a registrar, someone else could be using the same domain name in another AD instance. This problem will bite you when you need to establish trusts or merge domains with another AD instance - if both of you are using example.local you will have conflicts.

Despite these problems, the use of .local is still popular especially in small companies. Microsoft's Small Business server even suggests using this when using its configuration wizard to create an AD domain.

Besides naming with .local, you could choose the name as a subdomain of your external domain, such as ad.example.com, or buy an additional domain for AD only, such as examplecorp.com. Using something like ad.example.com or corp.example.com is pretty common today; Microsoft also recommends this. This is easy and ensures ownership of that domain (unless you forget to renew example.com). Using this method means that your AD DNS server is only responsible for this subdomain and will happily forward on requests for your external websites to servers.

AD naming seems easy, but as we've shown above, there are important considerations when choosing a domain name for your Active Directory domain. This advice, "be careful about seemingly-simple decisions," carries to many other spaces than AD.

Setting up an AD infrastructure should be planned carefully. The domain name choice should be a part of this planning. Consider how your network will be used, and how it will grow over time. If you don't own a public domain name, is it worth purchasing one now so you can ensure your AD domain name is reserved, even if you never use it on the internet. If you do have an external domain name already, try and keep your internal and external DNS separate, you'll appreciate it in the long run. Finally, never use a public domain name that you don't own, you never know who might snap it up and cause you problems!

Further reading: