Skip to content

Introduce PowerDnsWriter for zone synchronization to PowerDNS #2764

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
f6aefd2
add scaffolding for PowerDNS writer
qrtp May 2, 2025
4333a55
inherit base staging logic from DnsUpdateWriter
qrtp May 3, 2025
d32c1bc
initial conversion of DNS changes for PowerDNS API usage
qrtp May 3, 2025
5639b21
handle record updates and deletes
qrtp May 5, 2025
d0bc866
add powerDNS API logging
qrtp May 5, 2025
4a45d9e
add license headers
qrtp May 5, 2025
4fc4a72
only fetch zone details when necessary
qrtp May 6, 2025
4563454
add reference to PowerDNS OpenAPI spec
qrtp May 6, 2025
b9e5ff8
automatically create default TLD definition
qrtp May 6, 2025
e3ba1ce
use primary zone configuration and add powerDNS resource files
qrtp May 7, 2025
45d2cf7
add zone xfer settings
qrtp May 8, 2025
38ae70a
PowerDNS client updates for dynamic config
qrtp May 13, 2025
0a28a12
adjust PowerDNS zone update body format
qrtp May 13, 2025
c49477d
only process delete change types when no other updates for a given do…
qrtp May 13, 2025
8fb99bc
support A/AAAA glue records
qrtp May 14, 2025
5e71300
automatic ZSK rotation
qrtp May 15, 2025
db534d3
add license header to management example script
qrtp May 15, 2025
fa247e4
log DS values for DNSSEC config
qrtp May 15, 2025
cfc1b7f
clarify DS logging entries
qrtp May 15, 2025
50ddac7
manage TSIG configuration
qrtp May 16, 2025
be6a2b0
handle root NS server configuration for new TLDs
qrtp May 17, 2025
765454b
optional TSIG configuration flag
qrtp May 19, 2025
433652c
Merge pull request #1 from unstoppabledomains/qrtp/dns-playground
qrtp May 21, 2025
72dc3b6
modularize PowerDNS config settings
qrtp May 30, 2025
e7385bf
refactor and reuse config merge from RegistryConfig class
qrtp May 31, 2025
2691fae
add validation for SOA and NS records
qrtp Jun 3, 2025
abe7767
update configuration mgmt from review comments
qrtp Jun 26, 2025
ec0d63e
Update core/src/main/java/google/registry/config/RegistryConfig.java
qrtp Jun 26, 2025
81bc11f
add comment to getConfigSettings method
qrtp Jun 26, 2025
caf6718
Merge pull request #9 from unstoppabledomains/qrtp/pdns-review-comments
qrtp Jun 26, 2025
6bd7dc2
Merge remote-tracking branch 'upstream/master' into qrtp/snyc-upstream
qrtp Jun 26, 2025
c3c1da0
Merge pull request #10 from unstoppabledomains/qrtp/snyc-upstream
qrtp Jun 27, 2025
b335133
add comment to getConfigSettings method
qrtp Jun 26, 2025
dd487e8
Hardcode beam pipelines to use GKE for tasks (#2753)
weiminyu May 8, 2025
d06bcf8
Add SQL table for password resets (#2751)
gbrodman May 8, 2025
f581632
Add Console POC reminder front-end (#2754)
ptkach May 12, 2025
f50a51a
Use the primary DB for DomainInfoFlow (#2750)
gbrodman May 13, 2025
442ee64
Remove registrar id from invoice grouping key (#2749)
jicelhay May 13, 2025
f1f7588
Add registrar_id col to password reset requests (#2756)
gbrodman May 15, 2025
829866d
Don't always require contacts in CreateDomainCommand (#2755)
gbrodman May 15, 2025
c2ea4b3
Add RegistrarPoc id column (#2761)
ptkach Jun 2, 2025
7156d30
Fix create_cdns_tld command (#2760)
weiminyu Jun 3, 2025
9b129e8
Add console action test base case (#2762)
gbrodman Jun 4, 2025
e6504c6
Update version of google-java-format (#2766)
gbrodman Jun 6, 2025
a5e98ae
Add an aggregate module for DNS writers (#2769)
weiminyu Jun 9, 2025
432e429
Add some changes related to RDAP Feb 2024 profile (#2759)
gbrodman Jun 11, 2025
9c16b3d
Add java code for RegitrarPoc id (#2770)
ptkach Jun 14, 2025
06857fc
Remove spurious parenthesis in URS command output (#2767)
CydeWeys Jun 16, 2025
b580c9e
Add password reset Java object (#2765)
gbrodman Jun 17, 2025
72f01bc
Bypass config check for caching when safe (#2773)
weiminyu Jun 20, 2025
bcb2235
Fix prober cert renewal scripts (#2776)
weiminyu Jun 25, 2025
91bb91a
Cache history values for RDAP domain requests (#2777)
gbrodman Jun 25, 2025
ed105e8
Remove commit from co-pilot due to conflict with google repo requirem…
qrtp Jun 27, 2025
72a1a85
Merge branch 'feature/power-dns-writer' into qrtp/remove-copilot-commit
qrtp Jun 27, 2025
13a94a3
Merge pull request #12 from unstoppabledomains/qrtp/remove-copilot-co…
qrtp Jun 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions core/src/main/java/google/registry/config/RegistryConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@
public final class RegistryConfig {

public static final String CANARY_HEADER = "canary";
private static final String ENVIRONMENT_CONFIG_FORMAT = "files/nomulus-config-%s.yaml";
private static final String YAML_CONFIG_PROD =
private static final String YAML_CONFIG_ENV_TEMPLATE = "files/nomulus-config-%s.yaml";
private static final String YAML_CONFIG_DEFAULT =
readResourceUtf8(RegistryConfig.class, "files/default-config.yaml");

/** Dagger qualifier for configuration settings. */
Expand All @@ -85,19 +85,18 @@ public final class RegistryConfig {
}

/**
* Loads the {@link RegistryConfigSettings} POJO from the YAML configuration files.
* Loads a generic typed POJO from the YAML configuration files.
*
* <p>The {@code default-config.yaml} file in this directory is loaded first, and a fatal error is
* thrown if it cannot be found or if there is an error parsing it. Separately, the
* environment-specific config file named {@code nomulus-config-ENVIRONMENT.yaml} is also loaded
* and those values merged into the POJO.
* <p>The {@code defaultYaml} file is loaded first, and a fatal error is thrown if it cannot be
* found or if there is an error parsing it. Separately, the environment-specific config file
* template {@code customYamlTemplate} is also loaded and those values merged into the POJO.
*/
static RegistryConfigSettings getConfigSettings() {
public static <T> T getEnvironmentConfigSettings(
String defaultYaml, String customYamlTemplate, Class<T> clazz) {
String configFilePath =
String.format(
ENVIRONMENT_CONFIG_FORMAT, Ascii.toLowerCase(RegistryEnvironment.get().name()));
String.format(customYamlTemplate, Ascii.toLowerCase(RegistryEnvironment.get().name()));
String customYaml = readResourceUtf8(RegistryConfig.class, configFilePath);
return YamlUtils.getConfigSettings(YAML_CONFIG_PROD, customYaml, RegistryConfigSettings.class);
return YamlUtils.getConfigSettings(defaultYaml, customYaml, clazz);
}

/** Dagger module for providing configuration settings. */
Expand Down Expand Up @@ -1723,7 +1722,10 @@ public static ImmutableSet<String> getNoPollMessageOnDeletionRegistrarIds() {
*/
@VisibleForTesting
public static final Supplier<RegistryConfigSettings> CONFIG_SETTINGS =
memoize(RegistryConfig::getConfigSettings);
memoize(
() ->
RegistryConfig.getEnvironmentConfigSettings(
YAML_CONFIG_DEFAULT, YAML_CONFIG_ENV_TEMPLATE, RegistryConfigSettings.class));

private static InternetAddress parseEmailAddress(String email) {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Default configuration for PowerDNS
powerDns:
baseUrl: http://localhost:8081/api/v1
apiKey: example-api-key
dnssecEnabled: false
tsigEnabled: true
rootNameServers:
- ns1.example.com.
- ns2.example.com.
soaName: nstld.example.com.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Add environment-specific configuration here.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Add environment-specific configuration here.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Add environment-specific configuration here.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Add environment-specific configuration here.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Add environment-specific configuration here.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Add environment-specific configuration here.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Add environment-specific configuration here.
powerDns:
baseUrl: http://unittest:8081/api/v1
apiKey: unittest-api-key
dnssecEnabled: true
tsigEnabled: true
rootNameServers:
- ns1.unittest.com.
- ns2.unittest.com.
soaName: nstld.unittest.com.
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ public class DnsUpdateWriter extends BaseDnsWriter {
private final Duration dnsDefaultNsTtl;
private final Duration dnsDefaultDsTtl;
private final DnsMessageTransport transport;
private final Clock clock;
private final Update update;
private final String zoneName;
protected final Clock clock;
protected final Update update;
protected final String zoneName;

/**
* Class constructor.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
//
// Licensed 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 google.registry.dns.writer.powerdns;

import static com.google.common.base.Suppliers.memoize;
import static google.registry.util.ResourceUtils.readResourceUtf8;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig;
import google.registry.config.RegistryConfig.Config;
import jakarta.inject.Singleton;
import java.util.function.Supplier;

/**
* Configuration manager for PowerDNS settings.
*
* <p>This class is responsible for loading the PowerDNS configuration from the YAML files, found in
* the {@code files/power-dns} directory.
*/
public final class PowerDnsConfig {

// expected config file locations for PowerDNS
private static final String YAML_CONFIG_ENV_TEMPLATE = "files/power-dns/env-%s.yaml";
private static final String YAML_CONFIG_DEFAULT =
readResourceUtf8(RegistryConfig.class, "files/power-dns/default.yaml");

/** Dagger module that provides DNS configuration settings. */
@Module
public static final class PowerDnsConfigModule {

/** Parsed PowerDNS configuration settings. */
@Singleton
@Provides
static PowerDnsConfigSettings providePowerDnsConfigSettings() {
return CONFIG_SETTINGS.get();
}

/** Base URL of the PowerDNS server. */
@Provides
@Config("powerDnsBaseUrl")
public static String providePowerDnsBaseUrl(PowerDnsConfigSettings config) {
return config.powerDns.baseUrl;
}

/** API key for the PowerDNS server. */
@Provides
@Config("powerDnsApiKey")
public static String providePowerDnsApiKey(PowerDnsConfigSettings config) {
return config.powerDns.apiKey;
}

/** Whether DNSSEC is enabled for the PowerDNS server. */
@Provides
@Config("powerDnsDnssecEnabled")
public static Boolean providePowerDnsDnssecEnabled(PowerDnsConfigSettings config) {
return config.powerDns.dnssecEnabled;
}

/** Whether TSIG is enabled for the PowerDNS server. */
@Provides
@Config("powerDnsTsigEnabled")
public static Boolean providePowerDnsTsigEnabled(PowerDnsConfigSettings config) {
return config.powerDns.tsigEnabled;
}

/** Default SOA MNAME for the TLD zone. */
@Provides
@Config("powerDnsRootNameServers")
public static ImmutableList<String> providePowerDnsRootNameServers(
PowerDnsConfigSettings config) {
return ImmutableList.copyOf(config.powerDns.rootNameServers);
}

/** Default SOA RNAME for the TLD zone. */
@Provides
@Config("powerDnsSoaName")
public static String providePowerDnsSoaName(PowerDnsConfigSettings config) {
return config.powerDns.soaName;
}

private PowerDnsConfigModule() {}
}

/**
* Memoizes loading of the {@link PowerDnsConfigSettings} POJO.
*
* <p>Memoizing without cache expiration is used because the app must be re-deployed in order to
* change the contents of the YAML config files.
*/
@VisibleForTesting
public static final Supplier<PowerDnsConfigSettings> CONFIG_SETTINGS =
memoize(
() ->
RegistryConfig.getEnvironmentConfigSettings(
YAML_CONFIG_DEFAULT, YAML_CONFIG_ENV_TEMPLATE, PowerDnsConfigSettings.class));

private PowerDnsConfig() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
//
// Licensed 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 google.registry.dns.writer.powerdns;

import java.util.List;

/** The POJO that PowerDNS YAML config files are deserialized into. */
public class PowerDnsConfigSettings {

public PowerDns powerDns;

public static class PowerDns {
public String baseUrl;
public String apiKey;
public Boolean dnssecEnabled;
public Boolean tsigEnabled;
public List<String> rootNameServers;
public String soaName;
}
}
Loading