1
0
mirror of https://github.com/google/nomulus synced 2026-07-06 16:16:38 +00:00

Compare commits

...

5 Commits

Author SHA1 Message Date
gbrodman ea9d717378 Use custom Protostuff delegate for InetAddresses (#3079)
We need this to serialize/deserialize hosts, because we're not allowed
to reflectively access InetAddress.
2026-06-08 19:16:35 +00:00
Juan Celhay d1769b29ef fix relative path of manifests (#3084) 2026-06-08 15:37:17 +00:00
gbrodman 14376953e5 Skip EPP params for BRDA (#3083)
this is an extra field that shouldn't be included in this output
apparently
2026-06-05 20:52:54 +00:00
Juan Celhay c13c9b53e3 Add sandbox to the Cloud Deploy delivery pipeline (#3080)
* add sandbox target to the delivery pipeline

* add sandbox target
2026-06-05 19:32:28 +00:00
Ben McIlwain 1cd6026151 Fix npx build overriding Angular output paths (#3082)
This commit reverts changes from PR #3068 that swapped 'npm run build' for 'npx ng build' while attempting to dynamically set the '--output-path' via the CLI.

Passing '--output-path' on the command line overrides the entire 'outputPath' configuration object in angular.json. Because the new Angular 18 Application Builder (esbuild) nests outputs inside a 'browser/' directory by default, overriding the configuration bypassed the 'browser: ""' flattening property, causing all client assets to be nested deeper than expected.

This resulted in empty deployments because downstream tasks (like Jetty's copyConsole and the deployment tar scripts) expected the assets to be completely flat. By removing the '--output-path' override from the 'npx ng build' calls, the Angular CLI once again respects angular.json, flattens the output into 'staged/dist/', and the restored 'doLast' block successfully copies the artifacts where they belong.
2026-06-05 16:31:14 +00:00
11 changed files with 192 additions and 66 deletions
+8 -1
View File
@@ -53,10 +53,17 @@ def createConsoleTask = { env ->
project.tasks.register("buildConsoleFor${env.capitalize()}", Exec) {
workingDir "${consoleDir}/"
executable 'npx'
args 'ng', 'build', '--base-href=/console/', "--configuration=${env}", "--output-path=staged/console-${env}"
args 'ng', 'build', '--base-href=/console/', "--configuration=${env}"
doFirst {
println "Building console for environment: ${env}"
}
doLast {
copy {
from "${consoleDir}/staged/dist/"
into "${consoleDir}/staged/console-${env}"
}
delete "${consoleDir}/staged/dist"
}
dependsOn(tasks.npmInstallDeps)
}
project.tasks.register("deleteConsoleFor${env.capitalize()}", Delete) {
@@ -212,17 +212,16 @@ public class RdeIO {
}
}
// Don't write the IDN elements for BRDA.
// Don't write the IDN elements or EPP params for BRDA.
if (mode == RdeMode.FULL) {
for (IdnTableEnum idn : IdnTableEnum.values()) {
output.write(marshaller.marshalIdn(idn.getTable()));
counter.increment(RdeResourceType.IDN);
}
output.write(marshaller.marshalRdeEppParams());
counter.increment(RdeResourceType.EPP_PARAMS);
}
output.write(marshaller.marshalRdeEppParams());
counter.increment(RdeResourceType.EPP_PARAMS);
// Output XML that says how many resources were emitted.
header = counter.makeHeader(tld, mode);
output.write(marshaller.marshalOrDie(new XjcRdeHeaderElement(header)));
@@ -372,7 +372,7 @@ public class RdePipeline implements Serializable {
* <p>The (repoId, pendingDeposit) pairs denote hosts that are referenced from a domain, that are
* to be included in the corresponding pending deposit.
*
* <p>The (repoId, revisionId) paris come from the most recent history entry query, which can be
* <p>The (repoId, revisionId) pairs come from the most recent history entry query, which can be
* used to load the embedded resources themselves.
*
* @return a pair of (repoId, ([pendingDeposit], [revisionId])) where neither the pendingDeposit
@@ -25,10 +25,20 @@ import com.google.common.flogger.FluentLogger;
import google.registry.model.EppResource;
import google.registry.model.domain.Domain;
import google.registry.model.host.Host;
import io.protostuff.Input;
import io.protostuff.LinkedBuffer;
import io.protostuff.Output;
import io.protostuff.Pipe;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.WireFormat;
import io.protostuff.runtime.DefaultIdStrategy;
import io.protostuff.runtime.Delegate;
import io.protostuff.runtime.RuntimeSchema;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import redis.clients.jedis.AbstractPipeline;
@@ -52,11 +62,20 @@ public class SimplifiedJedisClient {
Domain.class, "d_",
Host.class, "h_");
/** We need to inform Protostuff of the custom {@link InetAddress} delegates. */
private static DefaultIdStrategy createIdStrategy() {
DefaultIdStrategy strategy = new DefaultIdStrategy();
strategy.registerDelegate(new GenericInetAddressDelegate<>(InetAddress.class));
strategy.registerDelegate(new GenericInetAddressDelegate<>(Inet4Address.class));
strategy.registerDelegate(new GenericInetAddressDelegate<>(Inet6Address.class));
return strategy;
}
private static final ImmutableMap<Class<? extends EppResource>, Schema<? extends EppResource>>
VALUE_SCHEMAS =
ImmutableMap.of(
Domain.class, RuntimeSchema.getSchema(Domain.class),
Host.class, RuntimeSchema.getSchema(Host.class));
Host.class, RuntimeSchema.getSchema(Host.class, createIdStrategy()));
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -151,4 +170,46 @@ public class SimplifiedJedisClient {
checkArgument(VALUE_SCHEMAS.containsKey(clazz), "Unknown class type %s", clazz);
return (Schema<V>) VALUE_SCHEMAS.get(clazz);
}
/**
* A custom Protostuff {@link Delegate} for {@link InetAddress} and its subclasses.
*
* <p>This is required in Java 17+ because Protostuff's default runtime schema serialization
* relies on reflection. Since {@link InetAddress} is part of the encapsulated {@code java.base}
* module, reflective access is restricted and throws {@link
* java.lang.reflect.InaccessibleObjectException}.
*
* <p>This delegate serializes the IP address as a raw byte array using {@link
* InetAddress#getAddress()} and reconstructs it using {@link InetAddress#getByAddress(byte[])}
*/
private record GenericInetAddressDelegate<T extends InetAddress>(Class<T> clazz)
implements Delegate<T> {
@Override
public WireFormat.FieldType getFieldType() {
return WireFormat.FieldType.BYTES;
}
@Override
public Class<T> typeClass() {
return clazz;
}
@SuppressWarnings("unchecked")
@Override
public T readFrom(Input input) throws IOException {
return (T) InetAddress.getByAddress(input.readByteArray());
}
@Override
public void writeTo(Output output, int number, T value, boolean repeated) throws IOException {
output.writeByteArray(number, value.getAddress(), repeated);
}
@Override
public void transfer(Pipe pipe, Input input, Output output, int number, boolean repeated)
throws IOException {
output.writeByteArray(number, input.readByteArray(), repeated);
}
}
}
@@ -30,7 +30,7 @@ public enum RdeResourceType {
REGISTRAR("urn:ietf:params:xml:ns:rdeRegistrar-1.0", EnumSet.of(FULL, THIN)),
IDN("urn:ietf:params:xml:ns:rdeIDN-1.0", EnumSet.of(FULL)),
HEADER("urn:ietf:params:xml:ns:rdeHeader-1.0", EnumSet.of(FULL, THIN)),
EPP_PARAMS("urn:ietf:params:xml:ns:rdeEppParams-1.0", EnumSet.of(FULL, THIN));
EPP_PARAMS("urn:ietf:params:xml:ns:rdeEppParams-1.0", EnumSet.of(FULL));
private final String uri;
private final ImmutableSet<RdeMode> modes;
@@ -19,6 +19,7 @@ import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableO
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistActiveHost;
import static google.registry.testing.DatabaseHelper.persistActiveSubordinateHost;
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
import com.google.common.collect.ImmutableList;
@@ -67,7 +68,8 @@ public class SimplifiedJedisClientTest {
@Test
void testClient_roundTrip_host() {
Host host = persistActiveHost("ns1.example.tld");
Domain domain = persistActiveDomain("example.tld");
Host host = persistActiveSubordinateHost("ns1.example.tld", domain);
SimplifiedJedisClient client = createJedisClient();
client.set(new SimplifiedJedisClient.JedisResource<>("repoId1", host));
assertThat(client.get(Host.class, "repoId1")).hasValue(host);
@@ -4,7 +4,6 @@
<rde:rdeMenu>
<rde:version>1.0</rde:version>
<rde:objURI>urn:ietf:params:xml:ns:rdeDomain-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeEppParams-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeHeader-1.0</rde:objURI>
<rde:objURI>urn:ietf:params:xml:ns:rdeRegistrar-1.0</rde:objURI>
</rde:rdeMenu>
@@ -12,45 +11,10 @@
<rdeDomain:domain/>
<rdeRegistrar:registrar/>
<rdeEppParams:eppParams>
<rdeEppParams:version>1.0</rdeEppParams:version>
<rdeEppParams:lang>en</rdeEppParams:lang>
<rdeEppParams:objURI>urn:ietf:params:xml:ns:rdeDomain-1.0</rdeEppParams:objURI>
<rdeEppParams:objURI>urn:ietf:params:xml:ns:rdeHost-1.0</rdeEppParams:objURI>
<rdeEppParams:svcExtension>
<epp:extURI>urn:ietf:params:xml:ns:launch-1.0</epp:extURI>
<epp:extURI>urn:ietf:params:xml:ns:rgp-1.0</epp:extURI>
<epp:extURI>urn:ietf:params:xml:ns:secDNS-1.1</epp:extURI>
<epp:extURI>urn:ietf:params:xml:ns:fee-0.6</epp:extURI>
<epp:extURI>urn:ietf:params:xml:ns:fee-0.11</epp:extURI>
<epp:extURI>urn:ietf:params:xml:ns:fee-0.12</epp:extURI>
<epp:extURI>urn:ietf:params:xml:ns:epp:fee-1.0</epp:extURI>
</rdeEppParams:svcExtension>
<rdeEppParams:dcp>
<epp:access>
<epp:all/>
</epp:access>
<epp:statement>
<epp:purpose>
<epp:admin/>
<epp:prov/>
</epp:purpose>
<epp:recipient>
<epp:ours/>
<epp:public/>
</epp:recipient>
<epp:retention>
<epp:stated/>
</epp:retention>
</epp:statement>
</rdeEppParams:dcp>
</rdeEppParams:eppParams>
<rdeHeader:header>
<rdeHeader:tld>soy</rdeHeader:tld>
<rdeHeader:count uri="urn:ietf:params:xml:ns:rdeDomain-1.0">1</rdeHeader:count>
<rdeHeader:count uri="urn:ietf:params:xml:ns:rdeRegistrar-1.0">1</rdeHeader:count>
<rdeHeader:count uri="urn:ietf:params:xml:ns:rdeEppParams-1.0">1</rdeHeader:count>
</rdeHeader:header>
</rde:contents>
+6 -6
View File
@@ -38,7 +38,7 @@ steps:
- -c
- |
set -e
for env in crash; do
for env in crash sandbox; do
config_file="release/clouddeploy/${env}-config.yaml"
if [ -f "$config_file" ]; then
echo "Extracting checks from $config_file..."
@@ -52,8 +52,8 @@ steps:
' "$config_file" > checks.tmp
# Insert the checks where the placeholder is located and remove the placeholder
sed -i '/stableDeploymentAlertPolicyChecks/r checks.tmp' release/clouddeploy/delivery-pipeline.yaml
sed -i '/stableDeploymentAlertPolicyChecks/d' release/clouddeploy/delivery-pipeline.yaml
sed -i "/${env}StableDeploymentAlertPolicyChecks/r checks.tmp" release/clouddeploy/delivery-pipeline.yaml
sed -i "/${env}StableDeploymentAlertPolicyChecks/d" release/clouddeploy/delivery-pipeline.yaml
rm -f checks.tmp
# Extract only the indented block under partialDeploymentAlertPolicyChecks.
@@ -68,8 +68,8 @@ steps:
' "$config_file" > partial_checks.tmp
# Insert the checks where the placeholder is located and remove the placeholder
sed -i '/partialDeploymentAlertPolicyChecks/r partial_checks.tmp' release/clouddeploy/delivery-pipeline.yaml
sed -i '/partialDeploymentAlertPolicyChecks/d' release/clouddeploy/delivery-pipeline.yaml
sed -i "/${env}PartialDeploymentAlertPolicyChecks/r partial_checks.tmp" release/clouddeploy/delivery-pipeline.yaml
sed -i "/${env}PartialDeploymentAlertPolicyChecks/d" release/clouddeploy/delivery-pipeline.yaml
rm -f partial_checks.tmp
fi
@@ -95,7 +95,7 @@ steps:
- -c
- |
set -e
for env in crash; do
for env in crash sandbox; do
target_file="release/clouddeploy/${env}-target.yaml"
if [ -f "$target_file" ]; then
echo "Applying target $target_file..."
+49 -3
View File
@@ -19,7 +19,7 @@ serialPipeline:
duration: 600s
googleCloud:
alertPolicyChecks:
partialDeploymentAlertPolicyChecks
crashPartialDeploymentAlertPolicyChecks
- phaseId: "canary-5"
profiles: ["crash-partial-phase-5"]
percentage: 50
@@ -28,7 +28,7 @@ serialPipeline:
duration: 600s
googleCloud:
alertPolicyChecks:
partialDeploymentAlertPolicyChecks
crashPartialDeploymentAlertPolicyChecks
- phaseId: "stable"
profiles: ["crash"]
percentage: 100
@@ -51,4 +51,50 @@ serialPipeline:
duration: 600s
googleCloud:
alertPolicyChecks:
stableDeploymentAlertPolicyChecks
crashStableDeploymentAlertPolicyChecks
- targetId: sandbox
strategy:
canary:
customCanaryDeployment:
phaseConfigs:
- phaseId: "canary-1"
profiles: ["sandbox-partial-phase-1"]
percentage: 10
analysis:
# 10 minutes.
duration: 600s
googleCloud:
alertPolicyChecks:
sandboxPartialDeploymentAlertPolicyChecks
- phaseId: "canary-5"
profiles: ["sandbox-partial-phase-5"]
percentage: 50
analysis:
# 10 minutes.
duration: 600s
googleCloud:
alertPolicyChecks:
sandboxPartialDeploymentAlertPolicyChecks
- phaseId: "stable"
profiles: ["sandbox"]
percentage: 100
postdeploy:
tasks:
- type: container
image: gcr.io/google.com/cloudsdktool/google-cloud-cli:stable
env:
DEPLOYED_IMAGE: ${{ deploy_params['deployed_image'] }}
BASE_IMAGE: ${{ deploy_params['base_image'] }}
TARGET_ID: ${{ target.id }}
command: ["/bin/bash"]
args:
- "-c"
- |
gcloud artifacts docker tags add $DEPLOYED_IMAGE \
${BASE_IMAGE}:live-cd-${TARGET_ID}
analysis:
# 10 minutes.
duration: 600s
googleCloud:
alertPolicyChecks:
sandboxStableDeploymentAlertPolicyChecks
+20
View File
@@ -0,0 +1,20 @@
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: sandbox
requireApproval: true
executionConfigs:
- usages:
- RENDER
- DEPLOY
- ANALYSIS
- POSTDEPLOY
executionTimeout: 3600s
defaultPool:
# Placeholder: Replace with artifact bucket name.
artifactStorage: artifactStorage
# Placeholder: Replace with project number.
serviceAccount: serviceAccount
gke:
# Placeholder: Replace with project ID, location, and cluster name.
cluster: cluster
+39 -12
View File
@@ -7,27 +7,54 @@ profiles:
- name: crash
manifests:
rawYaml:
- ../jetty/kubernetes/nomulus-crash-backend.yaml
- ../jetty/kubernetes/nomulus-crash-console.yaml
- ../jetty/kubernetes/nomulus-crash-frontend.yaml
- ../jetty/kubernetes/nomulus-crash-pubapi.yaml
- ../../jetty/kubernetes/nomulus-crash-backend.yaml
- ../../jetty/kubernetes/nomulus-crash-console.yaml
- ../../jetty/kubernetes/nomulus-crash-frontend.yaml
- ../../jetty/kubernetes/nomulus-crash-pubapi.yaml
deploy:
kubectl: { }
- name: crash-partial-phase-1
manifests:
rawYaml:
- ../jetty/kubernetes/nomulus-crash-backend-partial-phase-1.yaml
- ../jetty/kubernetes/nomulus-crash-console-partial-phase-1.yaml
- ../jetty/kubernetes/nomulus-crash-frontend-partial-phase-1.yaml
- ../jetty/kubernetes/nomulus-crash-pubapi-partial-phase-1.yaml
- ../../jetty/kubernetes/nomulus-crash-backend-partial-phase-1.yaml
- ../../jetty/kubernetes/nomulus-crash-console-partial-phase-1.yaml
- ../../jetty/kubernetes/nomulus-crash-frontend-partial-phase-1.yaml
- ../../jetty/kubernetes/nomulus-crash-pubapi-partial-phase-1.yaml
deploy:
kubectl: { }
- name: crash-partial-phase-5
manifests:
rawYaml:
- ../jetty/kubernetes/nomulus-crash-backend-partial-phase-5.yaml
- ../jetty/kubernetes/nomulus-crash-console-partial-phase-5.yaml
- ../jetty/kubernetes/nomulus-crash-frontend-partial-phase-5.yaml
- ../jetty/kubernetes/nomulus-crash-pubapi-partial-phase-5.yaml
- ../../jetty/kubernetes/nomulus-crash-backend-partial-phase-5.yaml
- ../../jetty/kubernetes/nomulus-crash-console-partial-phase-5.yaml
- ../../jetty/kubernetes/nomulus-crash-frontend-partial-phase-5.yaml
- ../../jetty/kubernetes/nomulus-crash-pubapi-partial-phase-5.yaml
deploy:
kubectl: { }
- name: sandbox
manifests:
rawYaml:
- ../../jetty/kubernetes/nomulus-sandbox-backend.yaml
- ../../jetty/kubernetes/nomulus-sandbox-console.yaml
- ../../jetty/kubernetes/nomulus-sandbox-frontend.yaml
- ../../jetty/kubernetes/nomulus-sandbox-pubapi.yaml
deploy:
kubectl: { }
- name: sandbox-partial-phase-1
manifests:
rawYaml:
- ../../jetty/kubernetes/nomulus-sandbox-backend-partial-phase-1.yaml
- ../../jetty/kubernetes/nomulus-sandbox-console-partial-phase-1.yaml
- ../../jetty/kubernetes/nomulus-sandbox-frontend-partial-phase-1.yaml
- ../../jetty/kubernetes/nomulus-sandbox-pubapi-partial-phase-1.yaml
deploy:
kubectl: { }
- name: sandbox-partial-phase-5
manifests:
rawYaml:
- ../../jetty/kubernetes/nomulus-sandbox-backend-partial-phase-5.yaml
- ../../jetty/kubernetes/nomulus-sandbox-console-partial-phase-5.yaml
- ../../jetty/kubernetes/nomulus-sandbox-frontend-partial-phase-5.yaml
- ../../jetty/kubernetes/nomulus-sandbox-pubapi-partial-phase-5.yaml
deploy:
kubectl: { }