update pool record support in ultradns

This commit is contained in:
adriancole 2013-03-24 16:01:01 -07:00
parent a7dc94ea77
commit d9572151ae
8 changed files with 378 additions and 1 deletions

View File

@ -0,0 +1,62 @@
/**
* 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.binders;
import static java.lang.String.format;
import java.util.Map;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.MapBinder;
import org.jclouds.ultradns.ws.domain.UpdatePoolRecord;
/**
*
* @author Adrian Cole
*/
public class UpdatePoolRecordToXML implements MapBinder {
private static final String HEADER = "<v01:updatePoolRecord><transactionID /><poolRecordID>%s</poolRecordID><parentPoolId /><childPoolId />";
private static final String FOOTER = "</v01:updatePoolRecord>";
@SuppressWarnings("unchecked")
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
StringBuilder xml = new StringBuilder();
xml.append(format(HEADER, postParams.get("poolRecordID")));
UpdatePoolRecord update = UpdatePoolRecord.class.cast(postParams.get("update"));
xml.append("<pointsTo>").append(update.getPointsTo()).append("</pointsTo>");
xml.append("<priority>").append(update.getPriority()).append("</priority>");
xml.append("<failOverDelay>").append(update.getFailOverDelay()).append("</failOverDelay>");
xml.append("<ttl>").append(update.getTTL()).append("</ttl>");
xml.append("<weight>").append(update.getWeight()).append("</weight>");
xml.append("<mode>").append(update.getMode()).append("</mode>");
xml.append("<threshold>").append(update.getThreshold()).append("</threshold>");
xml.append(FOOTER);
return (R) request.toBuilder().payload(xml.toString()).build();
}
@Override
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
throw new UnsupportedOperationException("use map form");
}
}

View File

@ -0,0 +1,232 @@
/**
* 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;
/**
* holds updates for a record
*
* @author Adrian Cole
*/
public final class UpdatePoolRecord {
/**
* @param spec what to prime updates from
* @param pointsTo new value to point to.
*/
public static UpdatePoolRecord pointingTo(PoolRecordSpec spec, String pointsTo) {
return new Builder().from(spec).pointsTo(pointsTo).build();
}
private final String pointsTo;
private final String mode;
private final int priority;
private final int weight;
private final int failOverDelay;
private final int threshold;
private final int ttl;
private UpdatePoolRecord(String pointsTo, String mode, int priority, int weight, int failOverDelay, int threshold,
int ttl) {
this.pointsTo = checkNotNull(pointsTo, "pointsTo");
this.mode = checkNotNull(mode, "mode for %s", pointsTo);
this.priority = priority;
this.weight = weight;
checkArgument(weight >= 0, "weight of %s must be unsigned", pointsTo);
this.failOverDelay = failOverDelay;
checkArgument(failOverDelay >= 0, "failOverDelay of %s must be unsigned", pointsTo);
this.threshold = threshold;
checkArgument(threshold >= 0, "threshold of %s must be unsigned", pointsTo);
this.ttl = ttl;
checkArgument(ttl >= 0, "ttl of %s must be unsigned", pointsTo);
}
/**
* correlates to {@link TrafficControllerPoolRecord#getPointsTo()}
*/
public String getPointsTo() {
return pointsTo;
}
/**
* correlates to {@link PoolRecordSpec#getState()}
*/
public String getMode() {
return mode;
}
/**
* correlates to {@link PoolRecordSpec#getPriority()}
*/
public int getPriority() {
return priority;
}
/**
* correlates to {@link PoolRecordSpec#getWeight()}
*/
public int getWeight() {
return weight;
}
/**
* correlates to {@link PoolRecordSpec#getFailOverDelay()}
*/
public int getFailOverDelay() {
return failOverDelay;
}
/**
* correlates to {@link PoolRecordSpec#getThreshold()}
*/
public int getThreshold() {
return threshold;
}
/**
* correlates to {@link PoolRecordSpec#getTTL()}
*/
public int getTTL() {
return ttl;
}
@Override
public int hashCode() {
return Objects.hashCode(pointsTo, mode, priority, 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;
UpdatePoolRecord that = UpdatePoolRecord.class.cast(obj);
return equal(this.pointsTo, that.pointsTo) && equal(this.mode, that.mode) && equal(this.priority, that.priority)
&& 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("pointsTo", pointsTo).add("mode", mode).add("priority", priority)
.add("weight", weight).add("failOverDelay", failOverDelay).add("threshold", threshold).add("ttl", ttl)
.toString();
}
public static Builder builder() {
return new Builder();
}
public Builder toBuilder() {
return new Builder().from(this);
}
public final static class Builder {
private String pointsTo;
private String mode;
private int priority;
private int weight;
private int failOverDelay;
private int threshold;
private int ttl;
/**
* @see UpdatePoolRecord#getPointsTo()
*/
public Builder pointsTo(String pointsTo) {
this.pointsTo = pointsTo;
return this;
}
/**
* @see UpdatePoolRecord#getMode()
*/
public Builder mode(String mode) {
this.mode = mode;
return this;
}
/**
* @see UpdatePoolRecord#getPriority()
*/
public Builder priority(int priority) {
this.priority = priority;
return this;
}
/**
* @see UpdatePoolRecord#getWeight()
*/
public Builder weight(int weight) {
this.weight = weight;
return this;
}
/**
* @see UpdatePoolRecord#getFailOverDelay()
*/
public Builder failOverDelay(int failOverDelay) {
this.failOverDelay = failOverDelay;
return this;
}
/**
* @see UpdatePoolRecord#getThreshold()
*/
public Builder threshold(int threshold) {
this.threshold = threshold;
return this;
}
/**
* @see UpdatePoolRecord#getTTL()
*/
public Builder ttl(int ttl) {
this.ttl = ttl;
return this;
}
public UpdatePoolRecord build() {
return new UpdatePoolRecord(pointsTo, mode, priority, weight, failOverDelay, threshold, ttl);
}
public Builder from(PoolRecordSpec in) {
return this.mode(in.getState()).weight(in.getWeight()).failOverDelay(in.getFailOverDelay())
.threshold(in.getThreshold()).ttl(in.getTTL());
}
public Builder from(TrafficControllerPoolRecord in) {
return this.weight(in.getWeight()).pointsTo(in.getPointsTo()).priority(in.getPriority());
}
public Builder from(UpdatePoolRecord in) {
return this.pointsTo(in.pointsTo).mode(in.mode).priority(in.priority).weight(in.weight)
.failOverDelay(in.failOverDelay).threshold(in.threshold).ttl(in.ttl);
}
}
}

View File

@ -25,6 +25,7 @@ import org.jclouds.ultradns.ws.domain.PoolRecordSpec;
import org.jclouds.ultradns.ws.domain.ResourceRecord; import org.jclouds.ultradns.ws.domain.ResourceRecord;
import org.jclouds.ultradns.ws.domain.TrafficControllerPool; import org.jclouds.ultradns.ws.domain.TrafficControllerPool;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord; import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
import org.jclouds.ultradns.ws.domain.UpdatePoolRecord;
import com.google.common.collect.FluentIterable; import com.google.common.collect.FluentIterable;
@ -102,12 +103,26 @@ public interface TrafficControllerPoolApi {
* Retrieves information about the specified pool record * Retrieves information about the specified pool record
* *
* @param poolRecordID * @param poolRecordID
* {@see TrafficControllerPoolRecord#getId()} * {@link TrafficControllerPoolRecord#getId()}
* @return null if not found * @return null if not found
*/ */
@Nullable @Nullable
PoolRecordSpec getRecordSpec(String poolRecordID); PoolRecordSpec getRecordSpec(String poolRecordID);
/**
* This request updates an existing pool record.
*
* @param poolRecordID
* {@link TrafficControllerPoolRecord#getId()}
* @param update
* what to update, usually primed via
* {@link UpdatePoolRecord#pointingTo(PoolRecordSpec, String)} or
* {@link org.jclouds.ultradns.ws.domain.UpdatePoolRecord.Builder#from(PoolRecordSpec)}
* @throws ResourceNotFoundException
* if the record doesn't exist
*/
void updateRecord(String poolRecordID, UpdatePoolRecord update) throws ResourceNotFoundException;
/** /**
* deletes a specific pooled resource record * deletes a specific pooled resource record
* *

View File

@ -25,15 +25,18 @@ import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404; import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.Payload; import org.jclouds.rest.annotations.Payload;
import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost; import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser; import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.ultradns.ws.UltraDNSWSExceptions.ResourceAlreadyExistsException; import org.jclouds.ultradns.ws.UltraDNSWSExceptions.ResourceAlreadyExistsException;
import org.jclouds.ultradns.ws.binders.UpdatePoolRecordToXML;
import org.jclouds.ultradns.ws.domain.PoolRecordSpec; import org.jclouds.ultradns.ws.domain.PoolRecordSpec;
import org.jclouds.ultradns.ws.domain.TrafficControllerPool; import org.jclouds.ultradns.ws.domain.TrafficControllerPool;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord; import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
import org.jclouds.ultradns.ws.domain.UpdatePoolRecord;
import org.jclouds.ultradns.ws.filters.SOAPWrapWithPasswordAuth; import org.jclouds.ultradns.ws.filters.SOAPWrapWithPasswordAuth;
import org.jclouds.ultradns.ws.xml.AttributeHandler; import org.jclouds.ultradns.ws.xml.AttributeHandler;
import org.jclouds.ultradns.ws.xml.PoolRecordSpecHandler; import org.jclouds.ultradns.ws.xml.PoolRecordSpecHandler;
@ -122,6 +125,15 @@ public interface TrafficControllerPoolAsyncApi {
@Fallback(NullOnNotFoundOr404.class) @Fallback(NullOnNotFoundOr404.class)
ListenableFuture<PoolRecordSpec> getRecordSpec(@PayloadParam("poolRecordId") String poolRecordID); ListenableFuture<PoolRecordSpec> getRecordSpec(@PayloadParam("poolRecordId") String poolRecordID);
/**
* @see TrafficControllerPoolApi#getRecordSpec(String)
*/
@Named("updatePoolRecord>")
@POST
@MapBinder(UpdatePoolRecordToXML.class)
ListenableFuture<Void> updateRecord(@PayloadParam("poolRecordID") String poolRecordID,
@PayloadParam("update") UpdatePoolRecord update) throws ResourceNotFoundException;
/** /**
* @see TrafficControllerPoolApi#deleteRecord(String) * @see TrafficControllerPoolApi#deleteRecord(String)
*/ */

View File

@ -23,8 +23,10 @@ import static org.testng.Assert.assertNull;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.ultradns.ws.UltraDNSWSApi; import org.jclouds.ultradns.ws.UltraDNSWSApi;
import org.jclouds.ultradns.ws.UltraDNSWSExceptions.ResourceAlreadyExistsException; import org.jclouds.ultradns.ws.UltraDNSWSExceptions.ResourceAlreadyExistsException;
import org.jclouds.ultradns.ws.domain.UpdatePoolRecord;
import org.jclouds.ultradns.ws.internal.BaseUltraDNSWSApiExpectTest; import org.jclouds.ultradns.ws.internal.BaseUltraDNSWSApiExpectTest;
import org.jclouds.ultradns.ws.parse.GetPoolRecordSpecResponseTest; import org.jclouds.ultradns.ws.parse.GetPoolRecordSpecResponseTest;
import org.jclouds.ultradns.ws.parse.GetTCLoadBalancingPoolsByZoneResponseTest; import org.jclouds.ultradns.ws.parse.GetTCLoadBalancingPoolsByZoneResponseTest;
@ -172,6 +174,33 @@ public class TrafficControllerPoolApiExpectTest extends BaseUltraDNSWSApiExpectT
assertNull(notFound.getTrafficControllerPoolApiForZone("jclouds.org.").getRecordSpec("04053D8E57C7931F")); assertNull(notFound.getTrafficControllerPoolApiForZone("jclouds.org.").getRecordSpec("04053D8E57C7931F"));
} }
UpdatePoolRecord update = UpdatePoolRecord.builder()
.pointsTo("www.baz.com.")
.mode("Normal")
.weight(98)
.failOverDelay(0)
.threshold(1)
.ttl(200).build();
HttpRequest updateRecord = HttpRequest.builder().method("POST")
.endpoint("https://ultra-api.ultradns.com:8443/UltraDNS_WS/v01")
.addHeader("Host", "ultra-api.ultradns.com:8443")
.payload(payloadFromResourceWithContentType("/update_poolrecord.xml", "application/xml")).build();
HttpResponse updateRecordResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/poolrecord_updated.xml", "application/xml")).build();
public void testUpdateRecordWhenResponseIs2xx() {
UltraDNSWSApi success = requestSendsResponse(updateRecord, updateRecordResponse);
success.getTrafficControllerPoolApiForZone("jclouds.org.").updateRecord("04053D8E57C7931F", update);
}
@Test(expectedExceptions = ResourceNotFoundException.class, expectedExceptionsMessageRegExp = "Pool Record does not exist.")
public void testUpdateRecordWhenResponseNotFound() {
UltraDNSWSApi notFound = requestSendsResponse(updateRecord, recordDoesntExist);
notFound.getTrafficControllerPoolApiForZone("jclouds.org.").updateRecord("04053D8E57C7931F", update);
}
HttpRequest deleteRecord = HttpRequest.builder().method("POST") HttpRequest deleteRecord = HttpRequest.builder().method("POST")
.endpoint("https://ultra-api.ultradns.com:8443/UltraDNS_WS/v01") .endpoint("https://ultra-api.ultradns.com:8443/UltraDNS_WS/v01")
.addHeader("Host", "ultra-api.ultradns.com:8443") .addHeader("Host", "ultra-api.ultradns.com:8443")

View File

@ -35,6 +35,7 @@ import org.jclouds.ultradns.ws.domain.PoolRecordSpec;
import org.jclouds.ultradns.ws.domain.TrafficControllerPool; import org.jclouds.ultradns.ws.domain.TrafficControllerPool;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord; import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord;
import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord.Status; import org.jclouds.ultradns.ws.domain.TrafficControllerPoolRecord.Status;
import org.jclouds.ultradns.ws.domain.UpdatePoolRecord;
import org.jclouds.ultradns.ws.domain.Zone; import org.jclouds.ultradns.ws.domain.Zone;
import org.jclouds.ultradns.ws.internal.BaseUltraDNSWSApiLiveTest; import org.jclouds.ultradns.ws.internal.BaseUltraDNSWSApiLiveTest;
import org.testng.annotations.AfterClass; import org.testng.annotations.AfterClass;
@ -152,6 +153,12 @@ public class TrafficControllerPoolApiLiveTest extends BaseUltraDNSWSApiLiveTest
assertNull(api(zoneName).getRecordSpec("06063D9C54C5AE09")); assertNull(api(zoneName).getRecordSpec("06063D9C54C5AE09"));
} }
@Test(expectedExceptions = ResourceNotFoundException.class, expectedExceptionsMessageRegExp = "Pool Record does not exist.")
public void testUpdateRecordWhenNotFound() {
api(zoneName).updateRecord("06063D9C54C5AE09",
UpdatePoolRecord.builder().pointsTo("www.foo.com.").mode("Normal").build());
}
String hostname = "www.tcpool." + zoneName; String hostname = "www.tcpool." + zoneName;
String poolId; String poolId;
@ -223,6 +230,24 @@ public class TrafficControllerPoolApiLiveTest extends BaseUltraDNSWSApiLiveTest
} }
@Test(dependsOnMethods = "addCNAMERecordsToPool") @Test(dependsOnMethods = "addCNAMERecordsToPool")
public void testUpdateRecord() {
PoolRecordSpec spec = api(zoneName).getRecordSpec(cname2);
UpdatePoolRecord update = UpdatePoolRecord.builder().from(spec)
.pointsTo("www.baz.com.")
.weight(98)
.ttl(200).build();
api(zoneName).updateRecord(cname2, update);
TrafficControllerPoolRecord record = getRecordById(cname2).get();
assertEquals(record.getPointsTo(), "www.baz.com.");
spec = api(zoneName).getRecordSpec(cname2);
assertEquals(spec.getWeight(), 98);
assertEquals(spec.getTTL(), 200);
}
@Test(dependsOnMethods = "testUpdateRecord")
public void testDeleteRecord() { public void testDeleteRecord() {
api(zoneName).deleteRecord(cname1); api(zoneName).deleteRecord(cname1);
assertFalse(getRecordById(cname1).isPresent()); assertFalse(getRecordById(cname1).isPresent());

View File

@ -0,0 +1 @@
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns1:updatePoolRecordResponse xmlns:ns1="http://webservice.api.ultra.neustar.com/v01/"><result xmlns:ns2="http://schema.ultraservice.neustar.com/v01/">Successful</result></ns1:updatePoolRecordResponse></soap:Body></soap:Envelope>

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:updatePoolRecord><transactionID /><poolRecordID>04053D8E57C7931F</poolRecordID><parentPoolId /><childPoolId /><pointsTo>www.baz.com.</pointsTo><priority>0</priority><failOverDelay>0</failOverDelay><ttl>200</ttl><weight>98</weight><mode>Normal</mode><threshold>1</threshold></v01:updatePoolRecord></soapenv:Body></soapenv:Envelope>