Friday, March 1, 2013

Denominator: A Multi-Vendor Interface for DNS


by Adrian Cole and Adrian Cockcroft

Overview

We announced Denominator at our February NetflixOSS meetup, and now we are ready to release the first code as open source.  Denominator is a portable Java library for manipulating DNS clouds.  Denominator has pluggable back-ends, initially including AWS Route53, Neustar Ultra, DynECT, and a mock for testing.  We also ship a command line version so it's easy for anyone to try it out.
The reason we built Denominator is that we are working on multi-region failover and traffic sharing patterns to provide higher availability for the streaming service during regional outages caused by our own bugs and AWS issues. To do this we need to directly control the DNS configuration that routes users to each region and each zone. When we looked at the features and vendors in this space we found that we were already using AWS Route53, which has a nice API but is missing some advanced features; Neustar UltraDNS, which has a SOAP based API; and DynECT, which has a REST API that uses a quite different pseudo-transactional model.  We couldn’t find a Java based API that grouped together common set of capabilities that we are interested in, so we created one. The idea is that any feature that is supported by more than one vendor API is the highest common denominator, and that functionality can be switched between vendors as needed, or in the event of a DNS vendor outage.
With most of our NetflixOSS projects, we are running the code in production at the point where we open source it on github. In the case of Denominator we started off sharing the code with DNS vendors who helped us get the abstraction model right, and who are taking feedback to fix issues that we have uncovered in their APIs, and we are still fairly early in the development process. We are building Denominator to be as portable as possible, with few dependencies. We will initially embed it in services such as Edda, which collects the historical state of our cloud, and use the command line version in scripting to add simple records. We are also planning to develop a service that can manage and automate the DNS related operations that we will need to control multi-region traffic steering and failover. The Denominator project is being led by Adrian Cole, who is well known as the author of the cross platform jclouds open source project. He recently joined Netflix and is bringing a lot of valuable experience to our platform team.

Command Line Usage

The denominator cli is published on bintray.  When the code moves from active development to a more stable release we will publish installable packages. Installing it is as simple as downloading the file making it executable and running it.  The only prerequisite is a Java runtime.  Under the hood, the cli is wired together with airline and really executable.  This means you drop the "java -jar" and run it like any other binary, such as dig.
Here's an example of listing your zones:
chmod 755 denominator
./denominator -p ultradns -c username -c password zone list
If you are using denominator from an EC2 instance authorized for Route 53 via IAM, you can skip the credential arguments, and even detect your public ip:
./denominator -p route53 --zone foo.com. record add --name hostname.foo.com. --type A --ec2-public-ipv4
We will also have an expert mode for DNS savvy users, which accepts zone file format:
./denominator ... record add hostname.foo.com 3600 IN A 1.2.3.4

Library Structure and Features

Denominator is a pluggable library wired together with Dagger.  Creating a connection to a provider requires that you have access to two things: the name of the provider, and credentials for it.
manager = Denominator.create("ultradns", credentials(username, password));
The credentials are variable length, as certain providers require more that 2 parts.  This returns an instance of DNSApiManager where apis such as  ZoneApi are found.  In order to iterate through resources, you'd call list() such as below:
for (Iterator<String> zone = manager.getApi().getZoneApi().list(); zone.hasNext();) {
    processZone(zone.next());
}
The Denominator model is based on the ResourceRecordSet concept.  A ResourceRecordSet is simply a group of records who share the same name and type.  For example all address (A) records for the name netflix.com are aggregated into the same ResourceRecordSet.  The values of each record in a set are type-specific.  These data types are implemented as map-backed interfaces.  This affords both the strong typing of java and extensibility and versatility of maps.
For example, the following are identical:
mxData.getPreference();
mxData.get("preference");
Denominator is a work in progress, so if you are interested in getting involved, join the mailing list, hop on irc freenode #denominator or fork us on github! You can learn more about Denominator at the April 18 UJUG or at JAXConf.
Regardless, stop by in-person at our next NetflixOSS Meetup on March 13th to hear more about Denominator and other Netflix projects.