diff --git a/.run/ImportOfficeData.run.xml b/.run/ImportOfficeData.run.xml
index 92ce7bd5..6dfa1d1d 100644
--- a/.run/ImportOfficeData.run.xml
+++ b/.run/ImportOfficeData.run.xml
@@ -33,4 +33,38 @@
true
-
+
+
+
+
+
+
+
+
+
+
+
+ false
+ true
+
+
+
+ false
+ true
+
+
+
\ No newline at end of file
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainDnsSetupHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainDnsSetupHostingAssetValidator.java
index 052db872..4f9f393b 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainDnsSetupHostingAssetValidator.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainDnsSetupHostingAssetValidator.java
@@ -15,15 +15,16 @@ import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanPro
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
-class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator {
+// TODO.impl: make package private once we've migrated the legacy data
+public class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator {
// according to RFC 1035 (section 5) and RFC 1034
- static final String RR_REGEX_NAME = "([a-z0-9\\.-]+|@)\\s+";
- static final String RR_REGEX_TTL = "(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*";
- static final String RR_REGEX_IN = "IN\\s+"; // record class IN for Internet
- static final String RR_RECORD_TYPE = "[A-Z]+\\s+";
- static final String RR_RECORD_DATA = "[^;].*";
- static final String RR_COMMENT = "(;.*)*";
+ static final String RR_REGEX_NAME = "(\\*\\.)?([a-zA-Z0-9\\._-]+|@)[ \t]+";
+ static final String RR_REGEX_TTL = "(([1-9][0-9]*[mMhHdDwW]?)+[ \t]+)?";
+ static final String RR_REGEX_IN = "[iI][nN][ \t]+"; // record class IN for Internet
+ static final String RR_RECORD_TYPE = "[a-zA-Z]+[ \t]+";
+ static final String RR_RECORD_DATA = "(([^;]+)|(\".*\")|(\\(.*\\)))[ \t]*";
+ static final String RR_COMMENT = "(;.*)?";
static final String RR_REGEX_TTL_IN =
RR_REGEX_NAME + RR_REGEX_TTL + RR_REGEX_IN + RR_RECORD_TYPE + RR_RECORD_DATA + RR_COMMENT;
@@ -32,26 +33,27 @@ class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator
RR_REGEX_NAME + RR_REGEX_IN + RR_REGEX_TTL + RR_RECORD_TYPE + RR_RECORD_DATA + RR_COMMENT;
public static final String IDENTIFIER_SUFFIX = "|DNS";
+ private static List zoneFileErrors = null; // TODO.impl: remove once legacy data is migrated
+
HsDomainDnsSetupHostingAssetValidator() {
super(
DOMAIN_DNS_SETUP,
AlarmContact.isOptional(),
integerProperty("TTL").min(0).withDefault(21600),
- booleanProperty("auto-SOA-RR").withDefault(true),
+ booleanProperty("auto-SOA").withDefault(true),
booleanProperty("auto-NS-RR").withDefault(true),
booleanProperty("auto-MX-RR").withDefault(true),
booleanProperty("auto-A-RR").withDefault(true),
booleanProperty("auto-AAAA-RR").withDefault(true),
booleanProperty("auto-MAILSERVICES-RR").withDefault(true),
- booleanProperty("auto-AUTOCONFIG-RR").withDefault(true), // TODO.spec: does that already exist?
+ booleanProperty("auto-AUTOCONFIG-RR").withDefault(true),
booleanProperty("auto-AUTODISCOVER-RR").withDefault(true),
booleanProperty("auto-DKIM-RR").withDefault(true),
booleanProperty("auto-SPF-RR").withDefault(true),
booleanProperty("auto-WILDCARD-MX-RR").withDefault(true),
booleanProperty("auto-WILDCARD-A-RR").withDefault(true),
booleanProperty("auto-WILDCARD-AAAA-RR").withDefault(true),
- booleanProperty("auto-WILDCARD-DKIM-RR").withDefault(true), // TODO.spec: check, if that really works
booleanProperty("auto-WILDCARD-SPF-RR").withDefault(true),
arrayOf(
stringProperty("user-RR").matchesRegEx(RR_REGEX_TTL_IN, RR_REGEX_IN_TTL).required()
@@ -60,7 +62,7 @@ class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator
@Override
protected Pattern identifierPattern(final HsHostingAsset assetEntity) {
- return Pattern.compile("^" + Pattern.quote(assetEntity.getParentAsset().getIdentifier() + IDENTIFIER_SUFFIX) + "$");
+ return Pattern.compile("^" + Pattern.quote(assetEntity.getParentAsset().getIdentifier() + IDENTIFIER_SUFFIX) + "$");
}
@Override
@@ -78,33 +80,105 @@ class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator
// TODO.spec: define which checks should get raised to error level
final var namedCheckZone = new SystemProcess("named-checkzone", fqdn(assetEntity));
- if (namedCheckZone.execute(toZonefileString(assetEntity)) != 0) {
- // yes, named-checkzone writes error messages to stdout
+ final var zonefileString = toZonefileString(assetEntity);
+ final var zoneFileErrorResult = zoneFileErrors != null ? zoneFileErrors : result;
+ if (namedCheckZone.execute(zonefileString) != 0) {
+ // yes, named-checkzone writes error messages to stdout, not stderr
stream(namedCheckZone.getStdOut().split("\n"))
- .map(line -> line.replaceAll(" stream-0x[0-9a-f:]+", ""))
- .forEach(result::add);
+ .map(line -> line.replaceAll(" stream-0x[0-9a-f]+:", "line "))
+ .map(line -> "[" + assetEntity.getIdentifier() + "] " + line)
+ .forEach(zoneFileErrorResult::add);
+ if (!namedCheckZone.getStdErr().isEmpty()) {
+ result.add("unexpected stderr output for " + namedCheckZone.getCommand() + ": " + namedCheckZone.getStdErr());
+ }
}
return result;
}
String toZonefileString(final HsHostingAsset assetEntity) {
- // TODO.spec: we need to expand the templates (auto-...) in the same way as in Saltstack
+ // TODO.spec: we need to expand the templates (auto-...) in the same way as in Saltstack, with proper IP-numbers etc.
return """
- $ORIGIN {domain}.
- $TTL {ttl}
+ $TTL {ttl}
- ; these records are just placeholders to create a valid zonefile for the validation
- @ 1814400 IN SOA {domain}. root.{domain} ( 1999010100 10800 900 604800 86400 )
- @ IN NS ns
-
- {userRRs}
- """
- .replace("{domain}", fqdn(assetEntity))
- .replace("{ttl}", getPropertyValue(assetEntity, "TTL"))
- .replace("{userRRs}", getPropertyValues(assetEntity, "user-RR") );
+ {auto-SOA}
+ {auto-NS-RR}
+ {auto-MX-RR}
+ {auto-A-RR}
+ {auto-AAAA-RR}
+ {auto-DKIM-RR}
+ {auto-SPF-RR}
+
+ {auto-WILDCARD-MX-RR}
+ {auto-WILDCARD-A-RR}
+ {auto-WILDCARD-AAAA-RR}
+ {auto-WILDCARD-SPF-RR}
+
+ {userRRs}
+ """
+ .replace("{ttl}", assetEntity.getDirectValue("TTL", Integer.class, 43200).toString())
+ .replace("{auto-SOA}", assetEntity.getDirectValue("auto-SOA", Boolean.class, false).equals(true)
+ ? """
+ {domain}. IN SOA h00.hostsharing.net. hostmaster.hostsharing.net. (
+ 1303649373 ; serial secs since Jan 1 1970
+ 6H ; refresh (>=10000)
+ 1H ; retry (>=1800)
+ 1W ; expire
+ 1H ; minimum
+ )
+ """
+ : "; no auto-SOA"
+ )
+ .replace("{auto-NS-RR}", assetEntity.getDirectValue("auto-NS-RR", Boolean.class, true)
+ ? """
+ {domain}. IN NS dns1.hostsharing.net.
+ {domain}. IN NS dns2.hostsharing.net.
+ {domain}. IN NS dns3.hostsharing.net.
+ """
+ : "; no auto-NS-RR")
+ .replace("{auto-MX-RR}", assetEntity.getDirectValue("auto-MX-RR", Boolean.class, true)
+ ? """
+ {domain}. IN MX 30 mailin1.hostsharing.net.
+ {domain}. IN MX 30 mailin2.hostsharing.net.
+ {domain}. IN MX 30 mailin3.hostsharing.net.
+ """
+ : "; no auto-MX-RR")
+ .replace("{auto-A-RR}", assetEntity.getDirectValue("auto-A-RR", Boolean.class, true)
+ ? "{domain}. IN A 83.223.95.160" // arbitrary IP-number
+ : "; no auto-A-RR")
+ .replace("{auto-AAAA-RR}", assetEntity.getDirectValue("auto-AAA-RR", Boolean.class, true)
+ ? "{domain}. IN AAAA 2a01:37:1000::53df:5fa0:0" // arbitrary IP-number
+ : "; no auto-AAAA-RR")
+ .replace("{auto-DKIM-RR}", assetEntity.getDirectValue("auto-DKIM-RR", Boolean.class, true)
+ ? "default._domainkey 21600 IN TXT \"v=DKIM1; h=sha256; k=rsa; s=email; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmdM9d15bqe94zbHVcKKpUF875XoCWHKRap/sG3NJZ9xZ/BjfGXmqoEYeFNpX3CB7pOXhH5naq4N+6gTjArTviAiVThHXyebhrxaf1dVS4IUC6raTEyQrWPZUf7ZxXmcCYvOdV4jIQ8GRfxwxqibIJcmMiufXTLIgRUif5uaTgFwIDAQAB\""
+ : "; no auto-DKIM-RR")
+ .replace("{auto-SPF-RR}", assetEntity.getDirectValue("auto-SPF-RR", Boolean.class, true)
+ ? "{domain}. IN TXT \"v=spf1 include:spf.hostsharing.net ?all\""
+ : "; no auto-SPF-RR")
+ .replace("{auto-WILDCARD-MX-RR}", assetEntity.getDirectValue("auto-SPF-RR", Boolean.class, true)
+ ? """
+ *.{domain}. IN MX 30 mailin1.hostsharing.net.
+ *.{domain}. IN MX 30 mailin1.hostsharing.net.
+ *.{domain}. IN MX 30 mailin1.hostsharing.net.
+ """
+ : "; no auto-WILDCARD-MX-RR")
+ .replace("{auto-WILDCARD-A-RR}", assetEntity.getDirectValue("auto-WILDCARD-A-RR", Boolean.class, true)
+ ? "*.{domain}. IN A 83.223.95.160" // arbitrary IP-number
+ : "; no auto-WILDCARD-A-RR")
+ .replace("{auto-WILDCARD-AAAA-RR}", assetEntity.getDirectValue("auto-WILDCARD-AAAA-RR", Boolean.class, true)
+ ? "*.{domain}. IN AAAA 2a01:37:1000::53df:5fa0:0" // arbitrary IP-number
+ : "; no auto-WILDCARD-AAAA-RR")
+ .replace("{auto-WILDCARD-SPF-RR}", assetEntity.getDirectValue("auto-WILDCARD-SPF-RR", Boolean.class, true)
+ ? "*.{domain}. IN TXT \"v=spf1 include:spf.hostsharing.net ?all\""
+ : "; no auto-WILDCARD-SPF-RR")
+ .replace("{domain}", fqdn(assetEntity))
+ .replace("{userRRs}", getPropertyValues(assetEntity, "user-RR"));
}
private String fqdn(final HsHostingAsset assetEntity) {
- return assetEntity.getIdentifier().substring(0, assetEntity.getIdentifier().length()-IDENTIFIER_SUFFIX.length());
+ return assetEntity.getIdentifier().substring(0, assetEntity.getIdentifier().length() - IDENTIFIER_SUFFIX.length());
+ }
+
+ public static void addZonefileErrorsTo(final List zoneFileErrors) {
+ HsDomainDnsSetupHostingAssetValidator.zoneFileErrors = zoneFileErrors;
}
}
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainHttpSetupHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainHttpSetupHostingAssetValidator.java
index 37bed650..f98daea7 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainHttpSetupHostingAssetValidator.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainHttpSetupHostingAssetValidator.java
@@ -13,8 +13,8 @@ import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringPrope
class HsDomainHttpSetupHostingAssetValidator extends HostingAssetEntityValidator {
public static final String IDENTIFIER_SUFFIX = "|HTTP";
- public static final String FILESYSTEM_PATH = "^/";
- public static final String PARTIAL_DOMAIN_NAME_REGEX = "(?!-)[A-Za-z0-9-]{1,63}(? {
}
return "";
}
+
+ public ValidatableProperty, ?> getProperty(final String propertyName) {
+ return stream(propertyValidators).filter(pv -> pv.propertyName().equals(propertyName)).findFirst().orElse(null);
+ }
}
diff --git a/src/main/java/net/hostsharing/hsadminng/mapper/PatchableMapWrapper.java b/src/main/java/net/hostsharing/hsadminng/mapper/PatchableMapWrapper.java
index ffd9c1bd..01b71ead 100644
--- a/src/main/java/net/hostsharing/hsadminng/mapper/PatchableMapWrapper.java
+++ b/src/main/java/net/hostsharing/hsadminng/mapper/PatchableMapWrapper.java
@@ -1,22 +1,27 @@
package net.hostsharing.hsadminng.mapper;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import lombok.SneakyThrows;
import org.apache.commons.lang3.tuple.ImmutablePair;
import jakarta.validation.constraints.NotNull;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import static java.util.Optional.ofNullable;
-import static java.util.stream.Collectors.joining;
/** This class wraps another (usually persistent) map and
* supports applying `PatchMap` as well as a toString method with stable entry order.
*/
public class PatchableMapWrapper implements Map {
+ private static final ObjectMapper jsonWriter = new ObjectMapper()
+ .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true)
+ .configure(SerializationFeature.INDENT_OUTPUT, true);
+
private final Map delegate;
private PatchableMapWrapper(final Map map) {
@@ -53,24 +58,9 @@ public class PatchableMapWrapper implements Map {
});
}
+ @SneakyThrows
public String toString() {
- return "{\n"
- + (
- keySet().stream().sorted()
- .map(k -> " \"" + k + "\": " + formatted(get(k))))
- .collect(joining(",\n")
- )
- + "\n}\n";
- }
-
- private Object formatted(final Object value) {
- if ( value == null || value instanceof Number || value instanceof Boolean ) {
- return value;
- }
- if ( value.getClass().isArray() ) {
- return "\"" + Arrays.toString( (Object[]) value) + "\"";
- }
- return "\"" + value + "\"";
+ return jsonWriter.writeValueAsString(delegate);
}
// --- below just delegating methods --------------------------------
diff --git a/src/main/java/net/hostsharing/hsadminng/system/SystemProcess.java b/src/main/java/net/hostsharing/hsadminng/system/SystemProcess.java
index 149c6019..8b302098 100644
--- a/src/main/java/net/hostsharing/hsadminng/system/SystemProcess.java
+++ b/src/main/java/net/hostsharing/hsadminng/system/SystemProcess.java
@@ -21,6 +21,11 @@ public class SystemProcess {
this.processBuilder = new ProcessBuilder(command);
}
+
+ public String getCommand() {
+ return processBuilder.command().toString();
+ }
+
public int execute() throws IOException, InterruptedException {
final var process = processBuilder.start();
stdOut = fetchOutput(process.getInputStream()); // yeah, twisted ProcessBuilder API
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainDnsSetupHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainDnsSetupHostingAssetValidatorUnitTest.java
index 7f66379c..3234ba28 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainDnsSetupHostingAssetValidatorUnitTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainDnsSetupHostingAssetValidatorUnitTest.java
@@ -35,12 +35,27 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
.assignedToAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
.identifier("example.org|DNS")
.config(Map.ofEntries(
+ entry("TTL", 21600),
+ entry("auto-SOA", true),
+ entry("auto-NS-RR", true),
+ entry("auto-MX-RR", true),
+ entry("auto-A-RR", true),
+ entry("auto-AAAA-RR", true),
+ entry("auto-MAILSERVICES-RR", true),
+ entry("auto-AUTOCONFIG-RR", true),
+ entry("auto-AUTODISCOVER-RR", true),
+ entry("auto-DKIM-RR", true),
+ entry("auto-SPF-RR", true),
+ entry("auto-WILDCARD-MX-RR", true),
+ entry("auto-WILDCARD-A-RR", true),
+ entry("auto-WILDCARD-AAAA-RR", true),
+ entry("auto-WILDCARD-SPF-RR", true),
entry("user-RR", Array.of(
- "@ 1814400 IN XXX example.org. root.example.org ( 1234 10800 900 604800 86400 )",
"www IN CNAME example.com. ; www.example.com is an alias for example.com",
"test1 IN 1h30m CNAME example.com.",
"test2 1h30m IN CNAME example.com.",
- "ns IN A 192.0.2.2; IPv4 address for ns.example.com")
+ "ns IN A 192.0.2.2; IPv4 address for ns.example.com",
+ "_acme-challenge.PAULCHEN-VS.core.example.org. 60 IN CNAME _acme-challenge.core.example.org.acme-pki.de.")
)
));
}
@@ -53,7 +68,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
// then
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
"{type=integer, propertyName=TTL, min=0, defaultValue=21600}",
- "{type=boolean, propertyName=auto-SOA-RR, defaultValue=true}",
+ "{type=boolean, propertyName=auto-SOA, defaultValue=true}",
"{type=boolean, propertyName=auto-NS-RR, defaultValue=true}",
"{type=boolean, propertyName=auto-MX-RR, defaultValue=true}",
"{type=boolean, propertyName=auto-A-RR, defaultValue=true}",
@@ -66,9 +81,8 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
"{type=boolean, propertyName=auto-WILDCARD-MX-RR, defaultValue=true}",
"{type=boolean, propertyName=auto-WILDCARD-A-RR, defaultValue=true}",
"{type=boolean, propertyName=auto-WILDCARD-AAAA-RR, defaultValue=true}",
- "{type=boolean, propertyName=auto-WILDCARD-DKIM-RR, defaultValue=true}",
"{type=boolean, propertyName=auto-WILDCARD-SPF-RR, defaultValue=true}",
- "{type=string[], propertyName=user-RR, elementsOf={type=string, propertyName=user-RR, matchesRegEx=[([a-z0-9\\.-]+|@)\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*IN\\s+[A-Z]+\\s+[^;].*(;.*)*, ([a-z0-9\\.-]+|@)\\s+IN\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*[A-Z]+\\s+[^;].*(;.*)*], required=true}}"
+ "{type=string[], propertyName=user-RR, elementsOf={type=string, propertyName=user-RR, matchesRegEx=[(\\*\\.)?([a-zA-Z0-9\\._-]+|@)[ \t]+(([1-9][0-9]*[mMhHdDwW]?)+[ \t]+)?[iI][nN][ \t]+[a-zA-Z]+[ \t]+(([^;]+)|(\".*\")|(\\(.*\\)))[ \t]*(;.*)?, (\\*\\.)?([a-zA-Z0-9\\._-]+|@)[ \t]+[iI][nN][ \t]+(([1-9][0-9]*[mMhHdDwW]?)+[ \t]+)?[a-zA-Z]+[ \t]+(([^;]+)|(\".*\")|(\\(.*\\)))[ \t]*(;.*)?], required=true}}"
);
}
@@ -135,7 +149,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
}
@Test
- void acceptsValidEntity() {
+ void acceptsValidEntityItself() {
// given
final var givenEntity = validEntityBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
@@ -147,6 +161,19 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
assertThat(errors).isEmpty();
}
+ @Test
+ void acceptsValidEntityInContext() {
+ // given
+ final var givenEntity = validEntityBuilder().build();
+ final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
+
+ // when
+ final var errors = validator.validateContext(givenEntity);
+
+ // then
+ assertThat(errors).isEmpty();
+ }
+
@Test
void rejectsInvalidProperties() {
// given
@@ -166,35 +193,56 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
// then
assertThat(result).containsExactlyInAnyOrder(
"'DOMAIN_DNS_SETUP:example.org|DNS.config.TTL' is expected to be of type Integer, but is of type String",
- "'DOMAIN_DNS_SETUP:example.org|DNS.config.user-RR' is expected to match any of [([a-z0-9\\.-]+|@)\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*IN\\s+[A-Z]+\\s+[^;].*(;.*)*, ([a-z0-9\\.-]+|@)\\s+IN\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*[A-Z]+\\s+[^;].*(;.*)*] but '@ 1814400 IN 1814400 BAD1 TTL only allowed once' does not match any",
- "'DOMAIN_DNS_SETUP:example.org|DNS.config.user-RR' is expected to match any of [([a-z0-9\\.-]+|@)\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*IN\\s+[A-Z]+\\s+[^;].*(;.*)*, ([a-z0-9\\.-]+|@)\\s+IN\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*[A-Z]+\\s+[^;].*(;.*)*] but 'www BAD1 Record-Class missing / not enough columns' does not match any");
+ "'DOMAIN_DNS_SETUP:example.org|DNS.config.user-RR' is expected to match any of [(\\*\\.)?([a-zA-Z0-9\\._-]+|@)[ \t]+(([1-9][0-9]*[mMhHdDwW]?)+[ \t]+)?[iI][nN][ \t]+[a-zA-Z]+[ \t]+(([^;]+)|(\".*\")|(\\(.*\\)))[ \t]*(;.*)?, (\\*\\.)?([a-zA-Z0-9\\._-]+|@)[ \t]+[iI][nN][ \t]+(([1-9][0-9]*[mMhHdDwW]?)+[ \t]+)?[a-zA-Z]+[ \t]+(([^;]+)|(\".*\")|(\\(.*\\)))[ \t]*(;.*)?] but '@ 1814400 IN 1814400 BAD1 TTL only allowed once' does not match any",
+ "'DOMAIN_DNS_SETUP:example.org|DNS.config.user-RR' is expected to match any of [(\\*\\.)?([a-zA-Z0-9\\._-]+|@)[ \t]+(([1-9][0-9]*[mMhHdDwW]?)+[ \t]+)?[iI][nN][ \t]+[a-zA-Z]+[ \t]+(([^;]+)|(\".*\")|(\\(.*\\)))[ \t]*(;.*)?, (\\*\\.)?([a-zA-Z0-9\\._-]+|@)[ \t]+[iI][nN][ \t]+(([1-9][0-9]*[mMhHdDwW]?)+[ \t]+)?[a-zA-Z]+[ \t]+(([^;]+)|(\".*\")|(\\(.*\\)))[ \t]*(;.*)?] but 'www BAD1 Record-Class missing / not enough columns' does not match any");
}
@Test
- void validStringMatchesRegEx() {
+ void validNameMatchesRegEx() {
assertThat("@ ").matches(RR_REGEX_NAME);
assertThat("ns ").matches(RR_REGEX_NAME);
assertThat("example.com. ").matches(RR_REGEX_NAME);
+ assertThat("example.ORG. ").matches(RR_REGEX_NAME);
+ }
+ @Test
+ void validTtlMatchesRegEx() {
assertThat("12400 ").matches(RR_REGEX_TTL);
assertThat("12400\t\t ").matches(RR_REGEX_TTL);
assertThat("12400 \t\t").matches(RR_REGEX_TTL);
assertThat("1h30m ").matches(RR_REGEX_TTL);
assertThat("30m ").matches(RR_REGEX_TTL);
+ }
+ @Test
+ void validInMatchesRegEx() {
+ assertThat("in ").matches(RR_REGEX_IN);
assertThat("IN ").matches(RR_REGEX_IN);
assertThat("IN\t\t ").matches(RR_REGEX_IN);
assertThat("IN \t\t").matches(RR_REGEX_IN);
+ }
+ @Test
+ void validRecordTypeMatchesRegEx() {
+ assertThat("a ").matches(RR_RECORD_TYPE);
assertThat("CNAME ").matches(RR_RECORD_TYPE);
assertThat("CNAME\t\t ").matches(RR_RECORD_TYPE);
assertThat("CNAME \t\t").matches(RR_RECORD_TYPE);
+ }
+ @Test
+ void validRecordDataMatchesRegEx() {
assertThat("example.com.").matches(RR_RECORD_DATA);
+ assertThat("example.com. ").matches(RR_RECORD_DATA);
assertThat("123.123.123.123").matches(RR_RECORD_DATA);
+ assertThat("123.123.123.123 ").matches(RR_RECORD_DATA);
+ assertThat("_acme-challenge.core.example.org.acme-pki.de.").matches(RR_RECORD_DATA);
assertThat("(some more complex argument in parenthesis)").matches(RR_RECORD_DATA);
assertThat("\"some more complex argument; including a semicolon\"").matches(RR_RECORD_DATA);
+ }
+ @Test
+ void validCommentMatchesRegEx() {
assertThat("; whatever ; \" really anything").matches(RR_COMMENT);
}
@@ -209,18 +257,42 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
// then
assertThat(zonefile).isEqualTo("""
- $ORIGIN example.org.
$TTL 21600
- ; these records are just placeholders to create a valid zonefile for the validation
- @ 1814400 IN SOA example.org. root.example.org ( 1999010100 10800 900 604800 86400 )
- @ IN NS ns
+ example.org. IN SOA h00.hostsharing.net. hostmaster.hostsharing.net. (
+ 1303649373 ; serial secs since Jan 1 1970
+ 6H ; refresh (>=10000)
+ 1H ; retry (>=1800)
+ 1W ; expire
+ 1H ; minimum
+ )
+
+ example.org. IN NS dns1.hostsharing.net.
+ example.org. IN NS dns2.hostsharing.net.
+ example.org. IN NS dns3.hostsharing.net.
+
+ example.org. IN MX 30 mailin1.hostsharing.net.
+ example.org. IN MX 30 mailin2.hostsharing.net.
+ example.org. IN MX 30 mailin3.hostsharing.net.
+
+ example.org. IN A 83.223.95.160
+ example.org. IN AAAA 2a01:37:1000::53df:5fa0:0
+ default._domainkey 21600 IN TXT "v=DKIM1; h=sha256; k=rsa; s=email; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmdM9d15bqe94zbHVcKKpUF875XoCWHKRap/sG3NJZ9xZ/BjfGXmqoEYeFNpX3CB7pOXhH5naq4N+6gTjArTviAiVThHXyebhrxaf1dVS4IUC6raTEyQrWPZUf7ZxXmcCYvOdV4jIQ8GRfxwxqibIJcmMiufXTLIgRUif5uaTgFwIDAQAB"
+ example.org. IN TXT "v=spf1 include:spf.hostsharing.net ?all"
+
+ *.example.org. IN MX 30 mailin1.hostsharing.net.
+ *.example.org. IN MX 30 mailin1.hostsharing.net.
+ *.example.org. IN MX 30 mailin1.hostsharing.net.
+
+ *.example.org. IN A 83.223.95.160
+ *.example.org. IN AAAA 2a01:37:1000::53df:5fa0:0
+ *.example.org. IN TXT "v=spf1 include:spf.hostsharing.net ?all"
- @ 1814400 IN XXX example.org. root.example.org ( 1234 10800 900 604800 86400 )
www IN CNAME example.com. ; www.example.com is an alias for example.com
test1 IN 1h30m CNAME example.com.
test2 1h30m IN CNAME example.com.
ns IN A 192.0.2.2; IPv4 address for ns.example.com
+ _acme-challenge.PAULCHEN-VS.core.example.org. 60 IN CNAME _acme-challenge.core.example.org.acme-pki.de.
""");
}
@@ -229,7 +301,8 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
// given
final var givenEntity = validEntityBuilder().config(Map.ofEntries(
entry("user-RR", Array.of(
- "example.org. 1814400 IN SOA example.org. root.example.org (1234 10800 900 604800 86400)"
+ "example.org. 1814400 IN SOA example.org. root.example.org (1234 10800 900 604800 86400)",
+ "example.org. 1814400 IN SOA example.org. root.example.org (4321 10800 900 604800 86400)"
))
))
.build();
@@ -240,9 +313,9 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
// then
assertThat(errors).containsExactlyInAnyOrder(
- "dns_master_load: example.org: multiple RRs of singleton type",
- "zone example.org/IN: loading from master file (null) failed: multiple RRs of singleton type",
- "zone example.org/IN: not loaded due to errors."
+ "[example.org|DNS] dns_master_load:line 26: example.org: multiple RRs of singleton type",
+ "[example.org|DNS] zone example.org/IN: loading from master file (null) failed: multiple RRs of singleton type",
+ "[example.org|DNS] zone example.org/IN: not loaded due to errors."
);
}
}
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainHttpSetupHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainHttpSetupHostingAssetValidatorUnitTest.java
index 29b4c05b..2cce0d82 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainHttpSetupHostingAssetValidatorUnitTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsDomainHttpSetupHostingAssetValidatorUnitTest.java
@@ -30,7 +30,8 @@ class HsDomainHttpSetupHostingAssetValidatorUnitTest {
.assignedToAsset(HsHostingAssetEntity.builder().type(UNIX_USER).build())
.identifier("example.org|HTTP")
.config(Map.ofEntries(
- entry("passenger-errorpage", true),
+ entry("passenger-errorpage", true),
+ entry("fcgi-php-bin", "/usr/bin/whatsoever"),
entry("subdomains", Array.of("www", "test")
)
));
@@ -54,10 +55,10 @@ class HsDomainHttpSetupHostingAssetValidatorUnitTest {
"{type=boolean, propertyName=includes, defaultValue=true}",
"{type=boolean, propertyName=letsencrypt, defaultValue=true}",
"{type=boolean, propertyName=multiviews, defaultValue=true}",
- "{type=string, propertyName=fcgi-php-bin, matchesRegEx=[^/], provided=[/usr/lib/cgi-bin/php], defaultValue=/usr/lib/cgi-bin/php}",
- "{type=string, propertyName=passenger-nodejs, matchesRegEx=[^/], provided=[/usr/bin/node], defaultValue=/usr/bin/node}",
- "{type=string, propertyName=passenger-python, matchesRegEx=[^/], provided=[/usr/bin/python3], defaultValue=/usr/bin/python3}",
- "{type=string, propertyName=passenger-ruby, matchesRegEx=[^/], provided=[/usr/bin/ruby], defaultValue=/usr/bin/ruby}",
+ "{type=string, propertyName=fcgi-php-bin, matchesRegEx=[^/.*], provided=[/usr/lib/cgi-bin/php], defaultValue=/usr/lib/cgi-bin/php}",
+ "{type=string, propertyName=passenger-nodejs, matchesRegEx=[^/.*], provided=[/usr/bin/node], defaultValue=/usr/bin/node}",
+ "{type=string, propertyName=passenger-python, matchesRegEx=[^/.*], provided=[/usr/bin/python3], defaultValue=/usr/bin/python3}",
+ "{type=string, propertyName=passenger-ruby, matchesRegEx=[^/.*], provided=[/usr/bin/ruby], defaultValue=/usr/bin/ruby}",
"{type=string[], propertyName=subdomains, elementsOf={type=string, propertyName=subdomains, matchesRegEx=[(?!-)[A-Za-z0-9-]{1,63}(? errors = new ArrayList<>();
+ static final LinkedHashSet errors = new LinkedHashSet<>();
public List readAllLines(Reader reader) throws Exception {
@@ -115,7 +115,20 @@ public class CsvDataImport extends ContextBasedTest {
}
protected Reader resourceReader(@NotNull final String resourcePath) {
- return new InputStreamReader(requireNonNull(getClass().getClassLoader().getResourceAsStream(resourcePath)));
+ try {
+ return new InputStreamReader(requireNonNull(getClass().getClassLoader().getResourceAsStream(resourcePath)));
+ } catch (Exception exc) {
+ throw new AssertionFailedError("cannot open '" + resourcePath + "'");
+ }
+ }
+
+ protected String resourceAsString(@NotNull final String resourcePath) {
+ try (InputStream inputStream = requireNonNull(getClass().getClassLoader().getResourceAsStream(resourcePath));
+ final var reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
+ return reader.lines().collect(Collectors.joining(System.lineSeparator()));
+ } catch (Exception exc) {
+ throw new AssertionFailedError("cannot open '" + resourcePath + "'");
+ }
}
protected List withoutHeader(final List records) {
@@ -127,7 +140,9 @@ public class CsvDataImport extends ContextBasedTest {
try (final var reader = new CSVReader(new StringReader(csvLine))) {
return stream(ofNullable(reader.readNext()).orElse(emptyArray(String.class)))
.map(String::trim)
- .map(target -> target.startsWith("'") && target.endsWith("'") ? target.substring(1, target.length()-1) : target)
+ .map(target -> target.startsWith("'") && target.endsWith("'") ?
+ target.substring(1, target.length() - 1) :
+ target)
.toArray(String[]::new);
}
}
@@ -147,7 +162,7 @@ public class CsvDataImport extends ContextBasedTest {
//noinspection unchecked
return (T) persistViaSql(id, ha);
}
- return persistViaEM(id, entity);
+ return persistViaEM(id, entity);
} catch (Exception exc) {
errors.add("failed to persist #" + entity.hashCode() + ": " + entity);
errors.add(exc.toString());
@@ -171,38 +186,40 @@ public class CsvDataImport extends ContextBasedTest {
}
final var query = em.createNativeQuery("""
- insert into hs_hosting_asset(
- uuid,
- type,
- bookingitemuuid,
- parentassetuuid,
- assignedtoassetuuid,
- alarmcontactuuid,
- identifier,
- caption,
- config,
- version)
- values (
- :uuid,
- :type,
- :bookingitemuuid,
- :parentassetuuid,
- :assignedtoassetuuid,
- :alarmcontactuuid,
- :identifier,
- :caption,
- cast(:config as jsonb),
- :version)
- """)
+ insert into hs_hosting_asset(
+ uuid,
+ type,
+ bookingitemuuid,
+ parentassetuuid,
+ assignedtoassetuuid,
+ alarmcontactuuid,
+ identifier,
+ caption,
+ config,
+ version)
+ values (
+ :uuid,
+ :type,
+ :bookingitemuuid,
+ :parentassetuuid,
+ :assignedtoassetuuid,
+ :alarmcontactuuid,
+ :identifier,
+ :caption,
+ cast(:config as jsonb),
+ :version)
+ """)
.setParameter("uuid", entity.getUuid())
.setParameter("type", entity.getType().name())
.setParameter("bookingitemuuid", ofNullable(entity.getBookingItem()).map(BaseEntity::getUuid).orElse(null))
.setParameter("parentassetuuid", ofNullable(entity.getParentAsset()).map(BaseEntity::getUuid).orElse(null))
- .setParameter("assignedtoassetuuid", ofNullable(entity.getAssignedToAsset()).map(BaseEntity::getUuid).orElse(null))
+ .setParameter(
+ "assignedtoassetuuid",
+ ofNullable(entity.getAssignedToAsset()).map(BaseEntity::getUuid).orElse(null))
.setParameter("alarmcontactuuid", ofNullable(entity.getAlarmContact()).map(BaseEntity::getUuid).orElse(null))
.setParameter("identifier", entity.getIdentifier())
.setParameter("caption", entity.getCaption())
- .setParameter("config", entity.getConfig().toString())
+ .setParameter("config", entity.getConfig().toString().replace("\t", "\\t"))
.setParameter("version", entity.getVersion());
final var count = query.executeUpdate();
@@ -212,17 +229,18 @@ public class CsvDataImport extends ContextBasedTest {
return entity;
}
- protected String toFormattedString(final Map map) {
+ protected String toJsonFormattedString(final Map map) {
if ( map.isEmpty() ) {
return "{}";
}
- return "{\n" +
+ final var json = "{\n" +
map.keySet().stream()
.map(id -> " " + id + "=" + map.get(id).toString())
- .map(e -> e.replaceAll("\n ", " ").replace("\n", ""))
+ .map(e -> e.replaceAll("\n ", " ").replace("\n", "").replace(" : ", ": ").replace("{ ", "{").replace(", ", ", "))
.sorted()
.collect(Collectors.joining(",\n")) +
"\n}\n";
+ return json;
}
protected void deleteTestDataFromHsOfficeTables() {
@@ -292,44 +310,26 @@ public class CsvDataImport extends ContextBasedTest {
try {
assertion.run();
} catch (final AssertionError exc) {
- errors.add(exc.toString());
+ logError(exc.getMessage());
}
}
- void logErrors() {
- final var errorsToLog = new ArrayList<>(errors);
+ public static void logError(final String error) {
+ errors.add(error);
+ }
+
+ protected static void expectError(final String expectedError) {
+ final var found = errors.remove(expectedError);
+ if (!found) {
+ logError("expected but not found: " + expectedError);
+ }
+ }
+
+ protected final void assertNoErrors() {
+ final var errorsToLog = new LinkedHashSet<>(errors);
errors.clear();
assertThat(errorsToLog).isEmpty();
}
-
- void expectErrors(final String... expectedErrors) {
- assertContainsExactlyInAnyOrderIgnoringWhitespace(errors, expectedErrors);
- }
-
- private static class IgnoringWhitespaceComparator implements Comparator {
- @Override
- public int compare(String s1, String s2) {
- return s1.replaceAll("\\s", "").compareTo(s2.replaceAll("\\s", ""));
- }
- }
-
- public static void assertContainsExactlyInAnyOrderIgnoringWhitespace(final List expected, final List actual) {
- final var sortedExpected = expected.stream()
- .map(m -> m.replaceAll("\\s+", " "))
- .map(m -> m.replaceAll("^ ", ""))
- .map(m -> m.replaceAll(" $", ""))
- .toList();
- final var sortedActual = actual.stream()
- .map(m -> m.replaceAll("\\s+", " "))
- .map(m -> m.replaceAll("^ ", ""))
- .map(m -> m.replaceAll(" $", ""))
- .toArray(String[]::new);
- assertThat(sortedExpected).containsExactlyInAnyOrder(sortedActual);
- }
-
- public static void assertContainsExactlyInAnyOrderIgnoringWhitespace(final List expected, final String... actual) {
- assertContainsExactlyInAnyOrderIgnoringWhitespace(expected, asList(actual));
- }
}
class Columns {
@@ -373,7 +373,7 @@ class Record {
boolean getBoolean(final String columnName) {
final String value = getString(columnName);
return isNotBlank(value) &&
- ( parseBoolean(value.trim()) || value.trim().startsWith("t"));
+ (parseBoolean(value.trim()) || value.trim().startsWith("t"));
}
Integer getInteger(final String columnName) {
@@ -408,7 +408,9 @@ class OrderedDependedTestsExtension implements TestWatcher, BeforeEachCallback {
@Override
public void testFailed(final ExtensionContext context, final Throwable cause) {
- previousTestsPassed = previousTestsPassed && context.getElement().map(e -> e.isAnnotationPresent(ContinueOnFailure.class)).orElse(false);
+ previousTestsPassed = previousTestsPassed && context.getElement()
+ .map(e -> e.isAnnotationPresent(ContinueOnFailure.class))
+ .orElse(false);
}
@Override
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java
index ae1b5e44..989a9ae4 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java
@@ -1,5 +1,7 @@
package net.hostsharing.hsadminng.hs.migration;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hash.HashGenerator;
import net.hostsharing.hsadminng.hash.HashGenerator.Algorithm;
@@ -10,6 +12,8 @@ import net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityV
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor;
+import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry;
+import net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainDnsSetupHostingAssetValidator;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.MethodOrderer;
@@ -18,12 +22,15 @@ import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.reflections.Reflections;
+import org.reflections.scanners.ResourcesScanner;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.Commit;
import org.springframework.test.annotation.DirtiesContext;
import java.io.Reader;
+import java.net.IDN;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -32,6 +39,8 @@ import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import static java.util.Arrays.stream;
import static java.util.Map.entry;
@@ -40,6 +49,11 @@ import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
+import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_DNS_SETUP;
+import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_HTTP_SETUP;
+import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_MBOX_SETUP;
+import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
+import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SMTP_SETUP;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.EMAIL_ALIAS;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV4_NUMBER;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
@@ -112,6 +126,12 @@ public class ImportHostingAssets extends ImportOfficeData {
static final Integer DBINSTANCE_ID_OFFSET = 6000000;
static final Integer DBUSER_ID_OFFSET = 7000000;
static final Integer DB_ID_OFFSET = 8000000;
+ static final Integer DOMAIN_SETUP_OFFSET = 10000000;
+ static final Integer DOMAIN_DNS_SETUP_OFFSET = 11000000;
+ static final Integer DOMAIN_HTTP_SETUP_OFFSET = 12000000;
+ static final Integer DOMAIN_MBOX_SETUP_OFFSET = 13000000;
+ static final Integer DOMAIN_SMTP_SETUP_OFFSET = 14000000;
+ static List zonefileErrors = new ArrayList<>();
record Hive(int hive_id, String hive_name, int inet_addr_id, AtomicReference serverRef) {}
@@ -120,6 +140,9 @@ public class ImportHostingAssets extends ImportOfficeData {
static Map hives = new WriteOnceMap<>();
static Map hostingAssets = new WriteOnceMap<>(); // TODO.impl: separate maps for each type?
static Map dbUsersByEngineAndName = new WriteOnceMap<>();
+ static Map domainSetupsByName = new WriteOnceMap<>();
+
+ final ObjectMapper jsonMapper = new ObjectMapper();
@Test
@Order(11010)
@@ -175,7 +198,7 @@ public class ImportHostingAssets extends ImportOfficeData {
void verifyHives() {
assumeThatWeAreImportingControlledTestData();
- assertThat(toFormattedString(first(5, hives))).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(first(5, hives))).isEqualToIgnoringWhitespace("""
{
2000001=Hive[hive_id=1, hive_name=h00, inet_addr_id=358, serverRef=null],
2000002=Hive[hive_id=2, hive_name=h01, inet_addr_id=359, serverRef=null],
@@ -267,15 +290,15 @@ public class ImportHostingAssets extends ImportOfficeData {
HsBookingItemType.MANAGED_WEBSPACE))
.isEqualToIgnoringWhitespace("""
{
- 3000630=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_WEBSPACE, [2001-06-01,), BI hsh00, { "HDD": 10, "Multi": 25, "SLA-Platform": "EXT24H", "SSD": 16, "Traffic": 50}),
- 3000968=HsBookingItemEntity(D-1015200:rar default project, MANAGED_SERVER, [2013-04-01,), BI vm1061, { "CPU": 6, "HDD": 250, "RAM": 14, "SLA-EMail": true, "SLA-Maria": true, "SLA-Office": true, "SLA-PgSQL": true, "SLA-Platform": "EXT4H", "SLA-Web": true, "SSD": 375, "Traffic": 250}),
- 3000978=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_SERVER, [2013-04-01,), BI vm1050, { "CPU": 4, "HDD": 250, "RAM": 32, "SLA-EMail": true, "SLA-Maria": true, "SLA-Office": true, "SLA-PgSQL": true, "SLA-Platform": "EXT4H", "SLA-Web": true, "SSD": 150, "Traffic": 250}),
- 3001061=HsBookingItemEntity(D-1000300:mim default project, MANAGED_SERVER, [2013-08-19,), BI vm1068, { "CPU": 2, "HDD": 250, "RAM": 4, "SLA-EMail": true, "SLA-Maria": true, "SLA-Office": true, "SLA-PgSQL": true, "SLA-Platform": "EXT2H", "SLA-Web": true, "Traffic": 250}),
- 3001094=HsBookingItemEntity(D-1000300:mim default project, MANAGED_WEBSPACE, [2013-09-10,), BI lug00, { "Multi": 5, "SLA-Platform": "EXT24H", "SSD": 1, "Traffic": 10}),
- 3001112=HsBookingItemEntity(D-1000300:mim default project, MANAGED_WEBSPACE, [2013-09-17,), BI mim00, { "Multi": 5, "SLA-Platform": "EXT24H", "SSD": 3, "Traffic": 20}),
- 3001447=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_SERVER, [2014-11-28,), BI vm1093, { "CPU": 6, "HDD": 500, "RAM": 16, "SLA-EMail": true, "SLA-Maria": true, "SLA-Office": true, "SLA-PgSQL": true, "SLA-Platform": "EXT4H", "SLA-Web": true, "SSD": 300, "Traffic": 250}),
- 3019959=HsBookingItemEntity(D-1101900:dph default project, MANAGED_WEBSPACE, [2021-06-02,), BI dph00, { "Multi": 1, "SLA-Platform": "EXT24H", "SSD": 25, "Traffic": 20}),
- 3023611=HsBookingItemEntity(D-1101800:wws default project, CLOUD_SERVER, [2022-08-10,), BI vm2097, { "CPU": 8, "RAM": 12, "SLA-Infrastructure": "EXT4H", "SSD": 25, "Traffic": 250})
+ 3000630=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_WEBSPACE, [2001-06-01,), BI hsh00, {"HDD" : 10, "Multi" : 25, "SLA-Platform" : "EXT24H", "SSD" : 16, "Traffic" : 50}),
+ 3000968=HsBookingItemEntity(D-1015200:rar default project, MANAGED_SERVER, [2013-04-01,), BI vm1061, {"CPU" : 6, "HDD" : 250, "RAM" : 14, "SLA-EMail" : true, "SLA-Maria" : true, "SLA-Office" : true, "SLA-PgSQL" : true, "SLA-Platform" : "EXT4H", "SLA-Web" : true, "SSD" : 375, "Traffic" : 250}),
+ 3000978=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_SERVER, [2013-04-01,), BI vm1050, {"CPU" : 4, "HDD" : 250, "RAM" : 32, "SLA-EMail" : true, "SLA-Maria" : true, "SLA-Office" : true, "SLA-PgSQL" : true, "SLA-Platform" : "EXT4H", "SLA-Web" : true, "SSD" : 150, "Traffic" : 250}),
+ 3001061=HsBookingItemEntity(D-1000300:mim default project, MANAGED_SERVER, [2013-08-19,), BI vm1068, {"CPU" : 2, "HDD" : 250, "RAM" : 4, "SLA-EMail" : true, "SLA-Maria" : true, "SLA-Office" : true, "SLA-PgSQL" : true, "SLA-Platform" : "EXT2H", "SLA-Web" : true, "Traffic" : 250}),
+ 3001094=HsBookingItemEntity(D-1000300:mim default project, MANAGED_WEBSPACE, [2013-09-10,), BI lug00, {"Multi" : 5, "SLA-Platform" : "EXT24H", "SSD" : 1, "Traffic" : 10}),
+ 3001112=HsBookingItemEntity(D-1000300:mim default project, MANAGED_WEBSPACE, [2013-09-17,), BI mim00, {"Multi" : 5, "SLA-Platform" : "EXT24H", "SSD" : 3, "Traffic" : 20}),
+ 3001447=HsBookingItemEntity(D-1000000:hsh default project, MANAGED_SERVER, [2014-11-28,), BI vm1093, {"CPU" : 6, "HDD" : 500, "RAM" : 16, "SLA-EMail" : true, "SLA-Maria" : true, "SLA-Office" : true, "SLA-PgSQL" : true, "SLA-Platform" : "EXT4H", "SLA-Web" : true, "SSD" : 300, "Traffic" : 250}),
+ 3019959=HsBookingItemEntity(D-1101900:dph default project, MANAGED_WEBSPACE, [2021-06-02,), BI dph00, {"Multi" : 1, "SLA-Platform" : "EXT24H", "SSD" : 25, "Traffic" : 20}),
+ 3023611=HsBookingItemEntity(D-1101800:wws default project, CLOUD_SERVER, [2022-08-10,), BI vm2097, {"CPU" : 8, "RAM" : 12, "SLA-Infrastructure" : "EXT4H", "SSD" : 25, "Traffic" : 250})
}
""");
}
@@ -298,20 +321,20 @@ public class ImportHostingAssets extends ImportOfficeData {
assertThat(firstOfEachType(15, UNIX_USER)).isEqualToIgnoringWhitespace("""
{
- 4005803=HsHostingAssetRealEntity(UNIX_USER, lug00, LUGs, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102090}),
- 4005805=HsHostingAssetRealEntity(UNIX_USER, lug00-wla.1, Paul Klemm, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102091}),
- 4005809=HsHostingAssetRealEntity(UNIX_USER, lug00-wla.2, Walter Müller, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 8, "SSD soft quota": 4, "locked": false, "shell": "/bin/bash", "userid": 102093}),
- 4005811=HsHostingAssetRealEntity(UNIX_USER, lug00-ola.a, LUG OLA - POP a, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102094}),
- 4005813=HsHostingAssetRealEntity(UNIX_USER, lug00-ola.b, LUG OLA - POP b, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102095}),
- 4005835=HsHostingAssetRealEntity(UNIX_USER, lug00-test, Test, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 1024, "SSD soft quota": 1024, "locked": false, "shell": "/usr/bin/passwd", "userid": 102106}),
- 4005964=HsHostingAssetRealEntity(UNIX_USER, mim00, Michael Mellis, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102147}),
- 4005966=HsHostingAssetRealEntity(UNIX_USER, mim00-1981, Jahrgangstreffen 1981, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 256, "SSD soft quota": 128, "locked": false, "shell": "/bin/bash", "userid": 102148}),
- 4005990=HsHostingAssetRealEntity(UNIX_USER, mim00-mail, Mailbox, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102160}),
- 4100705=HsHostingAssetRealEntity(UNIX_USER, hsh00-mim, Michael Mellis, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/false", "userid": 10003}),
- 4100824=HsHostingAssetRealEntity(UNIX_USER, hsh00, Hostsharing Paket, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 10000}),
- 4167846=HsHostingAssetRealEntity(UNIX_USER, hsh00-dph, hsh00-uph, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/false", "userid": 110568}),
- 4169546=HsHostingAssetRealEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110593}),
- 4169596=HsHostingAssetRealEntity(UNIX_USER, dph00-uph, Domain admin, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110594})
+ 4005803=HsHostingAssetRealEntity(UNIX_USER, lug00, LUGs, MANAGED_WEBSPACE:lug00, {"SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102090}),
+ 4005805=HsHostingAssetRealEntity(UNIX_USER, lug00-wla.1, Paul Klemm, MANAGED_WEBSPACE:lug00, {"SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102091}),
+ 4005809=HsHostingAssetRealEntity(UNIX_USER, lug00-wla.2, Walter Müller, MANAGED_WEBSPACE:lug00, {"SSD hard quota": 8, "SSD soft quota": 4, "locked": false, "shell": "/bin/bash", "userid": 102093}),
+ 4005811=HsHostingAssetRealEntity(UNIX_USER, lug00-ola.a, LUG OLA - POP a, MANAGED_WEBSPACE:lug00, {"SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102094}),
+ 4005813=HsHostingAssetRealEntity(UNIX_USER, lug00-ola.b, LUG OLA - POP b, MANAGED_WEBSPACE:lug00, {"SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102095}),
+ 4005835=HsHostingAssetRealEntity(UNIX_USER, lug00-test, Test, MANAGED_WEBSPACE:lug00, {"SSD hard quota": 1024, "SSD soft quota": 1024, "locked": false, "shell": "/usr/bin/passwd", "userid": 102106}),
+ 4005964=HsHostingAssetRealEntity(UNIX_USER, mim00, Michael Mellis, MANAGED_WEBSPACE:mim00, {"SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102147}),
+ 4005966=HsHostingAssetRealEntity(UNIX_USER, mim00-1981, Jahrgangstreffen 1981, MANAGED_WEBSPACE:mim00, {"SSD hard quota": 256, "SSD soft quota": 128, "locked": false, "shell": "/bin/bash", "userid": 102148}),
+ 4005990=HsHostingAssetRealEntity(UNIX_USER, mim00-mail, Mailbox, MANAGED_WEBSPACE:mim00, {"SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102160}),
+ 4100705=HsHostingAssetRealEntity(UNIX_USER, hsh00-mim, Michael Mellis, MANAGED_WEBSPACE:hsh00, {"HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/false", "userid": 10003}),
+ 4100824=HsHostingAssetRealEntity(UNIX_USER, hsh00, Hostsharing Paket, MANAGED_WEBSPACE:hsh00, {"HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 10000}),
+ 4167846=HsHostingAssetRealEntity(UNIX_USER, hsh00-dph, hsh00-uph, MANAGED_WEBSPACE:hsh00, {"HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/false", "userid": 110568}),
+ 4169546=HsHostingAssetRealEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, {"SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110593}),
+ 4169596=HsHostingAssetRealEntity(UNIX_USER, dph00-dph, Domain admin, MANAGED_WEBSPACE:dph00, {"SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110594})
}
""");
}
@@ -334,17 +357,15 @@ public class ImportHostingAssets extends ImportOfficeData {
assertThat(firstOfEachType(15, EMAIL_ALIAS)).isEqualToIgnoringWhitespace("""
{
- 5002403=HsHostingAssetRealEntity(EMAIL_ALIAS, lug00, lug00, MANAGED_WEBSPACE:lug00, { "target": "[michael.mellis@example.com]"}),
- 5002405=HsHostingAssetRealEntity(EMAIL_ALIAS, lug00-wla-listar, lug00-wla-listar, MANAGED_WEBSPACE:lug00, { "target": "[|/home/pacs/lug00/users/in/mailinglist/listar]"}),
- 5002429=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00, mim00, MANAGED_WEBSPACE:mim00, { "target": "[mim12-mi@mim12.hostsharing.net]"}),
- 5002431=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-abruf, mim00-abruf, MANAGED_WEBSPACE:mim00, { "target": "[michael.mellis@hostsharing.net]"}),
- 5002449=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-hhfx, mim00-hhfx, MANAGED_WEBSPACE:mim00, { "target": "[mim00-hhfx, |/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l]"}),
- 5002451=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-hhfx-l, mim00-hhfx-l, MANAGED_WEBSPACE:mim00, { "target": "[:include:/home/pacs/mim00/etc/hhfx.list]"}),
- 5002452=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-empty, mim00-empty, MANAGED_WEBSPACE:mim00, { "target": "[]"}),
- 5002453=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-0_entries, mim00-0_entries, MANAGED_WEBSPACE:mim00, { "target": "[]"}),
- 5002454=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-dev.null, mim00-dev.null, MANAGED_WEBSPACE:mim00, { "target": "[/dev/null]"}),
- 5002455=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-1_with_space, mim00-1_with_space, MANAGED_WEBSPACE:mim00, { "target": "[|/home/pacs/mim00/install/corpslistar/listar]"}),
- 5002456=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-1_with_single_quotes, mim00-1_with_single_quotes, MANAGED_WEBSPACE:mim00, { "target": "[|/home/pacs/rir00/mailinglist/ecartis -r kybs06-intern]"})
+ 5002403=HsHostingAssetRealEntity(EMAIL_ALIAS, lug00, lug00, MANAGED_WEBSPACE:lug00, {"target": [ "michael.mellis@example.com" ]}),
+ 5002405=HsHostingAssetRealEntity(EMAIL_ALIAS, lug00-wla-listar, lug00-wla-listar, MANAGED_WEBSPACE:lug00, {"target": [ "|/home/pacs/lug00/users/in/mailinglist/listar" ]}),
+ 5002429=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00, mim00, MANAGED_WEBSPACE:mim00, {"target": [ "mim12-mi@mim12.hostsharing.net" ]}),
+ 5002431=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-abruf, mim00-abruf, MANAGED_WEBSPACE:mim00, {"target": [ "michael.mellis@hostsharing.net" ]}),
+ 5002449=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-hhfx, mim00-hhfx, MANAGED_WEBSPACE:mim00, {"target": [ "mim00-hhfx", "|/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l" ]}),
+ 5002451=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-hhfx-l, mim00-hhfx-l, MANAGED_WEBSPACE:mim00, {"target": [ ":include:/home/pacs/mim00/etc/hhfx.list" ]}),
+ 5002454=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-dev.null, mim00-dev.null, MANAGED_WEBSPACE:mim00, {"target": [ "/dev/null" ]}),
+ 5002455=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-1_with_space, mim00-1_with_space, MANAGED_WEBSPACE:mim00, {"target": [ "|/home/pacs/mim00/install/corpslistar/listar" ]}),
+ 5002456=HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-1_with_single_quotes, mim00-1_with_single_quotes, MANAGED_WEBSPACE:mim00, {"target": [ "|/home/pacs/rir00/mailinglist/ecartis -r kybs06-intern" ]})
}
""");
}
@@ -352,7 +373,7 @@ public class ImportHostingAssets extends ImportOfficeData {
@Test
@Order(15000)
void createDatabaseInstances() {
- createDatabaseInstances(hostingAssets.values().stream().filter(ha -> ha.getType()==MANAGED_SERVER).toList());
+ createDatabaseInstances(hostingAssets.values().stream().filter(ha -> ha.getType() == MANAGED_SERVER).toList());
}
@Test
@@ -438,6 +459,94 @@ public class ImportHostingAssets extends ImportOfficeData {
""");
}
+ @Test
+ @Order(16010)
+ void importDomains() {
+ try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/hosting/domain.csv")) {
+ final var lines = readAllLines(reader);
+ importDomains(justHeader(lines), withoutHeader(lines));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ @Order(16020)
+ void importZonenfiles() {
+ final var reflections = new Reflections(MIGRATION_DATA_PATH + "/hosting/zonefiles", new ResourcesScanner());
+ final var zonefileFiles = reflections.getResources(Pattern.compile(".*\\.json")).stream().sorted().toList();
+ zonefileFiles.forEach(zonenfileName -> {
+ System.out.println("Processing zonenfile: " + zonenfileName);
+ importZonefiles(vmName(zonenfileName), resourceAsString(zonenfileName));
+ });
+ }
+
+ private String vmName(final String zonenfileName) {
+ return zonenfileName.substring(zonenfileName.length() - "vm0000.json".length()).substring(0, 6);
+ }
+
+ @Test
+ @Order(16019)
+ void verifyDomains() {
+ assumeThatWeAreImportingControlledTestData();
+
+ assertThat(firstOfEachType(
+ 12,
+ DOMAIN_SETUP,
+ DOMAIN_DNS_SETUP,
+ DOMAIN_HTTP_SETUP,
+ DOMAIN_MBOX_SETUP,
+ DOMAIN_SMTP_SETUP)).isEqualToIgnoringWhitespace("""
+ {
+ 10004531=HsHostingAssetRealEntity(DOMAIN_SETUP, l-u-g.org, l-u-g.org),
+ 10004532=HsHostingAssetRealEntity(DOMAIN_SETUP, linuxfanboysngirls.de, linuxfanboysngirls.de),
+ 10004534=HsHostingAssetRealEntity(DOMAIN_SETUP, lug-mars.de, lug-mars.de),
+ 10004581=HsHostingAssetRealEntity(DOMAIN_SETUP, 1981.ist-im-netz.de, 1981.ist-im-netz.de, DOMAIN_SETUP:ist-im-netz.de),
+ 10004587=HsHostingAssetRealEntity(DOMAIN_SETUP, mellis.de, mellis.de),
+ 10004589=HsHostingAssetRealEntity(DOMAIN_SETUP, ist-im-netz.de, ist-im-netz.de),
+ 10004600=HsHostingAssetRealEntity(DOMAIN_SETUP, waera.de, waera.de),
+ 10004604=HsHostingAssetRealEntity(DOMAIN_SETUP, xn--wra-qla.de, wära.de),
+ 10027662=HsHostingAssetRealEntity(DOMAIN_SETUP, dph-netzwerk.de, dph-netzwerk.de),
+ 11004531=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, l-u-g.org|DNS, DNS-Setup für l-u-g.org, DOMAIN_SETUP:l-u-g.org, MANAGED_WEBSPACE:lug00),
+ 11004532=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, linuxfanboysngirls.de|DNS, DNS-Setup für linuxfanboysngirls.de, DOMAIN_SETUP:linuxfanboysngirls.de, MANAGED_WEBSPACE:lug00),
+ 11004534=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, lug-mars.de|DNS, DNS-Setup für lug-mars.de, DOMAIN_SETUP:lug-mars.de, MANAGED_WEBSPACE:lug00),
+ 11004581=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, 1981.ist-im-netz.de|DNS, DNS-Setup für 1981.ist-im-netz.de, DOMAIN_SETUP:1981.ist-im-netz.de, MANAGED_WEBSPACE:mim00),
+ 11004587=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, mellis.de|DNS, DNS-Setup für mellis.de, DOMAIN_SETUP:mellis.de, MANAGED_WEBSPACE:mim00),
+ 11004589=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, ist-im-netz.de|DNS, DNS-Setup für ist-im-netz.de, DOMAIN_SETUP:ist-im-netz.de, MANAGED_WEBSPACE:mim00),
+ 11004600=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, waera.de|DNS, DNS-Setup für waera.de, DOMAIN_SETUP:waera.de, MANAGED_WEBSPACE:mim00),
+ 11004604=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, xn--wra-qla.de|DNS, DNS-Setup für wära.de, DOMAIN_SETUP:xn--wra-qla.de, MANAGED_WEBSPACE:mim00),
+ 11027662=HsHostingAssetRealEntity(DOMAIN_DNS_SETUP, dph-netzwerk.de|DNS, DNS-Setup für dph-netzwerk.de, DOMAIN_SETUP:dph-netzwerk.de, MANAGED_WEBSPACE:dph00),
+ 12004531=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, l-u-g.org|HTTP, HTTP-Setup für l-u-g.org, DOMAIN_SETUP:l-u-g.org, UNIX_USER:lug00, {"autoconfig": false, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": true, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": false, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "*" ]}),
+ 12004532=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, linuxfanboysngirls.de|HTTP, HTTP-Setup für linuxfanboysngirls.de, DOMAIN_SETUP:linuxfanboysngirls.de, UNIX_USER:lug00-wla.2, {"autoconfig": false, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": true, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": false, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "*" ]}),
+ 12004534=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, lug-mars.de|HTTP, HTTP-Setup für lug-mars.de, DOMAIN_SETUP:lug-mars.de, UNIX_USER:lug00-wla.2, {"autoconfig": false, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": true, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": true, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "www" ]}),
+ 12004581=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, 1981.ist-im-netz.de|HTTP, HTTP-Setup für 1981.ist-im-netz.de, DOMAIN_SETUP:1981.ist-im-netz.de, UNIX_USER:mim00, {"autoconfig": false, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": true, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": false, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "*" ]}),
+ 12004587=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, mellis.de|HTTP, HTTP-Setup für mellis.de, DOMAIN_SETUP:mellis.de, UNIX_USER:mim00, {"autoconfig": false, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": false, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": true, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "www", "michael", "test", "photos", "static", "input" ]}),
+ 12004589=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, ist-im-netz.de|HTTP, HTTP-Setup für ist-im-netz.de, DOMAIN_SETUP:ist-im-netz.de, UNIX_USER:mim00, {"autoconfig": false, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": false, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": true, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "*" ]}),
+ 12004600=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, waera.de|HTTP, HTTP-Setup für waera.de, DOMAIN_SETUP:waera.de, UNIX_USER:mim00, {"autoconfig": false, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": true, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": false, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "*" ]}),
+ 12004604=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, xn--wra-qla.de|HTTP, HTTP-Setup für wära.de, DOMAIN_SETUP:xn--wra-qla.de, UNIX_USER:mim00, {"autoconfig": false, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": true, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": false, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "*" ]}),
+ 12027662=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, dph-netzwerk.de|HTTP, HTTP-Setup für dph-netzwerk.de, DOMAIN_SETUP:dph-netzwerk.de, UNIX_USER:dph00-dph, {"autoconfig": true, "cgi": true, "fastcgi": true, "fcgi-php-bin": "/usr/lib/cgi-bin/php", "greylisting": true, "htdocsfallback": true, "includes": true, "indexes": true, "letsencrypt": true, "multiviews": true, "passenger": true, "passenger-errorpage": false, "passenger-nodejs": "/usr/bin/node", "passenger-python": "/usr/bin/python3", "passenger-ruby": "/usr/bin/ruby", "subdomains": [ "*" ]}),
+ 13004531=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, l-u-g.org|MBOX, E-Mail-Empfang-Setup für l-u-g.org, DOMAIN_SETUP:l-u-g.org, MANAGED_WEBSPACE:lug00),
+ 13004532=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, linuxfanboysngirls.de|MBOX, E-Mail-Empfang-Setup für linuxfanboysngirls.de, DOMAIN_SETUP:linuxfanboysngirls.de, MANAGED_WEBSPACE:lug00),
+ 13004534=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, lug-mars.de|MBOX, E-Mail-Empfang-Setup für lug-mars.de, DOMAIN_SETUP:lug-mars.de, MANAGED_WEBSPACE:lug00),
+ 13004581=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, 1981.ist-im-netz.de|MBOX, E-Mail-Empfang-Setup für 1981.ist-im-netz.de, DOMAIN_SETUP:1981.ist-im-netz.de, MANAGED_WEBSPACE:mim00),
+ 13004587=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, mellis.de|MBOX, E-Mail-Empfang-Setup für mellis.de, DOMAIN_SETUP:mellis.de, MANAGED_WEBSPACE:mim00),
+ 13004589=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, ist-im-netz.de|MBOX, E-Mail-Empfang-Setup für ist-im-netz.de, DOMAIN_SETUP:ist-im-netz.de, MANAGED_WEBSPACE:mim00),
+ 13004600=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, waera.de|MBOX, E-Mail-Empfang-Setup für waera.de, DOMAIN_SETUP:waera.de, MANAGED_WEBSPACE:mim00),
+ 13004604=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, xn--wra-qla.de|MBOX, E-Mail-Empfang-Setup für wära.de, DOMAIN_SETUP:xn--wra-qla.de, MANAGED_WEBSPACE:mim00),
+ 13027662=HsHostingAssetRealEntity(DOMAIN_MBOX_SETUP, dph-netzwerk.de|MBOX, E-Mail-Empfang-Setup für dph-netzwerk.de, DOMAIN_SETUP:dph-netzwerk.de, MANAGED_WEBSPACE:dph00),
+ 14004531=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, l-u-g.org|SMTP, E-Mail-Versand-Setup für l-u-g.org, DOMAIN_SETUP:l-u-g.org, MANAGED_WEBSPACE:lug00),
+ 14004532=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, linuxfanboysngirls.de|SMTP, E-Mail-Versand-Setup für linuxfanboysngirls.de, DOMAIN_SETUP:linuxfanboysngirls.de, MANAGED_WEBSPACE:lug00),
+ 14004534=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, lug-mars.de|SMTP, E-Mail-Versand-Setup für lug-mars.de, DOMAIN_SETUP:lug-mars.de, MANAGED_WEBSPACE:lug00),
+ 14004581=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, 1981.ist-im-netz.de|SMTP, E-Mail-Versand-Setup für 1981.ist-im-netz.de, DOMAIN_SETUP:1981.ist-im-netz.de, MANAGED_WEBSPACE:mim00),
+ 14004587=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, mellis.de|SMTP, E-Mail-Versand-Setup für mellis.de, DOMAIN_SETUP:mellis.de, MANAGED_WEBSPACE:mim00),
+ 14004589=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, ist-im-netz.de|SMTP, E-Mail-Versand-Setup für ist-im-netz.de, DOMAIN_SETUP:ist-im-netz.de, MANAGED_WEBSPACE:mim00),
+ 14004600=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, waera.de|SMTP, E-Mail-Versand-Setup für waera.de, DOMAIN_SETUP:waera.de, MANAGED_WEBSPACE:mim00),
+ 14004604=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, xn--wra-qla.de|SMTP, E-Mail-Versand-Setup für wära.de, DOMAIN_SETUP:xn--wra-qla.de, MANAGED_WEBSPACE:mim00),
+ 14027662=HsHostingAssetRealEntity(DOMAIN_SMTP_SETUP, dph-netzwerk.de|SMTP, E-Mail-Versand-Setup für dph-netzwerk.de, DOMAIN_SETUP:dph-netzwerk.de, MANAGED_WEBSPACE:dph00)
+ }
+ """);
+ }
+
// --------------------------------------------------------------------------------------------
@Test
@@ -471,7 +580,11 @@ public class ImportHostingAssets extends ImportOfficeData {
@Order(18999)
@ContinueOnFailure
void logValidationErrors() {
- this.logErrors();
+ if (isImportingControlledTestData()) {
+ expectError("zonedata dom_owner of mellis.de is old00 but expected to be mim00");
+ expectError("\nexpected: \"vm1068\"\n but was: \"vm1093\"");
+ }
+ this.assertNoErrors();
}
// --------------------------------------------------------------------------------------------
@@ -576,6 +689,46 @@ public class ImportHostingAssets extends ImportOfficeData {
persistHostingAssetsOfType(PGSQL_DATABASE, MARIADB_DATABASE);
}
+ @Test
+ @Order(19300)
+ @Commit
+ void persistDomainSetups() {
+ System.out.println("PERSISTING domain setups to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
+ persistHostingAssetsOfType(DOMAIN_SETUP);
+ }
+
+ @Test
+ @Order(19301)
+ @Commit
+ void persistDomainDnsSetups() {
+ System.out.println("PERSISTING domain DNS setups to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
+ persistHostingAssetsOfType(DOMAIN_DNS_SETUP);
+ }
+
+ @Test
+ @Order(19302)
+ @Commit
+ void persistDomainHttpSetups() {
+ System.out.println("PERSISTING domain HTTP setups to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
+ persistHostingAssetsOfType(DOMAIN_HTTP_SETUP);
+ }
+
+ @Test
+ @Order(19303)
+ @Commit
+ void persistDomainMboxSetups() {
+ System.out.println("PERSISTING domain MBOX setups to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
+ persistHostingAssetsOfType(DOMAIN_MBOX_SETUP);
+ }
+
+ @Test
+ @Order(19304)
+ @Commit
+ void persistDomainSmtpSetups() {
+ System.out.println("PERSISTING domain SMTP setups to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
+ persistHostingAssetsOfType(DOMAIN_SMTP_SETUP);
+ }
+
@Test
@Order(19900)
void verifyPersistedUnixUsersWithUserId() {
@@ -596,7 +749,7 @@ public class ImportHostingAssets extends ImportOfficeData {
4100824=HsHostingAssetRealEntity(UNIX_USER, hsh00, Hostsharing Paket, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 10000}),
4167846=HsHostingAssetRealEntity(UNIX_USER, hsh00-dph, hsh00-uph, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/false", "userid": 110568}),
4169546=HsHostingAssetRealEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 110593}),
- 4169596=HsHostingAssetRealEntity(UNIX_USER, dph00-uph, Domain admin, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 110594})
+ 4169596=HsHostingAssetRealEntity(UNIX_USER, dph00-dph, Domain admin, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 110594})
}
""");
}
@@ -604,37 +757,26 @@ public class ImportHostingAssets extends ImportOfficeData {
@Test
@Order(19910)
void verifyBookingItemsAreActuallyPersisted() {
- final var biCount = (Integer) em.createNativeQuery("SELECT count(*) FROM hs_booking_item", Integer.class).getSingleResult();
+ final var biCount = (Integer) em.createNativeQuery("select count(*) from hs_booking_item", Integer.class)
+ .getSingleResult();
assertThat(biCount).isGreaterThan(isImportingControlledTestData() ? 5 : 500);
}
@Test
@Order(19920)
void verifyHostingAssetsAreActuallyPersisted() {
- final var haCount = (Integer) em.createNativeQuery("SELECT count(*) FROM hs_hosting_asset", Integer.class).getSingleResult();
- assertThat(haCount).isGreaterThan(isImportingControlledTestData() ? 30 : 10000);
+ final var haCount = (Integer) em.createNativeQuery("select count(*) from hs_hosting_asset", Integer.class)
+ .getSingleResult();
+ assertThat(haCount).isGreaterThan(isImportingControlledTestData() ? 40 : 15000);
}
// ============================================================================================
@Test
- @Order(99999)
- void logErrors() {
- if (isImportingControlledTestData()) {
- super.expectErrors("""
- validation failed for id:5002452( HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-empty, mim00-empty, MANAGED_WEBSPACE:mim00, {
- "target": "[]"
- }
- )): ['EMAIL_ALIAS:mim00-empty.config.target' length is expected to be at min 1 but length of [[]] is 0]""",
- """
- validation failed for id:5002453( HsHostingAssetRealEntity(EMAIL_ALIAS, mim00-0_entries, mim00-0_entries, MANAGED_WEBSPACE:mim00, {
- "target": "[]"
- }
- )): ['EMAIL_ALIAS:mim00-0_entries.config.target' length is expected to be at min 1 but length of [[]] is 0]"""
- );
- } else {
- super.logErrors();
- }
+ @Order(19999)
+ void logErrorsAfterPersistingHostingAssets() {
+ errors.addAll(zonefileErrors);
+ assertNoErrors();
}
private void persistRecursively(final Integer key, final HsBookingItemEntity bi) {
@@ -648,20 +790,26 @@ public class ImportHostingAssets extends ImportOfficeData {
private void persistHostingAssetsOfType(final HsHostingAssetType... hsHostingAssetTypes) {
final var hsHostingAssetTypeSet = stream(hsHostingAssetTypes).collect(toSet());
- jpaAttempt.transacted(() -> {
- hostingAssets.forEach((key, ha) -> {
- context(rbacSuperuser);
- if (hsHostingAssetTypeSet.contains(ha.getType())) {
- new HostingAssetEntitySaveProcessor(em, ha)
- .preprocessEntity()
- .validateEntityIgnoring("'EMAIL_ALIAS:.*\\.config\\.target' .*")
- .prepareForSave()
- .saveUsing(entity -> persist(key, entity))
- .validateContext();
- }
+
+ if (hsHostingAssetTypeSet.contains(DOMAIN_DNS_SETUP)) {
+ HsDomainDnsSetupHostingAssetValidator.addZonefileErrorsTo(zonefileErrors);
+ }
+
+ jpaAttempt.transacted(() ->
+ hostingAssets.forEach((key, ha) -> {
+ if (hsHostingAssetTypeSet.contains(ha.getType())) {
+ context(rbacSuperuser); // if put only outside the loop, it seems to get lost after a while, no idea why
+ logError(() ->
+ new HostingAssetEntitySaveProcessor(em, ha)
+ .preprocessEntity()
+ .validateEntityIgnoring("'EMAIL_ALIAS:.*\\.config\\.target' .*")
+ .prepareForSave()
+ .saveUsing(entity -> persist(key, entity))
+ .validateContext()
+ );
}
- );
- }).assertSuccessful();
+ })
+ ).assertSuccessful();
}
private void importIpNumbers(final String[] header, final List records) {
@@ -894,12 +1042,14 @@ public class ImportHostingAssets extends ImportOfficeData {
// TODO.spec: crop SSD+HDD limits if > booked
if (unixUserAsset.getDirectValue("SSD hard quota", Integer.class, 0)
- > 1024*unixUserAsset.getContextValue("SSD", Integer.class, 0)) {
- unixUserAsset.getConfig().put("SSD hard quota", unixUserAsset.getContextValue("SSD", Integer.class, 0)*1024);
+ > 1024 * unixUserAsset.getContextValue("SSD", Integer.class, 0)) {
+ unixUserAsset.getConfig()
+ .put("SSD hard quota", unixUserAsset.getContextValue("SSD", Integer.class, 0) * 1024);
}
if (unixUserAsset.getDirectValue("HDD hard quota", Integer.class, 0)
- > 1024*unixUserAsset.getContextValue("HDD", Integer.class, 0)) {
- unixUserAsset.getConfig().put("HDD hard quota", unixUserAsset.getContextValue("HDD", Integer.class, 0)*1024);
+ > 1024 * unixUserAsset.getContextValue("HDD", Integer.class, 0)) {
+ unixUserAsset.getConfig()
+ .put("HDD hard quota", unixUserAsset.getContextValue("HDD", Integer.class, 0) * 1024);
}
// TODO.spec: does `softlimit records) {
+ final var httpDomainSetupValidator = HostingAssetEntityValidatorRegistry.forType(DOMAIN_HTTP_SETUP);
+
+ final var columns = new Columns(header);
+ records.stream()
+ .map(this::trimAll)
+ .map(row -> new Record(columns, row))
+ .forEach(rec -> {
+ final var domain_id = rec.getInteger("domain_id");
+ final var domain_name = rec.getString("domain_name");
+ // final var domain_since = rec.getString("domain_since");
+ // final var domain_dns_master = rec.getString("domain_dns_master");
+ final var owner_id = rec.getInteger("domain_owner");
+ final var domainoptions = rec.getString("domainoptions");
+
+ // Domain Setup
+ final var domainSetupAsset = HsHostingAssetRealEntity.builder()
+ .type(DOMAIN_SETUP)
+ // .parentAsset(parentDomainSetupAsset) are set once we've collected all of them
+ .identifier(domain_name)
+ .caption(IDN.toUnicode(domain_name))
+ .config(ofEntries(
+ // nothing here
+ ))
+ .build();
+ domainSetupsByName.put(domain_name, domainSetupAsset);
+ hostingAssets.put(DOMAIN_SETUP_OFFSET + domain_id, domainSetupAsset);
+ domainSetupAsset.setSubHostingAssets(new ArrayList<>());
+
+ // Domain DNS Setup
+ final var ownerAsset = hostingAssets.get(UNIXUSER_ID_OFFSET + owner_id);
+ final var webspaceAsset = ownerAsset.getParentAsset();
+ assertThat(webspaceAsset.getType()).isEqualTo(MANAGED_WEBSPACE);
+ final var domainDnsSetupAsset = HsHostingAssetRealEntity.builder()
+ .type(DOMAIN_DNS_SETUP)
+ .parentAsset(domainSetupAsset)
+ .assignedToAsset(webspaceAsset)
+ .identifier(domain_name + "|DNS")
+ .caption("DNS-Setup für " + IDN.toUnicode(domain_name))
+ .config(new HashMap<>()) // is read from separate files
+ .build();
+ hostingAssets.put(DOMAIN_DNS_SETUP_OFFSET + domain_id, domainDnsSetupAsset);
+ domainSetupAsset.getSubHostingAssets().add(domainDnsSetupAsset);
+
+ // Domain HTTP Setup
+ final var options = stream(domainoptions.split(",")).collect(toSet());
+ final var domainHttpSetupAsset = HsHostingAssetRealEntity.builder()
+ .type(DOMAIN_HTTP_SETUP)
+ .parentAsset(domainSetupAsset)
+ .assignedToAsset(ownerAsset)
+ .identifier(domain_name + "|HTTP")
+ .caption("HTTP-Setup für " + IDN.toUnicode(domain_name))
+ .config(ofEntries(
+ entry("htdocsfallback", options.contains("htdocsfallback")),
+ entry("indexes", options.contains("indexes")),
+ entry("cgi", options.contains("cgi")),
+ entry("passenger", options.contains("passenger")),
+ entry("passenger-errorpage", options.contains("passenger-errorpage")),
+ entry("fastcgi", options.contains("fastcgi")),
+ entry("autoconfig", options.contains("autoconfig")),
+ entry("greylisting", options.contains("greylisting")),
+ entry("includes", options.contains("includes")),
+ entry("letsencrypt", options.contains("letsencrypt")),
+ entry("multiviews", options.contains("multiviews")),
+ entry("subdomains", withDefault(rec.getString("valid_subdomain_names"), "*")
+ .split(",")),
+ entry("fcgi-php-bin", withDefault(
+ rec.getString("fcgi_php_bin"),
+ httpDomainSetupValidator.getProperty("fcgi-php-bin").defaultValue())),
+ entry("passenger-nodejs", withDefault(
+ rec.getString("passenger_nodejs"),
+ httpDomainSetupValidator.getProperty("passenger-nodejs").defaultValue())),
+ entry("passenger-python", withDefault(
+ rec.getString("passenger_python"),
+ httpDomainSetupValidator.getProperty("passenger-python").defaultValue())),
+ entry("passenger-ruby", withDefault(
+ rec.getString("passenger_ruby"),
+ httpDomainSetupValidator.getProperty("passenger-ruby").defaultValue()))
+ ))
+ .build();
+ hostingAssets.put(DOMAIN_HTTP_SETUP_OFFSET + domain_id, domainHttpSetupAsset);
+ domainSetupAsset.getSubHostingAssets().add(domainHttpSetupAsset);
+
+ // Domain MBOX Setup
+ final var domainMboxSetupAsset = HsHostingAssetRealEntity.builder()
+ .type(DOMAIN_MBOX_SETUP)
+ .parentAsset(domainSetupAsset)
+ .assignedToAsset(webspaceAsset)
+ .identifier(domain_name + "|MBOX")
+ .caption("E-Mail-Empfang-Setup für " + IDN.toUnicode(domain_name))
+ .config(ofEntries(
+ // no properties available
+ ))
+ .build();
+ hostingAssets.put(DOMAIN_MBOX_SETUP_OFFSET + domain_id, domainMboxSetupAsset);
+ domainSetupAsset.getSubHostingAssets().add(domainMboxSetupAsset);
+
+ // Domain SMTP Setup
+ final var domainSmtpSetupAsset = HsHostingAssetRealEntity.builder()
+ .type(DOMAIN_SMTP_SETUP)
+ .parentAsset(domainSetupAsset)
+ .assignedToAsset(webspaceAsset)
+ .identifier(domain_name + "|SMTP")
+ .caption("E-Mail-Versand-Setup für " + IDN.toUnicode(domain_name))
+ .config(ofEntries(
+ // no properties available
+ ))
+ .build();
+ hostingAssets.put(DOMAIN_SMTP_SETUP_OFFSET + domain_id, domainSmtpSetupAsset);
+ domainSetupAsset.getSubHostingAssets().add(domainSmtpSetupAsset);
+ });
+
+ domainSetupsByName.values().forEach(domainSetup -> {
+ final var parentDomainName = domainSetup.getIdentifier().split("\\.", 2)[1];
+ final var parentDomainSetup = domainSetupsByName.get(parentDomainName);
+ if (parentDomainSetup != null) {
+ domainSetup.setParentAsset(parentDomainSetup);
+ }
+ });
+ }
+
+ private String withDefault(final String givenValue, final Object defaultValue) {
+ if (defaultValue instanceof String defaultStringValue) {
+ return givenValue != null && !givenValue.isBlank() ? givenValue : defaultStringValue;
+ }
+ throw new RuntimeException(
+ "property default value expected to be of type string, but is of type " + defaultValue.getClass()
+ .getSimpleName());
+ }
+
+ private void importZonefiles(final String vmName, final String zonenfilesJson) {
+ if (zonenfilesJson == null || zonenfilesJson.isEmpty() || zonenfilesJson.isBlank()) {
+ return;
+ }
+
+ try {
+ //noinspection unchecked
+ final Map> zoneData = jsonMapper.readValue(zonenfilesJson, Map.class);
+ importZonenfile(vmName, zoneData);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("cannot read zonefile JSON: '" + zonenfilesJson + "'", e);
+ }
+ }
+
+ private void importZonenfile(final String vmName, final Map> zoneDataForVM) {
+ zoneDataForVM.forEach((domainName, zoneData) -> {
+ final var domainAsset = domainSetupsByName.get(domainName);
+ if (domainAsset != null) {
+ final var domainDnsSetupAsset = domainAsset.getSubHostingAssets().stream()
+ .filter(subAsset -> subAsset.getType() == DOMAIN_DNS_SETUP)
+ .findAny().orElse(null);
+ assertThat(domainDnsSetupAsset).as(domainAsset.getIdentifier() + " has no DOMAIN_DNS_SETUP").isNotNull();
+
+ final var domUser = domainAsset.getSubHostingAssets().stream()
+ .filter(ha -> ha.getType() == DOMAIN_HTTP_SETUP)
+ .findAny().orElseThrow()
+ .getAssignedToAsset();
+ final var domOwner = zoneData.remove("DOM_OWNER");
+ final var expectedDomOwner = domUser.getIdentifier();
+ if (domOwner.equals(expectedDomOwner)) {
+ logError(() -> assertThat(vmName).isEqualTo(domUser.getParentAsset().getParentAsset().getIdentifier()));
+
+ //noinspection unchecked
+ zoneData.put("user-RR", ((ArrayList>) zoneData.get("user-RR")).stream()
+ .map(userRR -> userRR.stream().map(Object::toString).collect(Collectors.joining(" ")))
+ .toArray(String[]::new)
+ );
+ domainDnsSetupAsset.getConfig().putAll(zoneData);
+ } else {
+ logError("zonedata dom_owner of " + domainAsset.getIdentifier() + " is " + domOwner + " but expected to be "
+ + expectedDomOwner);
+ }
+ }
+ });
+ }
+
// ============================================================================================
V returning(
@@ -1084,7 +1414,7 @@ public class ImportHostingAssets extends ImportOfficeData {
private String firstOfEachType(
final int maxCount,
final HsHostingAssetType... types) {
- return toFormattedString(stream(types)
+ return toJsonFormattedString(stream(types)
.flatMap(t ->
hostingAssets.entrySet().stream()
.filter(hae -> hae.getValue().getType() == t)
@@ -1100,7 +1430,7 @@ public class ImportHostingAssets extends ImportOfficeData {
private String firstOfEachType(
final int maxCount,
final HsBookingItemType... types) {
- return toFormattedString(stream(types)
+ return toJsonFormattedString(stream(types)
.flatMap(t ->
bookingItems.entrySet().stream()
.filter(bie -> bie.getValue().getType() == t)
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java
index 4e3e9e01..5bdacaab 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java
@@ -105,6 +105,7 @@ public class ImportOfficeData extends CsvDataImport {
// at least as the number of lines in business_partners.csv from test-data, but less than real data partner count
public static final int MAX_NUMBER_OF_TEST_DATA_PARTNERS = 100;
+ public static final int DELIBERATELY_BROKEN_BUSINESS_PARTNER_ID = 199;
static int relationId = 2000000;
@@ -151,7 +152,7 @@ public class ImportOfficeData extends CsvDataImport {
assumeThatWeAreImportingControlledTestData();
// no contacts yet => mostly null values
- assertThat(toFormattedString(partners)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(partners)).isEqualToIgnoringWhitespace("""
{
100=partner(P-10003: null null, null),
120=partner(P-10020: null null, null),
@@ -164,8 +165,8 @@ public class ImportOfficeData extends CsvDataImport {
542=partner(P-11019: null null, null)
}
""");
- assertThat(toFormattedString(contacts)).isEqualTo("{}");
- assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(contacts)).isEqualTo("{}");
+ assertThat(toJsonFormattedString(debitors)).isEqualToIgnoringWhitespace("""
{
100=debitor(D-1000300: rel(anchor='null null, null', type='DEBITOR'), mim),
120=debitor(D-1002000: rel(anchor='null null, null', type='DEBITOR'), xyz),
@@ -178,7 +179,7 @@ public class ImportOfficeData extends CsvDataImport {
542=debitor(D-1101900: rel(anchor='null null, null', type='DEBITOR'), dph)
}
""");
- assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(memberships)).isEqualToIgnoringWhitespace("""
{
100=Membership(M-1000300, P-10003, [2000-12-06,), ACTIVE),
120=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
@@ -206,7 +207,7 @@ public class ImportOfficeData extends CsvDataImport {
void verifyContacts() {
assumeThatWeAreImportingControlledTestData();
- assertThat(toFormattedString(partners)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(partners)).isEqualToIgnoringWhitespace("""
{
100=partner(P-10003: ?? Michael Mellis, Herr Michael Mellis , Michael Mellis),
120=partner(P-10020: LP JM GmbH, Herr Philip Meyer-Contract , JM GmbH),
@@ -219,7 +220,7 @@ public class ImportOfficeData extends CsvDataImport {
542=partner(P-11019: ?? Das Perfekte Haus, Herr Richard Wiese , Das Perfekte Haus)
}
""");
- assertThat(toFormattedString(contacts)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(contacts)).isEqualToIgnoringWhitespace("""
{
100=contact(caption='Herr Michael Mellis , Michael Mellis', emailAddresses='{ "main": "michael@Mellis.example.org"}'),
1200=contact(caption='JM e.K.', emailAddresses='{ "main": "jm-ex-partner@example.org"}'),
@@ -241,7 +242,7 @@ public class ImportOfficeData extends CsvDataImport {
90698=contact(caption='Jan Henning ', emailAddresses='{ "main": "mail@jan-henning.example.org"}')
}
""");
- assertThat(toFormattedString(persons)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(persons)).isEqualToIgnoringWhitespace("""
{
100=person(personType='??', tradeName='Michael Mellis', familyName='Mellis', givenName='Michael'),
1200=person(personType='LP', tradeName='JM e.K.'),
@@ -263,7 +264,7 @@ public class ImportOfficeData extends CsvDataImport {
90698=person(personType='NP', familyName='Henning', givenName='Jan')
}
""");
- assertThat(toFormattedString(debitors)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(debitors)).isEqualToIgnoringWhitespace("""
{
100=debitor(D-1000300: rel(anchor='?? Michael Mellis', type='DEBITOR', holder='?? Michael Mellis'), mim),
120=debitor(D-1002000: rel(anchor='LP JM GmbH', type='DEBITOR', holder='LP JM GmbH'), xyz),
@@ -276,7 +277,7 @@ public class ImportOfficeData extends CsvDataImport {
542=debitor(D-1101900: rel(anchor='?? Das Perfekte Haus', type='DEBITOR', holder='?? Das Perfekte Haus'), dph)
}
""");
- assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(memberships)).isEqualToIgnoringWhitespace("""
{
100=Membership(M-1000300, P-10003, [2000-12-06,), ACTIVE),
120=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
@@ -286,7 +287,7 @@ public class ImportOfficeData extends CsvDataImport {
542=Membership(M-1101900, P-11019, [2021-05-25,), ACTIVE)
}
""");
- assertThat(toFormattedString(relations)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(relations)).isEqualToIgnoringWhitespace("""
{
2000000=rel(anchor='LP Hostsharing e.G.', type='PARTNER', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
2000001=rel(anchor='?? Michael Mellis', type='DEBITOR', holder='?? Michael Mellis', contact='Herr Michael Mellis , Michael Mellis'),
@@ -373,7 +374,7 @@ public class ImportOfficeData extends CsvDataImport {
void verifySepaMandates() {
assumeThatWeAreImportingControlledTestData();
- assertThat(toFormattedString(bankAccounts)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(bankAccounts)).isEqualToIgnoringWhitespace("""
{
132=bankAccount(DE37500105177419788228: holder='Michael Mellis', bic='GENODEF1HH2'),
234234=bankAccount(DE37500105177419788228: holder='Michael Mellis', bic='INGDDEFFXXX'),
@@ -384,7 +385,7 @@ public class ImportOfficeData extends CsvDataImport {
387=bankAccount(DE89370400440532013000: holder='Richard Wiese Das Perfekte Haus', bic='COBADEFFXXX')
}
""");
- assertThat(toFormattedString(sepaMandates)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(sepaMandates)).isEqualToIgnoringWhitespace("""
{
132=SEPA-Mandate(DE37500105177419788228, HS-10003-20140801, 2013-12-01, [2013-12-01,)),
234234=SEPA-Mandate(DE37500105177419788228, MH12345, 2004-06-12, [2004-06-15,)),
@@ -413,7 +414,7 @@ public class ImportOfficeData extends CsvDataImport {
void verifyCoopShares() {
assumeThatWeAreImportingControlledTestData();
- assertThat(toFormattedString(coopShares)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(coopShares)).isEqualToIgnoringWhitespace("""
{
241=CoopShareTransaction(M-1000300: 2011-12-05, SUBSCRIPTION, 16, 1000300),
279=CoopShareTransaction(M-1015200: 2013-10-21, SUBSCRIPTION, 1, 1015200),
@@ -446,7 +447,7 @@ public class ImportOfficeData extends CsvDataImport {
void verifyCoopAssets() {
assumeThatWeAreImportingControlledTestData();
- assertThat(toFormattedString(coopAssets)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(coopAssets)).isEqualToIgnoringWhitespace("""
{
1093=CoopAssetsTransaction(M-1000300: 2023-10-05, DEPOSIT, 3072, 1000300, Kapitalerhoehung - Ueberweisung),
1094=CoopAssetsTransaction(M-1000300: 2023-10-06, DEPOSIT, 3072, 1000300, Kapitalerhoehung - Ueberweisung),
@@ -475,7 +476,7 @@ public class ImportOfficeData extends CsvDataImport {
void verifyMemberships() {
assumeThatWeAreImportingControlledTestData();
- assertThat(toFormattedString(memberships)).isEqualToIgnoringWhitespace("""
+ assertThat(toJsonFormattedString(memberships)).isEqualToIgnoringWhitespace("""
{
100=Membership(M-1000300, P-10003, [2000-12-06,), ACTIVE),
120=Membership(M-1002000, P-10020, [2000-12-06,2016-01-01), UNKNOWN),
@@ -494,11 +495,15 @@ public class ImportOfficeData extends CsvDataImport {
partners.forEach((id, p) -> {
final var partnerRel = p.getPartnerRel();
assertThat(partnerRel).describedAs("partner " + id + " without partnerRel").isNotNull();
- if ( id != 199 ) {
- logError( () -> assertThat(partnerRel.getContact()).describedAs("partner " + id + " without partnerRel.contact").isNotNull());
- logError( () -> assertThat(partnerRel.getContact().getCaption()).describedAs("partner " + id + " without valid partnerRel.contact").isNotNull());
- logError( () -> assertThat(partnerRel.getHolder()).describedAs("partner " + id + " without partnerRel.relHolder").isNotNull());
- logError( () -> assertThat(partnerRel.getHolder().getPersonType()).describedAs("partner " + id + " without valid partnerRel.relHolder").isNotNull());
+ if (id != DELIBERATELY_BROKEN_BUSINESS_PARTNER_ID) {
+ logError( () -> {
+ assertThat(partnerRel.getContact()).describedAs("partner " + id + " without partnerRel.contact").isNotNull();
+ assertThat(partnerRel.getContact().getCaption()).describedAs("partner " + id + " without valid partnerRel.contact").isNotNull();
+ });
+ logError( () -> {
+ assertThat(partnerRel.getHolder()).describedAs("partner " + id + " without partnerRel.relHolder").isNotNull();
+ assertThat(partnerRel.getHolder().getPersonType()).describedAs("partner " + id + " without valid partnerRel.relHolder").isNotNull();
+ });
}
});
}
@@ -604,6 +609,13 @@ public class ImportOfficeData extends CsvDataImport {
@Test
@Order(9000)
+ @ContinueOnFailure
+ void logCollectedErrorsBeforePersist() {
+ assertNoErrors();
+ }
+
+ @Test
+ @Order(9010)
void persistOfficeEntities() {
System.out.println("PERSISTING office data to database '" + jdbcUrl + "' as user '" + postgresAdminUser + "'");
@@ -716,6 +728,13 @@ public class ImportOfficeData extends CsvDataImport {
);
}
+ @Test
+ @Order(9999)
+ @ContinueOnFailure
+ void logCollectedErrors() {
+ this.assertNoErrors();
+ }
+
private void importBusinessPartners(final String[] header, final List records) {
final var columns = new Columns(header);
diff --git a/src/test/resources/migration/hosting/domain.csv b/src/test/resources/migration/hosting/domain.csv
new file mode 100644
index 00000000..3471bcfd
--- /dev/null
+++ b/src/test/resources/migration/hosting/domain.csv
@@ -0,0 +1,10 @@
+domain_id;domain_name;domain_since;domain_dns_master;domain_owner;valid_subdomain_names;passenger_python;passenger_nodejs;passenger_ruby;fcgi_php_bin;domainoptions
+4531;l-u-g.org;2013-09-10;dns.hostsharing.net;5803;*;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;greylisting,multiviews,indexes,htdocsfallback,includes,cgi,fastcgi,passenger
+4532;linuxfanboysngirls.de;2013-09-10;dns.hostsharing.net;5809;*;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;greylisting,multiviews,indexes,htdocsfallback,includes,cgi,fastcgi,passenger
+4534;lug-mars.de;2013-09-10;dns.hostsharing.net;5809;www;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;greylisting,letsencrypt,multiviews,indexes,htdocsfallback,includes,cgi,fastcgi,passenger
+4581;1981.ist-im-netz.de;2013-09-17;dns.hostsharing.net;5964;*;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;greylisting,multiviews,indexes,htdocsfallback,includes,cgi,fastcgi,passenger
+4587;mellis.de;2013-09-17;dns.hostsharing.net;5964;www,michael,test,photos,static,input;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;htdocsfallback,indexes,includes,letsencrypt,multiviews,cgi,fastcgi,passenger
+4589;ist-im-netz.de;2013-09-17;dns.hostsharing.net;5964;*;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;htdocsfallback,indexes,includes,letsencrypt,multiviews,cgi,fastcgi,passenger
+4600;waera.de;2013-09-17;dns.hostsharing.net;5964;*;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;greylisting,multiviews,indexes,htdocsfallback,includes,cgi,fastcgi,passenger
+4604;xn--wra-qla.de;2013-09-17;dns.hostsharing.net;5964;*;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;greylisting,multiviews,indexes,htdocsfallback,includes,cgi,fastcgi,passenger
+27662;dph-netzwerk.de;2021-06-02;h93.hostsharing.net;169596;*;/usr/bin/python3;/usr/bin/node;/usr/bin/ruby;/usr/lib/cgi-bin/php;htdocsfallback,indexes,autoconfig,greylisting,includes,letsencrypt,multiviews,cgi,fastcgi,passenger
diff --git a/src/test/resources/migration/hosting/emailalias.csv b/src/test/resources/migration/hosting/emailalias.csv
index 6b007ce3..b2421536 100644
--- a/src/test/resources/migration/hosting/emailalias.csv
+++ b/src/test/resources/migration/hosting/emailalias.csv
@@ -5,8 +5,6 @@ emailalias_id;pac_id;name;target
2431;1112;mim00-abruf;michael.mellis@hostsharing.net
2449;1112;mim00-hhfx;"mim00-hhfx,""|/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l"""
2451;1112;mim00-hhfx-l;:include:/home/pacs/mim00/etc/hhfx.list
-2452;1112;mim00-empty;
-2453;1112;mim00-0_entries;""
2454;1112;mim00-dev.null; /dev/null
2455;1112;mim00-1_with_space;" ""|/home/pacs/mim00/install/corpslistar/listar"""
2456;1112;mim00-1_with_single_quotes;'|/home/pacs/rir00/mailinglist/ecartis -r kybs06-intern'
diff --git a/src/test/resources/migration/hosting/unixuser.csv b/src/test/resources/migration/hosting/unixuser.csv
index 68538a04..7c75fcf5 100644
--- a/src/test/resources/migration/hosting/unixuser.csv
+++ b/src/test/resources/migration/hosting/unixuser.csv
@@ -15,5 +15,5 @@ unixuser_id;name;comment;shell;homedir;locked;packet_id;userid;quota_softlimit;q
167846;hsh00-dph;hsh00-uph;/bin/false;/home/pacs/hsh00/users/uph;0;630;110568;0;0;0;0
169546;dph00;Reinhard Wiese;/bin/bash;/home/pacs/dph00;0;19959;110593;0;0;0;0
-169596;dph00-uph;Domain admin;/bin/bash;/home/pacs/dph00/users/uph;0;19959;110594;0;0;0;0
+169596;dph00-dph;Domain admin;/bin/bash;/home/pacs/dph00/users/uph;0;19959;110594;0;0;0;0
diff --git a/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1068.json b/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1068.json
new file mode 100644
index 00000000..1b01b0aa
--- /dev/null
+++ b/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1068.json
@@ -0,0 +1,274 @@
+{
+ "1981.ist-im-netz.de": {
+ "DOM_OWNER": "mim00",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": []
+ },
+ "mellis.de": {
+ "DOM_OWNER": "mim00",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": true,
+ "auto-AUTOCONFIG-RR": true,
+ "auto-AUTODISCOVER-RR": true,
+ "auto-DKIM-RR": true,
+ "auto-MAILSERVICES-RR": true,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": true,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": true,
+ "user-RR": [
+ [
+ "dump.hoennig.de.",
+ 21600,
+ "IN",
+ "CNAME",
+ "mih12.hostsharing.net."
+ ],
+ [
+ "fotos.hoennig.de.",
+ 21600,
+ "IN",
+ "CNAME",
+ "mih12.hostsharing.net."
+ ],
+ [
+ "maven.hoennig.de.",
+ 21600,
+ "IN",
+ "NS",
+ "dns1.hostsharing.net."
+ ],
+ [
+ "key1._domainkey.mellis.de.",
+ 21600,
+ "IN",
+ "TXT",
+ "\"v=DKIM1; k=rsa; t=s; h=sha256; s=email; \" \"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzAIotiz04KGTF9ECNxEmnnl6eTHplxxYJpOWhx3YiLbQyt6D+sN5uMa/\" \"RMIJDr5BzqzHDQPTM6esLldtIu4OpHppdu3PG4BUB8aXfA0EQvt0wQ/VFGNP36x87nfqs2L8NxbgPwhVD5RqFgj6aheTt64PB+VRco3Nc2qLF4iGpM9UlQbp/W2IITXPbLd9Z/qPo4S6Yeghsq4eFSlcNqSGyO42d23EbAxiehJKBu2eTKX5Vj+n06h1zuXOHyC5IwIe515hmS/\" \"kybbyTTEe35Rmuh+1W9aBJb85d34Thi+knUJeysFleHe7mXG7k6zFiG5HjaP7CvDzzdWvCcaJhOIqXwIDAQAB\""
+ ]
+ ]
+ },
+ "ist-im-netz.de": {
+ "DOM_OWNER": "mim00",
+ "TTL": 14400,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": false,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": [
+ [
+ "1981.ist-im-netz.de.",
+ 14400,
+ "IN",
+ "NS",
+ "dns1.hostsharing.net."
+ ],
+ [
+ "1981.ist-im-netz.de.",
+ 14400,
+ "IN",
+ "NS",
+ "dns2.hostsharing.net."
+ ],
+ [
+ "1981.ist-im-netz.de.",
+ 14400,
+ "IN",
+ "NS",
+ "dns3.hostsharing.net."
+ ]
+ ]
+ },
+ "l-u-g.de": {
+ "DOM_OWNER": "lug00",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": []
+ },
+ "l-u-g.org": {
+ "DOM_OWNER": "lug00",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": []
+ },
+ "linuxfanboysngirls.de": {
+ "DOM_OWNER": "lug00-wla.2",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": []
+ },
+ "lug-mars.de": {
+ "DOM_OWNER": "lug00-wla.2",
+ "TTL": 14400,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": false,
+ "auto-NS-RR": true,
+ "auto-SOA": false,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": false,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": [
+ [
+ "lug-mars.de.",
+ 14400,
+ "IN",
+ "SOA",
+ "dns1.hostsharing.net. hostmaster.hostsharing.net. 1611590905 10800 3600 604800 3600"
+ ],
+ [
+ "lug-mars.de.",
+ 14400,
+ "IN",
+ "MX",
+ "10 mailin1.hostsharing.net."
+ ],
+ [
+ "lug-mars.de.",
+ 14400,
+ "IN",
+ "MX",
+ "20 mailin2.hostsharing.net."
+ ],
+ [
+ "lug-mars.de.",
+ 14400,
+ "IN",
+ "MX",
+ "30 mailin3.hostsharing.net."
+ ],
+ [
+ "bbb.lug-mars.de.",
+ 14400,
+ "IN",
+ "A",
+ "83.223.79.72"
+ ],
+ [
+ "ftp.lug-mars.de.",
+ 14400,
+ "IN",
+ "A",
+ "83.223.79.72"
+ ],
+ [
+ "www.lug-mars.de.",
+ 14400,
+ "IN",
+ "A",
+ "83.223.79.72"
+ ]
+ ]
+ },
+ "waera.de": {
+ "DOM_OWNER": "mim00",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": []
+ },
+ "xn--wra-qla.de": {
+ "DOM_OWNER": "mim00",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": []
+ }
+}
diff --git a/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1093.json b/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1093.json
new file mode 100644
index 00000000..73416ba2
--- /dev/null
+++ b/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1093.json
@@ -0,0 +1,89 @@
+{
+ "dph-netzwerk.de": {
+ "DOM_OWNER": "dph00-dph",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": true,
+ "auto-AUTOCONFIG-RR": true,
+ "auto-AUTODISCOVER-RR": true,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": true,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": true,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": [
+ [
+ "dph-netzwerk.de.",
+ 21600,
+ "IN",
+ "TXT",
+ "\"v=spf1 include:spf.hostsharing.net ?all\""
+ ],
+ [
+ "*.dph-netzwerk.de.",
+ 21600,
+ "IN",
+ "TXT",
+ "\"v=spf1 include:spf.hostsharing.net ?all\""
+ ]
+ ]
+ },
+ "mellis.de": {
+ "DOM_OWNER": "old00",
+ "TTL": 21600,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": true,
+ "auto-AUTOCONFIG-RR": true,
+ "auto-AUTODISCOVER-RR": true,
+ "auto-DKIM-RR": true,
+ "auto-MAILSERVICES-RR": true,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": true,
+ "auto-WILDCARD-MX-RR": true,
+ "auto-WILDCARD-SPF-RR": true,
+ "user-RR": [
+ [
+ "dump.mellis.de.",
+ 21600,
+ "IN",
+ "CNAME",
+ "mih12.hostsharing.net."
+ ],
+ [
+ "key1._domainkey.mellis.de.",
+ 21600,
+ "IN",
+ "TXT",
+ "\"v=DKIM1; k=rsa; t=s; h=sha256; s=email; \" \"p=OldFake+sN5uMa/\" \"OldFake/OldFake+OldFake/W2IITXPbLd9Z/OldFake+OldFake/\" \"OldFake+OldFake+OldFake\""
+ ]
+ ]
+ },
+ "ist-im-netz.de": {
+ "DOM_OWNER": "mim00",
+ "TTL": 700,
+ "auto-A-RR": true,
+ "auto-AAAA-RR": false,
+ "auto-AUTOCONFIG-RR": false,
+ "auto-AUTODISCOVER-RR": false,
+ "auto-DKIM-RR": false,
+ "auto-MAILSERVICES-RR": false,
+ "auto-MX-RR": true,
+ "auto-NS-RR": true,
+ "auto-SOA": true,
+ "auto-SPF-RR": false,
+ "auto-WILDCARD-A-RR": true,
+ "auto-WILDCARD-AAAA-RR": false,
+ "auto-WILDCARD-MX-RR": false,
+ "auto-WILDCARD-SPF-RR": false,
+ "user-RR": []
+ }
+}