From 5046e9a2967d8694b31f5249fb501390dfadfe9d Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Thu, 8 Aug 2024 10:40:34 +0200 Subject: [PATCH] import-hosting-domain-assets (#84) Co-authored-by: Michael Hoennig Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/84 --- .run/ImportOfficeData.run.xml | 36 +- ...HsDomainDnsSetupHostingAssetValidator.java | 130 ++++- ...sDomainHttpSetupHostingAssetValidator.java | 6 +- .../HsDomainSetupHostingAssetValidator.java | 2 +- .../hs/validation/HsEntityValidator.java | 4 + .../hsadminng/mapper/PatchableMapWrapper.java | 28 +- .../hsadminng/system/SystemProcess.java | 5 + ...DnsSetupHostingAssetValidatorUnitTest.java | 109 +++- ...ttpSetupHostingAssetValidatorUnitTest.java | 13 +- ...ainSetupHostingAssetValidatorUnitTest.java | 2 +- ...ailAliasHostingAssetValidatorUnitTest.java | 21 + .../hsadminng/hs/migration/CsvDataImport.java | 142 ++--- .../hs/migration/ImportHostingAssets.java | 490 +++++++++++++++--- .../hs/migration/ImportOfficeData.java | 59 ++- .../resources/migration/hosting/domain.csv | 10 + .../migration/hosting/emailalias.csv | 2 - .../resources/migration/hosting/unixuser.csv | 2 +- .../hosting/zonefiles/zonefiles-vm1068.json | 274 ++++++++++ .../hosting/zonefiles/zonefiles-vm1093.json | 89 ++++ 19 files changed, 1174 insertions(+), 250 deletions(-) create mode 100644 src/test/resources/migration/hosting/domain.csv create mode 100644 src/test/resources/migration/hosting/zonefiles/zonefiles-vm1068.json create mode 100644 src/test/resources/migration/hosting/zonefiles/zonefiles-vm1093.json 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": [] + } +}