Skip to content

Commit

Permalink
Adds Zone.ttl
Browse files Browse the repository at this point in the history
Zone.ttl is the SOA ttl. This is not always the default for new records.

See #357
  • Loading branch information
Adrian Cole committed Mar 31, 2015
1 parent 31b1842 commit 0b5f323
Show file tree
Hide file tree
Showing 25 changed files with 223 additions and 85 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
### Version 4.5
* Adds `Zone.email()` and displays it in CLI zone list output
* Adds `Zone.email()` and `Zone.ttl()` and displays them in CLI zone list output
* Adds `ZoneApi.iterateByName()` to support lookups
* Adds `-n` parameter to CLI zone list
* Deprecates `Zone.idOrName()` as `Zone.id()` cannot be null
Expand Down
2 changes: 1 addition & 1 deletion cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ If you just want to fool around, you can use the `mock` provider.
```bash
# first column is the zone id, which isn't always its name!
$ denominator -p mock zone list
denominator.io. denominator.io. admin.denominator.io.
denominator.io. denominator.io. admin.denominator.io. 86400
$ denominator -p mock -z denominator.io. record list
denominator.io. SOA 3600 ns1.denominator.io. admin.denominator.io. 1 3600 600 604800 60
denominator.io. NS 86400 ns1.denominator.io.
Expand Down
3 changes: 2 additions & 1 deletion cli/src/main/java/denominator/cli/Denominator.java
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,8 @@ public Iterator<String> doRun(final DNSApiManager mgr) {
return Iterators.transform(zones, new Function<Zone, String>() {
@Override
public String apply(Zone input) {
return format("%-24s %-36s %s", input.id(), input.name(), input.email());
return format("%-24s %-36s %-36s %d", input.id(), input.name(), input.email(),
input.ttl());
}
});
}
Expand Down
4 changes: 2 additions & 2 deletions cli/src/test/java/denominator/cli/DenominatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void listsAllProvidersWithCredentials() {
@Test // denominator -p mock zone list
public void testZoneList() {
assertThat(new ZoneList().doRun(mgr)).containsExactly(
"denominator.io. denominator.io. admin.denominator.io."
"denominator.io. denominator.io. admin.denominator.io. 86400"
);
}

Expand Down Expand Up @@ -226,7 +226,7 @@ public void testResourceRecordSetList() {
assertThat(command.doRun(mgr)).containsExactly(
"a.denominator.io. A alazona null 192.0.2.1",
"denominator.io. NS 86400 ns1.denominator.io.",
"denominator.io. SOA 3600 ns1.denominator.io. admin.denominator.io. 1 3600 600 604800 86400",
"denominator.io. SOA 86400 ns1.denominator.io. admin.denominator.io. 1 3600 600 604800 86400",
"server1.denominator.io. CERT 3600 12345 1 1 B33F",
"server1.denominator.io. SRV 3600 0 1 80 www.denominator.io.",
"www.geo.denominator.io. CNAME alazona 86400 a.denominator.io.",
Expand Down
51 changes: 49 additions & 2 deletions clouddns/src/main/java/denominator/clouddns/CloudDNSZoneApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
import javax.inject.Inject;

import denominator.clouddns.RackspaceApis.CloudDNS;
import denominator.clouddns.RackspaceApis.ListWithNext;
import denominator.model.Zone;

import static denominator.common.Util.singletonIterator;

class CloudDNSZoneApi implements denominator.ZoneApi {

private final CloudDNS api;
Expand All @@ -18,11 +21,55 @@ class CloudDNSZoneApi implements denominator.ZoneApi {

@Override
public Iterator<Zone> iterator() {
return api.domains().iterator();
return new ZipWithDomain(api.domains());
}

@Override
public Iterator<Zone> iterateByName(String name) {
return api.domainsByName(name).iterator();
ListWithNext<Zone> zones = api.domainsByName(name);
if (zones.isEmpty()) {
return singletonIterator(null);
}
return singletonIterator(zipWithDomain(zones.get(0)));
}

/**
* CloudDNS only exposes a domain's ttl in the show api.
*/
private Zone zipWithDomain(Zone next) {
int ttl = api.domain(next.id()).ttl();
return Zone.create(next.id(), next.name(), ttl, next.email());
}

class ZipWithDomain implements Iterator<Zone> {

ListWithNext<Zone> list;
int i = 0;
int length;

ZipWithDomain(ListWithNext<Zone> list) {
this.list = list;
this.length = list.size();
}

@Override
public boolean hasNext() {
while (i == length && list.next != null) {
list = api.domains(list.next);
length = list.size();
i = 0;
}
return i < length;
}

@Override
public Zone next() {
return zipWithDomain(list.get(i++));
}

@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,17 @@ protected Zone build(JsonReader reader) throws IOException {
String name = null, id = null, email = null;
while (reader.hasNext()) {
String nextName = reader.nextName();
if (nextName.equals("name")) {
name = reader.nextString();
} else if (nextName.equals("id")) {
if (nextName.equals("id")) {
id = reader.nextString();
} else if (nextName.equals("name")) {
name = reader.nextString();
} else if (nextName.equals("emailAddress")) {
email = reader.nextString();
} else {
reader.skipValue();
}
}
return Zone.create(name, id, email);
return Zone.create(id, name, /* CloudDNS only exposes ttl in the show api. */ 0, email);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ interface CloudDNS {
@RequestLine("GET /domains?name={name}")
ListWithNext<Zone> domainsByName(@Param("name") String name);

@RequestLine("GET")
ListWithNext<Zone> domains(URI href);

@RequestLine("GET /domains")
ListWithNext<Zone> domains();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import denominator.model.Zone;

import static denominator.assertj.ModelAssertions.assertThat;
import static denominator.clouddns.RackspaceApisTest.domainResponse;
import static denominator.clouddns.RackspaceApisTest.domainsResponse;

public class CloudDNSZoneApiMockTest {
Expand All @@ -20,15 +21,18 @@ public class CloudDNSZoneApiMockTest {
public void iteratorWhenPresent() throws Exception {
server.enqueueAuthResponse();
server.enqueue(new MockResponse().setBody(domainsResponse));
server.enqueue(new MockResponse().setBody(domainResponse));

ZoneApi api = server.connect().api().zones();

assertThat(api.iterator()).containsExactly(
Zone.create("denominator.io", "1234", "admin@denominator.io")
Zone.create("1234", "denominator.io", 3600, "admin@denominator.io")
);

server.assertAuthRequest();
server.assertRequest().hasPath("/v1.0/123123/domains");
server.assertRequest()
.hasPath("/v1.0/123123/domains/1234?showRecords=false&showSubdomains=false");
}

@Test
Expand All @@ -47,15 +51,18 @@ public void iteratorWhenAbsent() throws Exception {
public void iteratorByNameWhenPresent() throws Exception {
server.enqueueAuthResponse();
server.enqueue(new MockResponse().setBody(domainsResponse));
server.enqueue(new MockResponse().setBody(domainResponse));

ZoneApi api = server.connect().api().zones();

assertThat(api.iterateByName("denominator.io")).containsExactly(
Zone.create("denominator.io", "1234", "admin@denominator.io")
Zone.create("1234", "denominator.io", 3600, "admin@denominator.io")
);

server.assertAuthRequest();
server.assertRequest().hasPath("/v1.0/123123/domains?name=denominator.io");
server.assertRequest()
.hasPath("/v1.0/123123/domains/1234?showRecords=false&showSubdomains=false");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,17 @@ public void domainsPresent() throws Exception {
.hasPath("/v1.0/123123/domains");
}

/**
* Rackspace doesn't expose the ttl in domain list. A dummy TTL of zero is added as this result is
* never used directly.
*/
@Test
public void domainsByNamePresent() throws Exception {
server.enqueueAuthResponse();
server.enqueue(new MockResponse().setBody(domainsResponse));

assertThat(mockApi().domainsByName("denominator.io")).containsExactly(
Zone.create("denominator.io", "1234", "admin@denominator.io")
Zone.create("1234", "denominator.io", 0, "admin@denominator.io")
);

server.assertAuthRequest();
Expand Down Expand Up @@ -279,6 +283,9 @@ public Credentials get() {
static String
domainsResponse =
"{\"domains\":[{\"name\":\"denominator.io\",\"id\":1234,\"accountId\":123123,\"emailAddress\":\"admin@denominator.io\",\"updated\":\"2013-09-02T19:46:56.000+0000\",\"created\":\"2013-09-02T19:45:51.000+0000\"}],\"totalEntries\":1}";
static String
domainResponse =
"{\"name\":\"denominator.io\",\"id\":1234,\"accountId\":123123,\"ttl\": 3600,\"emailAddress\":\"admin@denominator.io\"}";
// NOTE records are allowed to be out of order by type
static String
recordsResponse =
Expand Down
12 changes: 6 additions & 6 deletions core/src/main/java/denominator/mock/MockZoneApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void create(String name) {
zone.add(ResourceRecordSet.builder()
.type("SOA")
.name(name)
.ttl(3600)
.ttl(86400)
.add(SOAData.builder().mname("ns1." + name).rname("admin." + name)
.serial(1).refresh(3600).retry(600).expire(604800).minimum(86400).build())
.build());
Expand All @@ -64,13 +64,13 @@ public boolean hasNext() {
public Zone next() {
Entry<String, Collection<ResourceRecordSet<?>>> next = delegate.next();
String name = next.getKey();
Iterator<ResourceRecordSet<?>> soa =
Iterator<ResourceRecordSet<?>> soas =
filter(next.getValue().iterator(), nameAndTypeEqualTo(name, "SOA"));

checkState(soa.hasNext(), "SOA record for zone %s was not present", name);

SOAData soaData = (SOAData) soa.next().records().get(0);
return Zone.create(name, name, soaData.rname());
checkState(soas.hasNext(), "SOA record for zone %s was not present", name);
ResourceRecordSet<SOAData> soa = (ResourceRecordSet<SOAData>) soas.next();
SOAData soaData = soa.records().get(0);
return Zone.create(name, name, soa.ttl(), soaData.rname());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ public void testImplicitDynamicCredentialsUpdate() {
DNSApiManager mgr = create(new DynamicCredentialsProvider());
ZoneApi zones = mgr.api().zones();
assertThat(zones.iterator())
.containsExactly(Zone.create("acme", "wily", "coyote"));
.containsExactly(Zone.create("acme", "wily", 86400, "coyote"));
assertThat(zones.iterator())
.containsExactly(Zone.create("acme", "road", "runner"));
.containsExactly(Zone.create("acme", "road", 86400, "runner"));

// now, if the supplier doesn't supply a set of credentials, we should
// get a correct message
Expand Down Expand Up @@ -118,7 +118,7 @@ public Iterator<Zone> iterator() {
CustomerUsernamePassword cup = creds.get();
// normally, the credentials object would be used to invoke a remote
// command. in this case, we don't and say we did :)
return asList(Zone.create(cup.customer, cup.username, cup.password)).iterator();
return asList(Zone.create(cup.customer, cup.username, 86400, cup.password)).iterator();
}

@Override
Expand Down
27 changes: 26 additions & 1 deletion core/src/test/java/denominator/ReadOnlyLiveTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class ReadOnlyLiveTest {
public DNSApiManager manager;

@Test
public void zoneIdentification() {
public void supportsDuplicateZoneNames() {
Iterator<Zone> zones = manager.api().zones().iterator();
assumeTrue("No zones to test", zones.hasNext());
Zone zone = zones.next();
Expand All @@ -38,6 +38,31 @@ public void iterateZonesByName() {
assumeTrue("No zones to test", zones.hasNext());
Zone zone = zones.next();
assertThat(manager.api().zones().iterateByName(zone.name())).contains(zone);

ResourceRecordSet<?>
soa =
manager.api().basicRecordSetsInZone(zone.id()).getByNameAndType(zone.name(), "SOA");

if (soa != null) {
assertThat(zone.ttl())
.overridingErrorMessage("zone %s should have the same ttl as soa %s", zone, soa)
.isEqualTo(soa.ttl());
}
}

@Test
public void zoneTtlIsEqualToSOATtl() {
Iterator<Zone> zones = manager.api().zones().iterator();
assumeTrue("No zones to test", zones.hasNext());
Zone zone = zones.next();
ResourceRecordSet<?>
soa =
manager.api().basicRecordSetsInZone(zone.id()).getByNameAndType(zone.name(), "SOA");
assumeTrue("SOA records aren't exposed", soa != null);

assertThat(zone.ttl())
.overridingErrorMessage("zone %s should have the same ttl as soa %s", zone, soa)
.isEqualTo(soa.ttl());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,22 @@ protected String jsonKey() {

protected Zone build(JsonReader reader) throws IOException {
String name = null, id = null, email = null;
int ttl = -1;
while (reader.hasNext()) {
String nextName = reader.nextName();
if (nextName.equals("name")) {
name = reader.nextString();
} else if (nextName.equals("id")) {
if (nextName.equals("id")) {
id = reader.nextString();
} else if (nextName.equals("name")) {
name = reader.nextString();
} else if (nextName.equals("ttl")) {
ttl = reader.nextInt();
} else if (nextName.equals("email")) {
email = reader.nextString();
} else {
reader.skipValue();
}
}
return Zone.create(name, id, email);
return Zone.create(id, name, ttl, email);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void domainsPresent() throws Exception {
server.enqueue(new MockResponse().setBody(domainsResponse));

assertThat(mockApi().domains()).containsExactly(
Zone.create("denominator.io.", domainId, "admin@denominator.io")
Zone.create(domainId, "denominator.io.", 3600, "admin@denominator.io")
);

server.assertAuthRequest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void iteratorWhenPresent() throws Exception {
ZoneApi api = server.connect().api().zones();

assertThat(api.iterator()).containsExactly(
Zone.create("denominator.io.", domainId, "admin@denominator.io")
Zone.create(domainId, "denominator.io.", 3600, "admin@denominator.io")
);

server.assertAuthRequest();
Expand All @@ -52,7 +52,7 @@ public void iteratorByNameWhenPresent() throws Exception {
ZoneApi api = server.connect().api().zones();

assertThat(api.iterateByName("denominator.io.")).containsExactly(
Zone.create("denominator.io.", domainId, "admin@denominator.io")
Zone.create(domainId, "denominator.io.", 3600, "admin@denominator.io")
);

server.assertAuthRequest();
Expand Down
10 changes: 5 additions & 5 deletions dynect/src/main/java/denominator/dynect/DynECTZoneApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ public Iterator<Zone> iterateByName(String name) {
}

private Zone fromSOA(String name) {
Iterator<ResourceRecordSet<?>> soa = api.rrsetsInZoneByNameAndType(name, name, "SOA").data;
checkState(soa.hasNext(), "SOA record for zone %s was not present", name);

SOAData soaData = (SOAData) soa.next().records().get(0);
return Zone.create(name, name, soaData.rname());
Iterator<ResourceRecordSet<?>> soas = api.rrsetsInZoneByNameAndType(name, name, "SOA").data;
checkState(soas.hasNext(), "SOA record for zone %s was not present", name);
ResourceRecordSet<SOAData> soa = (ResourceRecordSet<SOAData>) soas.next();
SOAData soaData = soa.records().get(0);
return Zone.create(name, name, soa.ttl(), soaData.rname());
}
}
Loading

0 comments on commit 0b5f323

Please sign in to comment.