1
0
mirror of https://github.com/google/nomulus synced 2026-02-06 13:01:11 +00:00

Compare commits

..

4 Commits

Author SHA1 Message Date
gbrodman
d23640a54f Update LoadTestAction for GKE and no-contacts (#2800)
It's necessary to remove the GAE-related code (and use GKE launch
commands instead), and we might as well remove contact-related fields
and actions because of the upcoming move to the minimum data set.
2025-08-13 18:35:46 +00:00
Pavlo Tkach
cc347264f1 Revert "Remove nodeSelector from k8s deployments (#2798)" (#2799)
This reverts commit 5cef2dd8b5.
We faced CPU quota issue with standard machine type, so rolling back to c4
for now to monitor server performance and decide if we want to try to
downgrade again in the future.
2025-08-13 15:05:54 +00:00
Pavlo Tkach
e5d4cbb9fc Increase hikari maximum pool size (#2802) 2025-08-12 21:01:28 +00:00
gbrodman
8c1e0ff4de Chage run-time of DeleteExpiredDomainsAction (#2801)
We probably want this to run before the billing recurrence expansion
pipeline just in case there are any domains that should be deleted
before their billing recurrence gets expanded.
2025-08-12 20:48:04 +00:00
18 changed files with 48 additions and 225 deletions

View File

@@ -243,7 +243,7 @@ hibernate:
# that BEAM pipelines are not subject to the maximumPoolSize value defined
# here. See PersistenceModule.java for more information.
hikariMinimumIdle: 1
hikariMaximumPoolSize: 20
hikariMaximumPoolSize: 40
hikariIdleTimeout: 300000
# The batch size is basically the number of insertions / updates in a single
# transaction that will be batched together into one INSERT/UPDATE statement.

View File

@@ -88,6 +88,7 @@
should exist between the RECURRING_BILLING cursor's time and the execution
time of the action.
</description>
<!-- Runs shortly after DeleteExpiredDomainsAction so it can delete domains before they renew -->
<schedule>0 3 * * *</schedule>
</task>
@@ -98,7 +99,8 @@
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
<!-- Runs shortly before ExpandBillingRecurrencesPipeline to catch and delete domains before they renew -->
<schedule>45 2 * * *</schedule>
</task>
<task>

View File

@@ -146,6 +146,7 @@
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
<!-- Runs shortly before ExpandBillingRecurrencesPipeline to catch and delete domains before they renew -->
<schedule>45 2 * * *</schedule>
</task>
</entries>

View File

@@ -130,6 +130,7 @@
should exist between the RECURRING_BILLING cursor's time and the execution
time of the action.
</description>
<!-- Runs shortly after DeleteExpiredDomainsAction so it can delete domains before they renew -->
<schedule>0 3 * * *</schedule>
</task>
@@ -140,7 +141,8 @@
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
<!-- Runs shortly before ExpandBillingRecurrencesPipeline to catch and delete domains before they renew -->
<schedule>45 2 * * *</schedule>
</task>
<task>

View File

@@ -57,6 +57,7 @@
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
<!-- Runs shortly before ExpandBillingRecurrencesPipeline to catch and delete domains before they renew -->
<schedule>45 2 * * *</schedule>
</task>
</entries>

View File

@@ -90,6 +90,7 @@
should exist between the RECURRING_BILLING cursor's time and the execution
time of the action.
</description>
<!-- Runs shortly after DeleteExpiredDomainsAction so it can delete domains before they renew -->
<schedule>0 3 * * *</schedule>
</task>
@@ -113,7 +114,8 @@
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
<!-- Runs shortly before ExpandBillingRecurrencesPipeline to catch and delete domains before they renew -->
<schedule>45 2 * * *</schedule>
</task>
<task>

View File

@@ -17,10 +17,7 @@ package google.registry.loadtest;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Lists.partition;
import static google.registry.security.XsrfTokenManager.X_CSRF_TOKEN;
import static google.registry.util.ResourceUtils.readResourceUtf8;
import static java.util.Arrays.asList;
import static org.joda.time.DateTimeZone.UTC;
import com.google.cloud.tasks.v2.Task;
import com.google.common.collect.ImmutableList;
@@ -34,7 +31,7 @@ import google.registry.request.Action;
import google.registry.request.Action.GaeService;
import google.registry.request.Parameter;
import google.registry.request.auth.Auth;
import google.registry.security.XsrfTokenManager;
import google.registry.util.Clock;
import google.registry.util.RegistryEnvironment;
import jakarta.inject.Inject;
import java.time.Instant;
@@ -67,11 +64,9 @@ public class LoadTestAction implements Runnable {
private static final int NUM_QUEUES = 10;
private static final int MAX_TASKS_PER_LOAD = 100;
private static final int ARBITRARY_VALID_HOST_LENGTH = 40;
private static final int MAX_CONTACT_LENGTH = 13;
private static final int MAX_DOMAIN_LABEL_LENGTH = 63;
private static final String EXISTING_DOMAIN = "testdomain";
private static final String EXISTING_CONTACT = "contact";
private static final String EXISTING_HOST = "ns1";
private static final Random random = new Random();
@@ -85,8 +80,8 @@ public class LoadTestAction implements Runnable {
/**
* The number of seconds to delay the execution of the first load testing tasks by. Preparatory
* work of creating independent contacts and hosts that will be used for later domain creation
* testing occurs during this period, so make sure that it is long enough.
* work of creating independent hosts that will be used for later domain creation testing occurs
* during this period, so make sure that it is long enough.
*/
@Inject
@Parameter("delaySeconds")
@@ -120,21 +115,6 @@ public class LoadTestAction implements Runnable {
@Parameter("domainChecks")
int domainChecksPerSecond;
/** The number of successful contact creates to enqueue per second over the length of the test. */
@Inject
@Parameter("successfulContactCreates")
int successfulContactCreatesPerSecond;
/** The number of failed contact creates to enqueue per second over the length of the test. */
@Inject
@Parameter("failedContactCreates")
int failedContactCreatesPerSecond;
/** The number of successful contact infos to enqueue per second over the length of the test. */
@Inject
@Parameter("contactInfos")
int contactInfosPerSecond;
/** The number of successful host creates to enqueue per second over the length of the test. */
@Inject
@Parameter("successfulHostCreates")
@@ -152,9 +132,8 @@ public class LoadTestAction implements Runnable {
@Inject CloudTasksUtils cloudTasksUtils;
private final String xmlContactCreateTmpl;
private final String xmlContactCreateFail;
private final String xmlContactInfo;
@Inject Clock clock;
private final String xmlDomainCheck;
private final String xmlDomainCreateTmpl;
private final String xmlDomainCreateFail;
@@ -163,53 +142,35 @@ public class LoadTestAction implements Runnable {
private final String xmlHostCreateFail;
private final String xmlHostInfo;
/**
* The XSRF token to be used for making requests to the epptool endpoint.
*
* <p>Note that the email address is set to empty, because the logged-in user hitting this
* endpoint will not be the same as when the tasks themselves fire and hit the epptool endpoint.
*/
private final String xsrfToken;
@Inject
LoadTestAction(@Parameter("tld") String tld, XsrfTokenManager xsrfTokenManager) {
xmlContactCreateTmpl = loadXml("contact_create");
xmlContactCreateFail = xmlContactCreateTmpl.replace("%contact%", EXISTING_CONTACT);
xmlContactInfo = loadXml("contact_info").replace("%contact%", EXISTING_CONTACT);
LoadTestAction(@Parameter("tld") String tld) {
xmlDomainCheck =
loadXml("domain_check").replace("%tld%", tld).replace("%domain%", EXISTING_DOMAIN);
xmlDomainCreateTmpl = loadXml("domain_create").replace("%tld%", tld);
xmlDomainCreateFail =
xmlDomainCreateTmpl
.replace("%domain%", EXISTING_DOMAIN)
.replace("%contact%", EXISTING_CONTACT)
.replace("%host%", EXISTING_HOST);
xmlDomainInfo =
loadXml("domain_info").replace("%tld%", tld).replace("%domain%", EXISTING_DOMAIN);
xmlHostCreateTmpl = loadXml("host_create");
xmlHostCreateFail = xmlHostCreateTmpl.replace("%host%", EXISTING_HOST);
xmlHostInfo = loadXml("host_info").replace("%host%", EXISTING_HOST);
xsrfToken = xsrfTokenManager.generateToken("");
}
@Override
public void run() {
validateAndLogRequest();
DateTime initialStartSecond = DateTime.now(UTC).plusSeconds(delaySeconds);
DateTime initialStartSecond = clock.nowUtc().plusSeconds(delaySeconds);
ImmutableList.Builder<String> preTaskXmls = new ImmutableList.Builder<>();
ImmutableList.Builder<String> contactNamesBuilder = new ImmutableList.Builder<>();
ImmutableList.Builder<String> hostPrefixesBuilder = new ImmutableList.Builder<>();
for (int i = 0; i < successfulDomainCreatesPerSecond; i++) {
String contactName = getRandomLabel(MAX_CONTACT_LENGTH);
String hostPrefix = getRandomLabel(ARBITRARY_VALID_HOST_LENGTH);
contactNamesBuilder.add(contactName);
hostPrefixesBuilder.add(hostPrefix);
preTaskXmls.add(
xmlContactCreateTmpl.replace("%contact%", contactName),
xmlHostCreateTmpl.replace("%host%", hostPrefix));
}
enqueue(createTasks(preTaskXmls.build(), DateTime.now(UTC)));
ImmutableList<String> contactNames = contactNamesBuilder.build();
enqueue(createTasks(preTaskXmls.build(), clock.nowUtc()));
ImmutableList<String> hostPrefixes = hostPrefixesBuilder.build();
ImmutableList.Builder<Task> tasks = new ImmutableList.Builder<>();
@@ -217,30 +178,17 @@ public class LoadTestAction implements Runnable {
DateTime startSecond = initialStartSecond.plusSeconds(offsetSeconds);
// The first "failed" creates might actually succeed if the object doesn't already exist, but
// that shouldn't affect the load numbers.
tasks.addAll(
createTasks(
createNumCopies(xmlContactCreateFail, failedContactCreatesPerSecond), startSecond));
tasks.addAll(
createTasks(createNumCopies(xmlHostCreateFail, failedHostCreatesPerSecond), startSecond));
tasks.addAll(
createTasks(
createNumCopies(xmlDomainCreateFail, failedDomainCreatesPerSecond), startSecond));
// We can do infos on the known existing objects.
tasks.addAll(
createTasks(createNumCopies(xmlContactInfo, contactInfosPerSecond), startSecond));
tasks.addAll(createTasks(createNumCopies(xmlHostInfo, hostInfosPerSecond), startSecond));
tasks.addAll(createTasks(createNumCopies(xmlDomainInfo, domainInfosPerSecond), startSecond));
// The domain check template uses "example.TLD" which won't exist, and one existing domain.
tasks.addAll(
createTasks(createNumCopies(xmlDomainCheck, domainChecksPerSecond), startSecond));
// Do successful creates on random names
tasks.addAll(
createTasks(
createNumCopies(xmlContactCreateTmpl, successfulContactCreatesPerSecond)
.stream()
.map(randomNameReplacer("%contact%", MAX_CONTACT_LENGTH))
.collect(toImmutableList()),
startSecond));
tasks.addAll(
createTasks(
createNumCopies(xmlHostCreateTmpl, successfulHostCreatesPerSecond)
@@ -253,7 +201,6 @@ public class LoadTestAction implements Runnable {
createNumCopies(xmlDomainCreateTmpl, successfulDomainCreatesPerSecond)
.stream()
.map(randomNameReplacer("%domain%", MAX_DOMAIN_LABEL_LENGTH))
.map(listNameReplacer("%contact%", contactNames))
.map(listNameReplacer("%host%", hostPrefixes))
.collect(toImmutableList()),
startSecond));
@@ -272,9 +219,6 @@ public class LoadTestAction implements Runnable {
|| failedDomainCreatesPerSecond > 0
|| domainInfosPerSecond > 0
|| domainChecksPerSecond > 0
|| successfulContactCreatesPerSecond > 0
|| failedContactCreatesPerSecond > 0
|| contactInfosPerSecond > 0
|| successfulHostCreatesPerSecond > 0
|| failedHostCreatesPerSecond > 0
|| hostInfosPerSecond > 0,
@@ -282,8 +226,7 @@ public class LoadTestAction implements Runnable {
logger.atInfo().log(
"Running load test with the following params. registrarId: %s, delaySeconds: %d, "
+ "runSeconds: %d, successful|failed domain creates/s: %d|%d, domain infos/s: %d, "
+ "domain checks/s: %d, successful|failed contact creates/s: %d|%d, "
+ "contact infos/s: %d, successful|failed host creates/s: %d|%d, host infos/s: %d.",
+ "domain checks/s: %d, successful|failed host creates/s: %d|%d, host infos/s: %d.",
registrarId,
delaySeconds,
runSeconds,
@@ -291,9 +234,6 @@ public class LoadTestAction implements Runnable {
failedDomainCreatesPerSecond,
domainInfosPerSecond,
domainChecksPerSecond,
successfulContactCreatesPerSecond,
failedContactCreatesPerSecond,
contactInfosPerSecond,
successfulHostCreatesPerSecond,
failedHostCreatesPerSecond,
hostInfosPerSecond);
@@ -303,10 +243,10 @@ public class LoadTestAction implements Runnable {
return readResourceUtf8(LoadTestAction.class, String.format("templates/%s.xml", name));
}
private List<String> createNumCopies(String xml, int numCopies) {
private ImmutableList<String> createNumCopies(String xml, int numCopies) {
String[] xmls = new String[numCopies];
Arrays.fill(xmls, xml);
return asList(xmls);
return ImmutableList.copyOf(xmls);
}
private Function<String, String> listNameReplacer(final String toReplace, List<String> choices) {
@@ -326,35 +266,27 @@ public class LoadTestAction implements Runnable {
return name.toString();
}
private List<Task> createTasks(List<String> xmls, DateTime start) {
private ImmutableList<Task> createTasks(ImmutableList<String> xmls, DateTime start) {
ImmutableList.Builder<Task> tasks = new ImmutableList.Builder<>();
for (int i = 0; i < xmls.size(); i++) {
// Space tasks evenly within across a second.
Instant scheduleTime =
Instant.ofEpochMilli(start.plusMillis((int) (1000.0 / xmls.size() * i)).getMillis());
tasks.add(
Task.newBuilder()
.setAppEngineHttpRequest(
cloudTasksUtils
.createTask(
EppToolAction.class,
Action.Method.POST,
ImmutableMultimap.of(
"clientId",
registrarId,
"superuser",
Boolean.FALSE.toString(),
"dryRun",
Boolean.FALSE.toString(),
"xml",
xmls.get(i)))
.toBuilder()
.getAppEngineHttpRequest()
.toBuilder()
// TODO: investigate if the following is necessary now that
// LegacyAuthenticationMechanism is gone.
.putHeaders(X_CSRF_TOKEN, xsrfToken)
.build())
cloudTasksUtils
.createTask(
EppToolAction.class,
Action.Method.POST,
ImmutableMultimap.of(
"clientId",
registrarId,
"superuser",
Boolean.FALSE.toString(),
"dryRun",
Boolean.FALSE.toString(),
"xml",
xmls.get(i)))
.toBuilder()
.setScheduleTime(
Timestamp.newBuilder()
.setSeconds(scheduleTime.getEpochSecond())
@@ -365,7 +297,7 @@ public class LoadTestAction implements Runnable {
return tasks.build();
}
private void enqueue(List<Task> tasks) {
private void enqueue(ImmutableList<Task> tasks) {
List<List<Task>> chunks = partition(tasks, MAX_TASKS_PER_LOAD);
// Farm out tasks to multiple queues to work around queue qps quotas.
for (int i = 0; i < chunks.size(); i++) {

View File

@@ -1,33 +0,0 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<contact:create
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
<contact:id>%contact%</contact:id>
<contact:postalInfo type="int">
<contact:name>John Doe</contact:name>
<contact:org>Example Inc.</contact:org>
<contact:addr>
<contact:street>123 Example Dr.</contact:street>
<contact:street>Suite 100</contact:street>
<contact:city>Dulles</contact:city>
<contact:sp>VA</contact:sp>
<contact:pc>20166-6503</contact:pc>
<contact:cc>US</contact:cc>
</contact:addr>
</contact:postalInfo>
<contact:voice x="1234">+1.7035555555</contact:voice>
<contact:fax>+1.7035555556</contact:fax>
<contact:email>jdoe@example.com</contact:email>
<contact:authInfo>
<contact:pw>2fooBAR</contact:pw>
</contact:authInfo>
<contact:disclose flag="1">
<contact:voice/>
<contact:email/>
</contact:disclose>
</contact:create>
</create>
<clTRID>trid</clTRID>
</command>
</epp>

View File

@@ -1,14 +0,0 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<info>
<contact:info
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
<contact:id>%contact%</contact:id>
<contact:authInfo>
<contact:pw>2fooBAR</contact:pw>
</contact:authInfo>
</contact:info>
</info>
<clTRID>trid</clTRID>
</command>
</epp>

View File

@@ -8,9 +8,6 @@
<domain:ns>
<domain:hostObj>%host%.example.com</domain:hostObj>
</domain:ns>
<domain:registrant>%contact%</domain:registrant>
<domain:contact type="admin">%contact%</domain:contact>
<domain:contact type="tech">%contact%</domain:contact>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>

View File

@@ -4,6 +4,7 @@
<host:create
xmlns:host="urn:ietf:params:xml:ns:host-1.0">
<host:name>%host%.example.com</host:name>
<host:addr ip="v4">8.8.8.8</host:addr>
</host:create>
</create>
<clTRID>trid</clTRID>

View File

@@ -14,7 +14,6 @@
package google.registry.tools;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableMap;
@@ -52,11 +51,6 @@ class LoadTestCommand extends ConfirmingCommand implements CommandWithConnection
description = "Number of domains to create per second.")
int successfulDomainCreates = 1;
@Parameter(
names = {"--successful_contact_creates"},
description = "Number of contact records to create per second.")
int successfulContactCreates = 1;
@Parameter(
names = {"--host_infos"},
description = "Number of successful host:info commands to send per second.")
@@ -67,11 +61,6 @@ class LoadTestCommand extends ConfirmingCommand implements CommandWithConnection
description = "Number of successful domain:info commands to send per second.")
int domainInfos = 1;
@Parameter(
names = {"--contact_infos"},
description = "Number of successful contact:info commands to send per second.")
int contactInfos = 1;
@Parameter(
names = {"--run_seconds"},
description = "Time to run the load test in seconds.")
@@ -120,10 +109,8 @@ class LoadTestCommand extends ConfirmingCommand implements CommandWithConnection
.put("clientId", clientId)
.put("successfulHostCreates", successfulHostCreates)
.put("successfulDomainCreates", successfulDomainCreates)
.put("successfulContactCreates", successfulContactCreates)
.put("hostInfos", hostInfos)
.put("domainInfos", domainInfos)
.put("contactInfos", contactInfos)
.put("runSeconds", runSeconds)
.build();

View File

@@ -35,7 +35,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.CharStreams;
import com.google.common.net.MediaType;
import com.google.re2j.Pattern;
import google.registry.config.RegistryConfig.Config;
import google.registry.request.Action.GaeService;
import google.registry.request.Action.GkeService;
@@ -56,9 +55,6 @@ import org.json.simple.JSONValue;
*/
public class ServiceConnection {
/** Pattern to heuristically extract title tag contents in HTML responses. */
protected static final Pattern HTML_TITLE_TAG_PATTERN = Pattern.compile("<title>(.*?)</title>");
private final Service service;
private final boolean useCanary;
private final HttpRequestFactory requestFactory;

View File

@@ -50,10 +50,8 @@ class LoadTestCommandTest extends CommandTestCase<LoadTestCommand> {
.put("clientId", "acme")
.put("successfulHostCreates", 1)
.put("successfulDomainCreates", 1)
.put("successfulContactCreates", 1)
.put("hostInfos", 1)
.put("domainInfos", 1)
.put("contactInfos", 1)
.put("runSeconds", 9200)
.build();
verify(connection)
@@ -69,10 +67,8 @@ class LoadTestCommandTest extends CommandTestCase<LoadTestCommand> {
"--client_id=NewRegistrar",
"--successful_host_creates=10",
"--successful_domain_creates=11",
"--successful_contact_creates=12",
"--host_infos=13",
"--domain_infos=14",
"--contact_infos=15",
"--run_seconds=16");
ImmutableMap<String, Object> params =
new ImmutableMap.Builder<String, Object>()
@@ -80,10 +76,8 @@ class LoadTestCommandTest extends CommandTestCase<LoadTestCommand> {
.put("clientId", "NewRegistrar")
.put("successfulHostCreates", 10)
.put("successfulDomainCreates", 11)
.put("successfulContactCreates", 12)
.put("hostInfos", 13)
.put("domainInfos", 14)
.put("contactInfos", 15)
.put("runSeconds", 16)
.build();
verify(connection)

View File

@@ -14,6 +14,9 @@ spec:
service: backend
spec:
serviceAccountName: nomulus
nodeSelector:
cloud.google.com/compute-class: "Performance"
cloud.google.com/machine-family: c4
containers:
- name: backend
image: gcr.io/GCP_PROJECT/nomulus
@@ -22,15 +25,9 @@ spec:
name: http
resources:
requests:
# explicit pod-slots 0 is required in order to downgrade node
# class from performance, which has implicit pod-slots 1
cloud.google.com/pod-slots: 0
cpu: "500m"
memory: "1Gi"
limits:
# explicit pod-slots 0 is required in order to downgrade node
# class from performance, which has implicit pod-slots 1
cloud.google.com/pod-slots: 0
cpu: "1000m"
memory: "1Gi"
args: [ENVIRONMENT]

View File

@@ -14,6 +14,9 @@ spec:
service: frontend
spec:
serviceAccountName: nomulus
nodeSelector:
cloud.google.com/compute-class: "Performance"
cloud.google.com/machine-family: c4
containers:
- name: frontend
image: gcr.io/GCP_PROJECT/nomulus
@@ -22,15 +25,9 @@ spec:
name: http
resources:
requests:
# explicit pod-slots 0 is required in order to downgrade node
# class from performance, which has implicit pod-slots 1
cloud.google.com/pod-slots: 0
cpu: "1000m"
memory: "1Gi"
limits:
# explicit pod-slots 0 is required in order to downgrade node
# class from performance, which has implicit pod-slots 1
cloud.google.com/pod-slots: 0
cpu: "1000m"
memory: "2Gi"
args: [ENVIRONMENT]
@@ -56,15 +53,9 @@ spec:
name: epp
resources:
requests:
# explicit pod-slots 0 is required in order to downgrade node
# class from performance, which has implicit pod-slots 1
cloud.google.com/pod-slots: 0
cpu: "1000m"
memory: "512Mi"
limits:
# explicit pod-slots 0 is required in order to downgrade node
# class from performance, which has implicit pod-slots 1
cloud.google.com/pod-slots: 0
cpu: "1000m"
memory: "512Mi"
args: [--env, PROXY_ENV, --log, --local]

View File

@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<contact:create
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
<contact:id>@@RANDOM_CONTACT@@-@@CHANNEL_NUMBER@@</contact:id>
<contact:postalInfo type="int">
<contact:name>John Doe</contact:name>
<contact:org>Example, Inc.</contact:org>
<contact:addr>
<contact:street>111 Example Street</contact:street>
<contact:street></contact:street>
<contact:city>Los Angeles</contact:city>
<contact:sp>CA</contact:sp>
<contact:pc>90210</contact:pc>
<contact:cc>US</contact:cc>
</contact:addr>
</contact:postalInfo>
<contact:voice>+1.2020202022</contact:voice>
<contact:fax>+1.2022022022</contact:fax>
<contact:email>test@email.com</contact:email>
<contact:authInfo>
<contact:pw>somepassword</contact:pw>
</contact:authInfo>
</contact:create>
</create>
<clTRID>epp-client-contact-create-@@NOW@@-@@CHANNEL_NUMBER@@</clTRID>
</command>
</epp>

View File

@@ -9,9 +9,6 @@
<domain:ns>
<domain:hostObj>ns1.domain.com</domain:hostObj>
</domain:ns>
<domain:registrant>@@RANDOM_CONTACT@@-@@CHANNEL_NUMBER@@</domain:registrant>
<domain:contact type="admin">@@RANDOM_CONTACT@@-@@CHANNEL_NUMBER@@</domain:contact>
<domain:contact type="tech">@@RANDOM_CONTACT@@-@@CHANNEL_NUMBER@@</domain:contact>
<domain:authInfo>
<domain:pw>somepassword</domain:pw>
</domain:authInfo>