From bd0fc715d0e484412b01ab9944c91532b0b4ef26 Mon Sep 17 00:00:00 2001 From: adriancole Date: Sat, 23 Mar 2013 10:25:32 -0700 Subject: [PATCH] add ability to read ultradns traffic controller pool records --- .../domain/TrafficControllerPoolRecord.java | 290 ++++++++++++++++++ .../ws/features/TrafficControllerPoolApi.java | 9 + .../TrafficControllerPoolAsyncApi.java | 14 + ...rafficControllerPoolRecordListHandler.java | 68 ++++ .../TrafficControllerPoolApiExpectTest.java | 18 ++ .../TrafficControllerPoolApiLiveTest.java | 34 +- .../parse/GetTCPoolRecordsResponseTest.java | 80 +++++ .../src/test/resources/list_tcrecords.xml | 1 + .../src/test/resources/tcrecords.xml | 18 ++ 9 files changed, 528 insertions(+), 4 deletions(-) create mode 100644 providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/TrafficControllerPoolRecord.java create mode 100644 providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/TrafficControllerPoolRecordListHandler.java create mode 100644 providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/parse/GetTCPoolRecordsResponseTest.java create mode 100644 providers/ultradns-ws/src/test/resources/list_tcrecords.xml create mode 100644 providers/ultradns-ws/src/test/resources/tcrecords.xml diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/TrafficControllerPoolRecord.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/TrafficControllerPoolRecord.java new file mode 100644 index 0000000000..061aaf6ab7 --- /dev/null +++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/domain/TrafficControllerPoolRecord.java @@ -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 2–100. 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); + } + } +} diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApi.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApi.java index e74861c0fc..b4d3e95e32 100644 --- a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApi.java +++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApi.java @@ -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 list() throws ResourceNotFoundException; + + /** + * Returns all records in the traffic controller pool. + * + * @throws ResourceNotFoundException + * if the pool doesn't exist + */ + FluentIterable listRecords(String poolId) throws ResourceNotFoundException; } diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolAsyncApi.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolAsyncApi.java index 7c1a8c5620..44e1d26224 100644 --- a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolAsyncApi.java +++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolAsyncApi.java @@ -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("{zoneName}TC") ListenableFuture> list() throws ResourceNotFoundException; + + /** + * @see TrafficControllerPoolApi#listRecords(String) + */ + @Named("getPoolRecords") + @POST + @XMLResponseParser(TrafficControllerPoolRecordListHandler.class) + @Payload("{poolId}") + ListenableFuture> listRecords(@PayloadParam("poolId") String poolId) + throws ResourceNotFoundException; + } diff --git a/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/TrafficControllerPoolRecordListHandler.java b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/TrafficControllerPoolRecordListHandler.java new file mode 100644 index 0000000000..7e84c35eef --- /dev/null +++ b/providers/ultradns-ws/src/main/java/org/jclouds/ultradns/ws/xml/TrafficControllerPoolRecordListHandler.java @@ -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> { + + private final Builder records = ImmutableSet. builder(); + + @Override + public FluentIterable getResult() { + return FluentIterable.from(records.build()); + } + + @Override + public void startElement(String url, String name, String qName, Attributes attrs) { + if (!equalsOrSuffix(qName, "PoolRecordData")) + return; + Map 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()); + } +} diff --git a/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApiExpectTest.java b/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApiExpectTest.java index e903aa5ca2..69d894495a 100644 --- a/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApiExpectTest.java +++ b/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApiExpectTest.java @@ -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()); + } + } diff --git a/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApiLiveTest.java b/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApiLiveTest.java index fd3358f89d..8833b53e23 100644 --- a/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApiLiveTest.java +++ b/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/features/TrafficControllerPoolApiLiveTest.java @@ -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(); diff --git a/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/parse/GetTCPoolRecordsResponseTest.java b/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/parse/GetTCPoolRecordsResponseTest.java new file mode 100644 index 0000000000..4e753cd51a --- /dev/null +++ b/providers/ultradns-ws/src/test/java/org/jclouds/ultradns/ws/parse/GetTCPoolRecordsResponseTest.java @@ -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 expected = expected(); + + TrafficControllerPoolRecordListHandler handler = injector.getInstance(TrafficControllerPoolRecordListHandler.class); + FluentIterable result = factory.create(handler).parse(is); + + assertEquals(result.toSet().toString(), expected.toSet().toString()); + } + + public FluentIterable expected() { + return FluentIterable.from(ImmutableSet. 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()); + } + +} \ No newline at end of file diff --git a/providers/ultradns-ws/src/test/resources/list_tcrecords.xml b/providers/ultradns-ws/src/test/resources/list_tcrecords.xml new file mode 100644 index 0000000000..6b09704e1c --- /dev/null +++ b/providers/ultradns-ws/src/test/resources/list_tcrecords.xml @@ -0,0 +1 @@ +identitycredential04053D8E57C7931F \ No newline at end of file diff --git a/providers/ultradns-ws/src/test/resources/tcrecords.xml b/providers/ultradns-ws/src/test/resources/tcrecords.xml new file mode 100644 index 0000000000..0d8518be6a --- /dev/null +++ b/providers/ultradns-ws/src/test/resources/tcrecords.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file