added ability to get the specification of an ultradns pool record by id

This commit is contained in:
adriancole 2013-03-24 10:42:45 -07:00
parent 179a0ea30a
commit 83ddeb10ab
9 changed files with 441 additions and 3 deletions

View File

@ -0,0 +1,236 @@
/**
* 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.Objects.equal;
import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects;
/**
* specifications and status of a current record in the pool.
*
* @author Adrian Cole
*/
public final class PoolRecordSpec {
private final String description;
private final String state;
private final boolean probingEnabled;
private final boolean allFailEnabled;
private final int weight;
private final int failOverDelay;
private final int threshold;
private final int ttl;
private PoolRecordSpec(String description, String state, boolean probingEnabled, boolean allFailEnabled, int weight,
int failOverDelay, int threshold, int ttl) {
this.description = checkNotNull(description, "description");
this.state = checkNotNull(state, "state for %s", description);
this.probingEnabled = probingEnabled;
this.allFailEnabled = allFailEnabled;
this.weight = weight;
checkArgument(weight >= 0, "weight of %s must be unsigned", description);
this.failOverDelay = failOverDelay;
checkArgument(failOverDelay >= 0, "failOverDelay of %s must be unsigned", description);
this.threshold = threshold;
checkArgument(threshold >= 0, "threshold of %s must be unsigned", description);
this.ttl = ttl;
checkArgument(ttl >= 0, "ttl of %s must be unsigned", description);
}
/**
* correlates to {@link TrafficControllerPoolRecord#getDescription()}
*/
public String getDescription() {
return description;
}
/**
* known values include {@code Normal} and {@code Normal-NoTest}
*/
public String getState() {
return state;
}
/**
* correlates to {@link TrafficControllerPoolRecord#isProbingEnabled()}
*/
public boolean isProbingEnabled() {
return probingEnabled;
}
/**
* undocumented
*/
public boolean isAllFailEnabled() {
return allFailEnabled;
}
/**
* correlates to {@link TrafficControllerPoolRecord#getWeight()}
*/
public int getWeight() {
return weight;
}
/**
* at the time of writing, between 030 (minutes).
*/
public int getFailOverDelay() {
return failOverDelay;
}
/**
* how many probes in a region must fail in order for this to fail.
*/
public int getThreshold() {
return threshold;
}
/**
* The resource record cache time to live (TTL), in seconds.
*/
public int getTTL() {
return ttl;
}
@Override
public int hashCode() {
return Objects
.hashCode(description, state, probingEnabled, allFailEnabled, weight, failOverDelay, threshold, ttl);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PoolRecordSpec that = PoolRecordSpec.class.cast(obj);
return equal(this.description, that.description) && equal(this.state, that.state)
&& equal(this.probingEnabled, that.probingEnabled) && equal(this.allFailEnabled, that.allFailEnabled)
&& equal(this.weight, that.weight) && equal(this.failOverDelay, that.failOverDelay)
&& equal(this.threshold, that.threshold) && equal(this.ttl, that.ttl);
}
@Override
public String toString() {
return toStringHelper(this).add("description", description).add("state", state)
.add("probingEnabled", probingEnabled).add("allFailEnabled", allFailEnabled).add("weight", weight)
.add("failOverDelay", failOverDelay).add("threshold", threshold).add("ttl", ttl).toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return builder().from(this);
}
public final static class Builder {
private String description;
private String state;
private boolean probingEnabled;
private boolean allFailEnabled;
private int weight;
private int failOverDelay;
private int threshold;
private int ttl;
/**
* @see PoolRecordSpec#getDescription()
*/
public Builder description(String description) {
this.description = description;
return this;
}
/**
* @see PoolRecordSpec#getState()
*/
public Builder state(String state) {
this.state = state;
return this;
}
/**
* @see PoolRecordSpec#isProbingEnabled()
*/
public Builder probingEnabled(boolean probingEnabled) {
this.probingEnabled = probingEnabled;
return this;
}
/**
* @see PoolRecordSpec#isAllFailEnabled()
*/
public Builder allFailEnabled(boolean allFailEnabled) {
this.allFailEnabled = allFailEnabled;
return this;
}
/**
* @see PoolRecordSpec#getWeight()
*/
public Builder weight(int weight) {
this.weight = weight;
return this;
}
/**
* @see PoolRecordSpec#getFailOverDelay()
*/
public Builder failOverDelay(int failOverDelay) {
this.failOverDelay = failOverDelay;
return this;
}
/**
* @see PoolRecordSpec#getThreshold()
*/
public Builder threshold(int threshold) {
this.threshold = threshold;
return this;
}
/**
* @see PoolRecordSpec#getTTL()
*/
public Builder ttl(int ttl) {
this.ttl = ttl;
return this;
}
public PoolRecordSpec build() {
return new PoolRecordSpec(description, state, probingEnabled, allFailEnabled, weight, failOverDelay,
threshold, ttl);
}
public Builder from(PoolRecordSpec in) {
return this.description(in.description).state(in.state).probingEnabled(in.probingEnabled)
.allFailEnabled(in.allFailEnabled).weight(in.weight).failOverDelay(in.failOverDelay)
.threshold(in.threshold).ttl(in.ttl);
}
}
}

View File

@ -18,8 +18,10 @@
*/
package org.jclouds.ultradns.ws.features;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.ultradns.ws.UltraDNSWSExceptions.ResourceAlreadyExistsException;
import org.jclouds.ultradns.ws.domain.PoolRecordSpec;
import org.jclouds.ultradns.ws.domain.ResourceRecord;
import org.jclouds.ultradns.ws.domain.TrafficControllerPool;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
@ -86,6 +88,16 @@ public interface TrafficControllerPoolApi {
*/
String addRecordToPoolWithTTL(String pointsTo, String lbPoolID, int ttl) throws ResourceAlreadyExistsException;
/**
* Retrieves information about the specified pool record
*
* @param poolRecordID
* {@see TrafficControllerPoolRecord#getId()}
* @return null if not found
*/
@Nullable
PoolRecordSpec getRecordSpec(String poolRecordID);
/**
* deletes a specific pooled resource record
*

View File

@ -21,6 +21,7 @@ package org.jclouds.ultradns.ws.features;
import javax.inject.Named;
import javax.ws.rs.POST;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.rest.annotations.Fallback;
@ -30,10 +31,12 @@ import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.ultradns.ws.UltraDNSWSExceptions.ResourceAlreadyExistsException;
import org.jclouds.ultradns.ws.domain.PoolRecordSpec;
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.IDHandler;
import org.jclouds.ultradns.ws.xml.PoolRecordSpecHandler;
import org.jclouds.ultradns.ws.xml.TrafficControllerPoolListHandler;
import org.jclouds.ultradns.ws.xml.TrafficControllerPoolRecordListHandler;
@ -98,6 +101,16 @@ public interface TrafficControllerPoolAsyncApi {
ListenableFuture<String> addRecordToPoolWithTTL(@PayloadParam("pointsTo") String pointsTo,
@PayloadParam("poolID") String lbPoolID, @PayloadParam("ttl") int ttl) throws ResourceAlreadyExistsException;
/**
* @see TrafficControllerPoolApi#getRecordSpec(String)
*/
@Named("getPoolRecordSpec>")
@POST
@Payload("<v01:getPoolRecordSpec><poolRecordId>{poolRecordId}</poolRecordId></v01:getPoolRecordSpec>")
@XMLResponseParser(PoolRecordSpecHandler.class)
@Fallback(NullOnNotFoundOr404.class)
ListenableFuture<PoolRecordSpec> getRecordSpec(@PayloadParam("poolRecordId") String poolRecordID);
/**
* @see TrafficControllerPoolApi#deleteRecord(String)
*/

View File

@ -0,0 +1,71 @@
/**
* 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.PoolRecordSpec;
import org.xml.sax.Attributes;
/**
*
* @author Adrian Cole
*/
public class PoolRecordSpecHandler extends ParseSax.HandlerForGeneratedRequestWithResult<PoolRecordSpec> {
private final PoolRecordSpec.Builder builder = PoolRecordSpec.builder();
@Override
public PoolRecordSpec getResult() {
return builder.build();
}
@Override
public void startElement(String url, String name, String qName, Attributes attrs) {
if (!equalsOrSuffix(qName, "PoolRecordSpecData")) {
return;
}
Map<String, String> attributes = cleanseAttributes(attrs);
builder.description(attributes.get("description"))
.state(attributes.get("recordState"));
builder.probingEnabled(trueIfEnabled(attributes, "probing"))
.allFailEnabled(trueIfEnabled(attributes, "allFail"));
builder.weight(asInt(attributes, "weight"))
.failOverDelay(asInt(attributes, "failOverDelay"))
.threshold(asInt(attributes, "threshold"))
.ttl(asInt(attributes, "ttl"));
}
private boolean trueIfEnabled(Map<String, String> attributes, String name) {
return "ENABLED".equalsIgnoreCase(attributes.get(name));
}
private int asInt(Map<String, String> attributes, String name) {
return parseInt(checkNotNull(attributes.get(name), name));
}
}

View File

@ -19,12 +19,14 @@
package org.jclouds.ultradns.ws.features;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.ultradns.ws.UltraDNSWSApi;
import org.jclouds.ultradns.ws.UltraDNSWSExceptions.ResourceAlreadyExistsException;
import org.jclouds.ultradns.ws.internal.BaseUltraDNSWSApiExpectTest;
import org.jclouds.ultradns.ws.parse.GetPoolRecordSpecResponseTest;
import org.jclouds.ultradns.ws.parse.GetTCLoadBalancingPoolsByZoneResponseTest;
import org.jclouds.ultradns.ws.parse.GetTCPoolRecordsResponseTest;
import org.testng.annotations.Test;
@ -130,6 +132,28 @@ public class TrafficControllerPoolApiExpectTest extends BaseUltraDNSWSApiExpectT
already.getTrafficControllerPoolApiForZone("jclouds.org.").addRecordToPoolWithTTL("1.2.3.4", "04053D8E57C7931F", 300);
}
HttpRequest getRecordSpec = HttpRequest.builder().method("POST")
.endpoint("https://ultra-api.ultradns.com:8443/UltraDNS_WS/v01")
.addHeader("Host", "ultra-api.ultradns.com:8443")
.payload(payloadFromResourceWithContentType("/get_poolrecordspec.xml", "application/xml")).build();
HttpResponse getRecordSpecResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/poolrecordspec.xml", "application/xml")).build();
public void testGetRecordSpecWhenResponseIs2xx() {
UltraDNSWSApi success = requestSendsResponse(getRecordSpec, getRecordSpecResponse);
assertEquals(success.getTrafficControllerPoolApiForZone("jclouds.org.").getRecordSpec("04053D8E57C7931F"),
new GetPoolRecordSpecResponseTest().expected());
}
HttpResponse recordDoesntExist = HttpResponse.builder().message("Server Error").statusCode(500)
.payload(payloadFromResource("/tcrecord_doesnt_exist.xml")).build();
public void testGetRecordSpecWhenResponseNotFound() {
UltraDNSWSApi notFound = requestSendsResponse(getRecordSpec, recordDoesntExist);
assertNull(notFound.getTrafficControllerPoolApiForZone("jclouds.org.").getRecordSpec("04053D8E57C7931F"));
}
HttpRequest deleteRecord = HttpRequest.builder().method("POST")
.endpoint("https://ultra-api.ultradns.com:8443/UltraDNS_WS/v01")
.addHeader("Host", "ultra-api.ultradns.com:8443")
@ -143,9 +167,6 @@ public class TrafficControllerPoolApiExpectTest extends BaseUltraDNSWSApiExpectT
success.getTrafficControllerPoolApiForZone("jclouds.org.").deleteRecord("04053D8E57C7931F");
}
HttpResponse recordDoesntExist = HttpResponse.builder().message("Server Error").statusCode(500)
.payload(payloadFromResource("/tcrecord_doesnt_exist.xml")).build();
public void testDeleteRecordWhenResponseNotFound() {
UltraDNSWSApi notFound = requestSendsResponse(deleteRecord, recordDoesntExist);
notFound.getTrafficControllerPoolApiForZone("jclouds.org.").deleteRecord("04053D8E57C7931F");

View File

@ -96,6 +96,19 @@ public class TrafficControllerPoolApiLiveTest extends BaseUltraDNSWSApiLiveTest
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);
return record;
}
static PoolRecordSpec checkPoolRecordSpec(PoolRecordSpec record) {
checkNotNull(record.getDescription(), "Description cannot be null for %s", record);
checkNotNull(record.getState(), "State cannot be null for %s", record);
// TODO: collect all possible states then consider enum
assertTrue(ImmutableSet.of("Normal", "Normal-NoTest").contains(record.getState()), "Unknown State for " + record);
assertTrue(record.getWeight() >= 0, "Weight must be unsigned for " + record);
assertTrue(record.getFailOverDelay() >= 0, "failOverDelay must be unsigned for " + record);
assertTrue(record.getThreshold() >= 0, "threshold must be unsigned for " + record);
assertTrue(record.getTTL() >= 0, "ttl must be unsigned for " + record);
return record;
}
@Test(expectedExceptions = ResourceNotFoundException.class, expectedExceptionsMessageRegExp = "Zone does not exist in the system.")

View File

@ -0,0 +1,61 @@
/**
* 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.PoolRecordSpec;
import org.jclouds.ultradns.ws.xml.PoolRecordSpecHandler;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(testName = "GetPoolRecordSpecResponseTest")
public class GetPoolRecordSpecResponseTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/poolrecordspec.xml");
PoolRecordSpec expected = expected();
PoolRecordSpecHandler handler = injector.getInstance(PoolRecordSpecHandler.class);
PoolRecordSpec result = factory.create(handler).parse(is);
assertEquals(result, expected);
assertEquals(result.hashCode(), expected.hashCode());
assertEquals(result.toString(), expected.toString());
}
public PoolRecordSpec expected() {
return PoolRecordSpec.builder()
.description("foo")
.state("Normal-NoTest")
.probingEnabled(false)
.allFailEnabled(false)
.weight(2)
.failOverDelay(0)
.threshold(1)
.ttl(120).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:getPoolRecordSpec><poolRecordId>04053D8E57C7931F</poolRecordId></v01:getPoolRecordSpec></soapenv:Body></soapenv:Envelope>

View File

@ -0,0 +1,10 @@
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:getPoolRecordSpecResponse
xmlns:ns1="http://webservice.api.ultra.neustar.com/v01/">
<PoolRecordSpecData xmlns:ns2="http://schema.ultraservice.neustar.com/v01/"
description="foo" recordState="Normal-NoTest" probing="DISABLED"
allFail="DISABLED" weight="2" failOverDelay="0" threshold="1" ttl="120" />
</ns1:getPoolRecordSpecResponse>
</soap:Body>
</soap:Envelope>