Merge pull request #1451 from jclouds/ultradns-tcpoolrecord-list

add ability to read ultradns traffic controller pool records
This commit is contained in:
Adrian Cole 2013-03-23 17:13:26 -07:00
commit 4267c55745
9 changed files with 528 additions and 4 deletions

View File

@ -0,0 +1,290 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ultradns.ws.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
/**
*
* @author Adrian Cole
*/
public final class TrafficControllerPoolRecord {
private final String id;
private final String poolId;
private final String pointsTo;
private final int weight;
private final int priority;
private final String type;
private final String forceAnswer;
private final boolean probingEnabled;
private final Status status;
private final boolean serving;
private final String description;
private TrafficControllerPoolRecord(String id, String poolId, String pointsTo, int weight, int priority,
String type, String forceAnswer, boolean probingEnabled, Status status, boolean serving, String description) {
this.id = checkNotNull(id, "id");
this.poolId = checkNotNull(poolId, "poolId for %s", id);
this.pointsTo = checkNotNull(pointsTo, "pointsTo for %s", poolId);
checkArgument(weight >= 0, "weight of %s must be unsigned", id);
this.weight = weight;
checkArgument(priority >= 0, "priority of %s must be unsigned", id);
this.priority = priority;
this.type = checkNotNull(type, "type for %s", poolId);
this.forceAnswer = checkNotNull(forceAnswer, "forceAnswer for %s", poolId);
this.probingEnabled = probingEnabled;
this.status = checkNotNull(status, "status for %s", poolId);
this.serving = serving;
this.description = checkNotNull(description, "description for %s", description);
}
/**
* The ID of the zone.
*/
public String getId() {
return id;
}
/**
* The pool this record belongs to.
*/
public String getPoolId() {
return poolId;
}
/**
* address or cname this points to. ex. {@code jclouds.org.} or
* {@code 1.2.3.4}
*/
public String getPointsTo() {
return pointsTo;
}
/**
* 0 or even numbers from 2100. Determines the traffic load to send to each
* server in a Traffic Controller pool. The value 0 indicates that Traffic
* Controller always serves the record.
*/
public int getWeight() {
return weight;
}
/**
* the default value is 1. The value 0 is the special All Fail priority.
*/
public int getPriority() {
return priority;
}
/**
* the type of the record, either {@code A} or {@code CNAME}
*/
public String getType() {
return type;
}
public String getForceAnswer() {
return forceAnswer;
}
public boolean isProbingEnabled() {
return probingEnabled;
}
/**
* status of the record
*/
public Status getStatus() {
return status;
}
public boolean isServing() {
return serving;
}
/**
* description of the record
*/
public String getDescription() {
return description;
}
public static enum Status {
OK, DISABLED, UNRECOGNIZED;
public static Status fromValue(String status) {
try {
return valueOf(checkNotNull(status, "status"));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
@Override
public int hashCode() {
return Objects.hashCode(id, poolId);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TrafficControllerPoolRecord that = TrafficControllerPoolRecord.class.cast(obj);
return Objects.equal(this.id, that.id) && Objects.equal(this.poolId, that.poolId);
}
@Override
public String toString() {
return Objects.toStringHelper(this).add("id", id).add("poolId", poolId).add("pointsTo", pointsTo)
.add("weight", weight).add("priority", priority).add("type", type).add("forceAnswer", forceAnswer)
.add("probingEnabled", probingEnabled).add("status", status).add("serving", serving)
.add("description", description).toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().from(this);
}
public final static class Builder {
private String id;
private String poolId;
private String pointsTo;
private int weight;
private int priority;
private String type;
private String forceAnswer;
private boolean probingEnabled;
private Status status;
private boolean serving;
private String description;
/**
* @see TrafficControllerPoolRecord#getId()
*/
public Builder id(String id) {
this.id = id;
return this;
}
/**
* @see TrafficControllerPoolRecord#getPoolId()
*/
public Builder poolId(String poolId) {
this.poolId = poolId;
return this;
}
/**
* @see TrafficControllerPoolRecord#getPointsTo()
*/
public Builder pointsTo(String pointsTo) {
this.pointsTo = pointsTo;
return this;
}
/**
* @see TrafficControllerPoolRecord#getWeight()
*/
public Builder weight(int weight) {
this.weight = weight;
return this;
}
/**
* @see TrafficControllerPoolRecord#getPriority()
*/
public Builder priority(int priority) {
this.priority = priority;
return this;
}
/**
* @see TrafficControllerPoolRecord#getType()
*/
public Builder type(String type) {
this.type = type;
return this;
}
/**
* @see TrafficControllerPoolRecord#getForceAnswer()
*/
public Builder forceAnswer(String forceAnswer) {
this.forceAnswer = forceAnswer;
return this;
}
/**
* @see TrafficControllerPoolRecord#isProbingEnabled()
*/
public Builder probingEnabled(boolean probingEnabled) {
this.probingEnabled = probingEnabled;
return this;
}
/**
* @see TrafficControllerPoolRecord#getStatus()
*/
public Builder status(Status status) {
this.status = status;
return this;
}
/**
* @see TrafficControllerPoolRecord#isServing()
*/
public Builder serving(boolean serving) {
this.serving = serving;
return this;
}
/**
* @see TrafficControllerPoolRecord#getDescription()
*/
public Builder description(String description) {
this.description = description;
return this;
}
public TrafficControllerPoolRecord build() {
return new TrafficControllerPoolRecord(id, poolId, pointsTo, weight, priority, type, forceAnswer,
probingEnabled, status, serving, description);
}
public Builder from(TrafficControllerPoolRecord in) {
return this.id(in.id).poolId(in.poolId).weight(in.weight).pointsTo(in.pointsTo).priority(in.priority)
.type(in.type).forceAnswer(in.forceAnswer).probingEnabled(in.probingEnabled).status(in.status)
.serving(in.serving).description(in.description);
}
}
}

View File

@ -20,6 +20,7 @@ package org.jclouds.ultradns.ws.features;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.ultradns.ws.domain.TrafficControllerPool;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
import com.google.common.collect.FluentIterable;
@ -36,4 +37,12 @@ public interface TrafficControllerPoolApi {
* if the zone doesn't exist
*/
FluentIterable<TrafficControllerPool> list() throws ResourceNotFoundException;
/**
* Returns all records in the traffic controller pool.
*
* @throws ResourceNotFoundException
* if the pool doesn't exist
*/
FluentIterable<TrafficControllerPoolRecord> listRecords(String poolId) throws ResourceNotFoundException;
}

View File

@ -23,12 +23,15 @@ import javax.ws.rs.POST;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.ultradns.ws.domain.TrafficControllerPool;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
import org.jclouds.ultradns.ws.filters.SOAPWrapWithPasswordAuth;
import org.jclouds.ultradns.ws.xml.TrafficControllerPoolListHandler;
import org.jclouds.ultradns.ws.xml.TrafficControllerPoolRecordListHandler;
import com.google.common.collect.FluentIterable;
import com.google.common.util.concurrent.ListenableFuture;
@ -51,4 +54,15 @@ public interface TrafficControllerPoolAsyncApi {
@XMLResponseParser(TrafficControllerPoolListHandler.class)
@Payload("<v01:getLoadBalancingPoolsByZone><zoneName>{zoneName}</zoneName><lbPoolType>TC</lbPoolType></v01:getLoadBalancingPoolsByZone>")
ListenableFuture<FluentIterable<TrafficControllerPool>> list() throws ResourceNotFoundException;
/**
* @see TrafficControllerPoolApi#listRecords(String)
*/
@Named("getPoolRecords")
@POST
@XMLResponseParser(TrafficControllerPoolRecordListHandler.class)
@Payload("<v01:getPoolRecords><poolId>{poolId}</poolId></v01:getPoolRecords>")
ListenableFuture<FluentIterable<TrafficControllerPoolRecord>> listRecords(@PayloadParam("poolId") String poolId)
throws ResourceNotFoundException;
}

View File

@ -0,0 +1,68 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ultradns.ws.xml;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.Integer.parseInt;
import static org.jclouds.util.SaxUtils.cleanseAttributes;
import static org.jclouds.util.SaxUtils.equalsOrSuffix;
import java.util.Map;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord.Status;
import org.xml.sax.Attributes;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
/**
*
* @author Adrian Cole
*/
public class TrafficControllerPoolRecordListHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<FluentIterable<TrafficControllerPoolRecord>> {
private final Builder<TrafficControllerPoolRecord> records = ImmutableSet.<TrafficControllerPoolRecord> builder();
@Override
public FluentIterable<TrafficControllerPoolRecord> getResult() {
return FluentIterable.from(records.build());
}
@Override
public void startElement(String url, String name, String qName, Attributes attrs) {
if (!equalsOrSuffix(qName, "PoolRecordData"))
return;
Map<String, String> attributes = cleanseAttributes(attrs);
records.add(TrafficControllerPoolRecord.builder()
.id(attributes.get("poolRecordID"))
.poolId(attributes.get("poolId"))
.pointsTo(attributes.get("pointsTo"))
.weight(parseInt(checkNotNull(attributes.get("weight"), "weight")))
.priority(parseInt(checkNotNull(attributes.get("priority"), "priority")))
.type(attributes.get("recordType"))
.forceAnswer(attributes.get("forceAnswer"))
.probingEnabled("ENABLED".equalsIgnoreCase(attributes.get("probing")))
.status(Status.valueOf(attributes.get("status")))
.serving("Yes".equalsIgnoreCase(attributes.get("serving")))
.description(attributes.get("description")).build());
}
}

View File

@ -25,6 +25,7 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.ultradns.ws.UltraDNSWSApi;
import org.jclouds.ultradns.ws.internal.BaseUltraDNSWSApiExpectTest;
import org.jclouds.ultradns.ws.parse.GetTCLoadBalancingPoolsByZoneResponseTest;
import org.jclouds.ultradns.ws.parse.GetTCPoolRecordsResponseTest;
import org.testng.annotations.Test;
/**
@ -47,4 +48,21 @@ public class TrafficControllerPoolApiExpectTest extends BaseUltraDNSWSApiExpectT
assertEquals(success.getTrafficControllerPoolApiForZone("jclouds.org.").list().toString(),
new GetTCLoadBalancingPoolsByZoneResponseTest().expected().toString());
}
HttpRequest listRecords = HttpRequest.builder().method("POST")
.endpoint("https://ultra-api.ultradns.com:8443/UltraDNS_WS/v01")
.addHeader("Host", "ultra-api.ultradns.com:8443")
.payload(payloadFromResourceWithContentType("/list_tcrecords.xml", "application/xml")).build();
HttpResponse listRecordsResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/tcrecords.xml", "application/xml")).build();
public void testListRecordsWhenResponseIs2xx() {
UltraDNSWSApi success = requestSendsResponse(listRecords, listRecordsResponse);
assertEquals(
success.getTrafficControllerPoolApiForZone("jclouds.org.").listRecords("04053D8E57C7931F").toString(),
new GetTCPoolRecordsResponseTest().expected().toString());
}
}

View File

@ -19,10 +19,13 @@
package org.jclouds.ultradns.ws.features;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertTrue;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.ultradns.ws.domain.Account;
import org.jclouds.ultradns.ws.domain.TrafficControllerPool;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord.Status;
import org.jclouds.ultradns.ws.domain.Zone;
import org.jclouds.ultradns.ws.internal.BaseUltraDNSWSApiLiveTest;
import org.testng.annotations.BeforeClass;
@ -44,10 +47,10 @@ public class TrafficControllerPoolApiLiveTest extends BaseUltraDNSWSApiLiveTest
}
private void checkTCPool(TrafficControllerPool pool) {
checkNotNull(pool.getZoneId(), "ZoneId cannot be null for a TrafficControllerPool %s", pool);
checkNotNull(pool.getId(), "Id cannot be null for a TrafficControllerPool %s", pool);
checkNotNull(pool.getName(), "Name cannot be null for a TrafficControllerPool %s", pool);
checkNotNull(pool.getDName(), "DName cannot be null for a TrafficControllerPool %s", pool);
checkNotNull(pool.getZoneId(), "ZoneId cannot be null for %s", pool);
checkNotNull(pool.getId(), "Id cannot be null for %s", pool);
checkNotNull(pool.getName(), "Name cannot be null for %s", pool);
checkNotNull(pool.getDName(), "DName cannot be null for %s", pool);
}
@Test
@ -59,6 +62,29 @@ public class TrafficControllerPoolApiLiveTest extends BaseUltraDNSWSApiLiveTest
}
}
@Test
public void testListTCPoolRecords() {
for (Zone zone : context.getApi().getZoneApi().listByAccount(account.getId())) {
for (TrafficControllerPool pool : api(zone.getName()).list()) {
for (TrafficControllerPoolRecord record : api(zone.getName()).listRecords(pool.getId())) {
checkTrafficControllerPoolRecord(record);
}
}
}
}
static void checkTrafficControllerPoolRecord(TrafficControllerPoolRecord record) {
checkNotNull(record.getId(), "Id cannot be null for %s", record);
checkNotNull(record.getPoolId(), "PoolId cannot be null for %s", record);
checkNotNull(record.getPointsTo(), "PointsTo cannot be null for %s", record);
assertTrue(record.getWeight() >= 0, "Weight must be unsigned for " + record);
assertTrue(record.getPriority() >= 0, "Priority must be unsigned for " + record);
checkNotNull(record.getType(), "Type cannot be null for %s", record);
checkNotNull(record.getStatus(), "Status cannot be null for %s", record);
assertTrue(record.getStatus() != Status.UNRECOGNIZED, "unrecognized status for " + record);
checkNotNull(record.getDescription(), "Description cannot be null for %s", record);
}
@Test(expectedExceptions = ResourceNotFoundException.class, expectedExceptionsMessageRegExp = "Zone does not exist in the system.")
public void testListTCPoolsWhenZoneIdNotFound() {
api("AAAAAAAAAAAAAAAA").list();

View File

@ -0,0 +1,80 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.ultradns.ws.parse;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord.Status;
import org.jclouds.ultradns.ws.xml.TrafficControllerPoolRecordListHandler;
import org.testng.annotations.Test;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
*/
@Test(testName = "GetTCPoolRecordsResponseTest")
public class GetTCPoolRecordsResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/tcrecords.xml");
FluentIterable<TrafficControllerPoolRecord> expected = expected();
TrafficControllerPoolRecordListHandler handler = injector.getInstance(TrafficControllerPoolRecordListHandler.class);
FluentIterable<TrafficControllerPoolRecord> result = factory.create(handler).parse(is);
assertEquals(result.toSet().toString(), expected.toSet().toString());
}
public FluentIterable<TrafficControllerPoolRecord> expected() {
return FluentIterable.from(ImmutableSet.<TrafficControllerPoolRecord> builder()
.add(TrafficControllerPoolRecord.builder()
.id("0000000000000001")
.poolId("0000000000000001")
.pointsTo("canary.jclouds.org.")
.weight(2)
.priority(2)
.type("CNAME")
.forceAnswer("Normal")
.probingEnabled(true)
.status(Status.OK)
.serving(true)
.description("canary app").build())
.add(TrafficControllerPoolRecord.builder()
.id("0000000000000002")
.poolId("0000000000000001")
.pointsTo("prod.jclouds.org.")
.weight(98)
.priority(1)
.type("CNAME")
.forceAnswer("Normal")
.probingEnabled(true)
.status(Status.OK)
.serving(true)
.description("prod app").build())
.build());
}
}

View File

@ -0,0 +1 @@
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v01="http://webservice.api.ultra.neustar.com/v01/"><soapenv:Header><wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsse:UsernameToken><wsse:Username>identity</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">credential</wsse:Password></wsse:UsernameToken></wsse:Security></soapenv:Header><soapenv:Body><v01:getPoolRecords><poolId>04053D8E57C7931F</poolId></v01:getPoolRecords></soapenv:Body></soapenv:Envelope>

View File

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:getPoolRecordsResponse
xmlns:ns1="http://webservice.api.ultra.neustar.com/v01/">
<PoolRecordsList xmlns:ns2="http://schema.ultraservice.neustar.com/v01/">
<ns2:PoolRecordData poolRecordID="0000000000000001"
poolId="0000000000000001" pointsTo="canary.jclouds.org." weight="2"
priority="2" recordType="CNAME" forceAnswer="Normal" probing="ENABLED"
status="OK" serving="Yes" description="canary app" />
<ns2:PoolRecordData poolRecordID="0000000000000002"
poolId="0000000000000001" pointsTo="prod.jclouds.org." weight="98"
priority="1" recordType="CNAME" forceAnswer="Normal" probing="ENABLED"
status="OK" serving="Yes" description="prod app" />
</PoolRecordsList>
</ns1:getPoolRecordsResponse>
</soap:Body>
</soap:Envelope>