From 6e5d51384bab1bfdee54126a6a90115ecd38523a Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Wed, 7 Aug 2024 17:17:35 +0200 Subject: [PATCH] generate almost complete Bind zonefile --- ...HsDomainDnsSetupHostingAssetValidator.java | 84 +++++++++++---- ...sDomainHttpSetupHostingAssetValidator.java | 4 +- .../hs/validation/HsEntityValidator.java | 4 + ...DnsSetupHostingAssetValidatorUnitTest.java | 102 ++++++++++++++---- .../hsadminng/hs/migration/CsvDataImport.java | 8 +- .../hs/migration/ImportHostingAssets.java | 96 ++++++++++------- .../hs/migration/ImportOfficeData.java | 2 +- .../resources/migration/hosting/unixuser.csv | 2 +- .../hosting/zonefiles/zonefiles-vm1068.json | 33 ++---- .../hosting/zonefiles/zonefiles-vm1093.json | 53 +++++++++ 10 files changed, 280 insertions(+), 108 deletions(-) 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 b283c99b..4fd1b2ac 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 @@ -18,18 +18,18 @@ import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringPrope 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 = "[([^;]+)|(\".*\")|(\\(.*\\))]\\s*"; + 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; FIXME + RR_REGEX_NAME + RR_REGEX_TTL + RR_REGEX_IN + RR_RECORD_TYPE + RR_RECORD_DATA + RR_COMMENT; static final String RR_REGEX_IN_TTL = - RR_REGEX_NAME + RR_REGEX_IN + RR_REGEX_TTL + RR_RECORD_TYPE + ".*"; // RR_RECORD_DATA + RR_COMMENT; FIXME + RR_REGEX_NAME + RR_REGEX_IN + RR_REGEX_TTL + RR_RECORD_TYPE + RR_RECORD_DATA + RR_COMMENT; public static final String IDENTIFIER_SUFFIX = "|DNS"; HsDomainDnsSetupHostingAssetValidator() { @@ -44,14 +44,13 @@ class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator 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() @@ -82,22 +81,30 @@ class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator if (namedCheckZone.execute(zonefileString) != 0) { // yes, named-checkzone writes error messages to stdout stream(namedCheckZone.getStdOut().split("\n")) - .map(line -> line.replaceAll(" stream-0x[0-9a-f:]+", "")) + .map(line -> line.replaceAll(" stream-0x[0-9a-f]+:", "line ")) + .map(line -> "[" + assetEntity.getIdentifier() + "] " + line) .forEach(result::add); } 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} {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} """ @@ -110,17 +117,52 @@ class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator 1H ; retry (>=1800) 1W ; expire 1H ; minimum - ) + ) """ - : "" + : "; no auto-SOA" ) - .replace("{auto-NS-RR}", """ - {domain}. IN NS dns1.hostsharing.net. - {domain}. IN NS dns2.hostsharing.net. - {domain}. IN NS dns3.hostsharing.net. - """) - .replace("{auto-A-RR}", "{domain}. IN A 83.223.95.160") // arbitrary IP-number - .replace("{auto-AAAA-RR}", "{domain}. IN AAAA 2a01:37:1000::53df:5fa0:0") // arbitrary IP-number + .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")); } 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 be522a63..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 @@ -14,7 +14,7 @@ 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/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 2f22ba16..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,13 +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", - "key1._domainkey.example.org. 21600 IN TXT \"v=DKIM1; k=rsa; t=s; h=sha256; s=email; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKzG+6ZiD7p60PFZ/qxmKNmP3AO3cIszXYyfvHn/MkyGx0vXhSolAheZtK6+g/h3m6McdPR6kHywcPuQRAPbcVh+SpPAorWe18VLdMcW4D6KxbMjQipRw1cZ4PjglGgcvsT42IAVQMFlEGl6KutmDkZebJNHlrFj38FcwD1wjL0wIDAQAB\"") + "_acme-challenge.PAULCHEN-VS.core.example.org. 60 IN CNAME _acme-challenge.core.example.org.acme-pki.de.") ) )); } @@ -67,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}}" ); } @@ -136,7 +149,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest { } @Test - void acceptsValidEntity() { + void acceptsValidEntityItself() { // given final var givenEntity = validEntityBuilder().build(); final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); @@ -148,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 @@ -167,37 +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); } @@ -212,23 +257,42 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest { // then assertThat(zonefile).isEqualTo(""" - $ORIGIN example.org. - $TTL 43200 - - + $TTL 21600 + + 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 - - @ 1814400 IN XXX example.org. root.example.org ( 1234 10800 900 604800 86400 ) + 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" + 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 - key1._domainkey.example.org. 21600 IN TXT "v=DKIM1; k=rsa; t=s; h=sha256; s=email; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKzG+6ZiD7p60PFZ/qxmKNmP3AO3cIszXYyfvHn/MkyGx0vXhSolAheZtK6+g/h3m6McdPR6kHywcPuQRAPbcVh+SpPAorWe18VLdMcW4D6KxbMjQipRw1cZ4PjglGgcvsT42IAVQMFlEGl6KutmDkZebJNHlrFj38FcwD1wjL0wIDAQAB" + _acme-challenge.PAULCHEN-VS.core.example.org. 60 IN CNAME _acme-challenge.core.example.org.acme-pki.de. """); } @@ -249,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/migration/CsvDataImport.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/CsvDataImport.java index 85533ae4..03593bc8 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/CsvDataImport.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/CsvDataImport.java @@ -310,11 +310,15 @@ public class CsvDataImport extends ContextBasedTest { try { assertion.run(); } catch (final AssertionError exc) { - errors.add(exc.toString()); + logError(exc.getMessage()); } } - void logErrors() { + public static void logError(final String error) { + errors.add(error); + } + + protected final void logErrors() { final var errorsToLog = new ArrayList<>(errors); errors.clear(); assertThat(errorsToLog).isEmpty(); 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 ea7b3f5a..b99e6654 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java @@ -12,6 +12,7 @@ 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.rbac.test.JpaAttempt; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.MethodOrderer; @@ -139,6 +140,8 @@ public class ImportHostingAssets extends ImportOfficeData { static Map dbUsersByEngineAndName = new WriteOnceMap<>(); static Map domainSetupsByName = new WriteOnceMap<>(); + final ObjectMapper jsonMapper = new ObjectMapper(); + @Test @Order(11010) void createBookingProjects() { @@ -329,7 +332,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, "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}) + 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}) } """); } @@ -469,13 +472,17 @@ public class ImportHostingAssets extends ImportOfficeData { @Order(16020) void importZonenfiles() { final var reflections = new Reflections(MIGRATION_DATA_PATH + "/hosting/zonefiles", new ResourcesScanner()); - final var zonefileFiles = reflections.getResources(Pattern.compile(".*\\.json")); + final var zonefileFiles = reflections.getResources(Pattern.compile(".*\\.json")).stream().sorted().toList(); zonefileFiles.forEach(zonenfileName -> { System.out.println("Processing zonenfile: " + zonenfileName); - importZonefiles(resourceAsString(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() { @@ -507,15 +514,15 @@ public class ImportHostingAssets extends ImportOfficeData { 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"}), - 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"}), - 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"}), - 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"}), - 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"}), - 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"}), - 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"}), - 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"}), - 12027662=HsHostingAssetRealEntity(DOMAIN_HTTP_SETUP, dph-netzwerk.de|HTTP, HTTP-Setup für dph-netzwerk.de, DOMAIN_SETUP:dph-netzwerk.de, UNIX_USER:dph00-uph, {"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"}), + 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), @@ -736,7 +743,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}) } """); } @@ -760,9 +767,9 @@ public class ImportHostingAssets extends ImportOfficeData { // ============================================================================================ @Test - @Order(99999) - void logErrors() { - super.logErrors(); + @Order(19999) + void logErrorsAfterPersistingHostingAssets() { + logErrors(); } private void persistRecursively(final Integer key, final HsBookingItemEntity bi) { @@ -1177,6 +1184,8 @@ public class ImportHostingAssets extends ImportOfficeData { } private void importDomains(final String[] header, final List records) { + final var httpDomainSetupValidator = HostingAssetEntityValidatorRegistry.forType(DOMAIN_HTTP_SETUP); + final var columns = new Columns(header); records.stream() .map(this::trimAll) @@ -1187,12 +1196,6 @@ public class ImportHostingAssets extends ImportOfficeData { // 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"); - // FIXME: missing properties - final var valid_subdomain_names = rec.getString("valid_subdomain_names"); - final var passenger_python = rec.getString("passenger_python"); - final var passenger_nodejs = rec.getString("passenger_nodejs"); - final var passenger_ruby = rec.getString("passenger_ruby"); - final var fcgi_php_bin = rec.getString("fcgi_php_bin"); final var domainoptions = rec.getString("domainoptions"); // Domain Setup @@ -1244,10 +1247,16 @@ public class ImportHostingAssets extends ImportOfficeData { entry("includes", options.contains("includes")), entry("letsencrypt", options.contains("letsencrypt")), entry("multiviews", options.contains("multiviews")), - entry("fcgi-php-bin", rec.getString("fcgi_php_bin")), - entry("passenger-nodejs", rec.getString("passenger_nodejs")), - entry("passenger-python", rec.getString("passenger_python")), - entry("passenger-ruby", rec.getString("passenger_ruby")) + 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); @@ -1291,39 +1300,54 @@ public class ImportHostingAssets extends ImportOfficeData { }); } - private void importZonefiles(final String zonenfilesJson) { + 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; } - final var objectMapper = new ObjectMapper(); try { //noinspection unchecked - final Map> zoneData = objectMapper.readValue(zonenfilesJson, Map.class); - importZonenfile(zoneData); + 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 Map> zoneDataForVM) { + private void importZonenfile( final String vmName, final Map> zoneDataForVM) { zoneDataForVM.forEach((domainName, zoneData) -> { - //noinspection unchecked 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); - logError(() -> { - assertThat(domainDnsSetupAsset).as(domainAsset.getIdentifier() + " has no DOMAIN_DNS_SETUP").isNotNull(); - zoneData.remove("DOM_OWNER"); // FIXME: doublecheck + 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); + } } }); } 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 42b0cfa0..b94320d6 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java @@ -611,7 +611,7 @@ public class ImportOfficeData extends CsvDataImport { @Order(9000) @ContinueOnFailure void logCollectedErrorsBeforePersist() { - this.logErrors(); + logErrors(); } @Test 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 index e64b0988..1b01b0aa 100644 --- a/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1068.json +++ b/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1068.json @@ -1,6 +1,6 @@ { "1981.ist-im-netz.de": { - "DOM_OWNER": "mih00", + "DOM_OWNER": "mim00", "TTL": 21600, "auto-A-RR": true, "auto-AAAA-RR": false, @@ -19,7 +19,7 @@ "user-RR": [] }, "mellis.de": { - "DOM_OWNER": "mih00", + "DOM_OWNER": "mim00", "TTL": 21600, "auto-A-RR": true, "auto-AAAA-RR": true, @@ -67,7 +67,7 @@ ] }, "ist-im-netz.de": { - "DOM_OWNER": "mih00", + "DOM_OWNER": "mim00", "TTL": 14400, "auto-A-RR": true, "auto-AAAA-RR": false, @@ -146,26 +146,7 @@ "user-RR": [] }, "linuxfanboysngirls.de": { - "DOM_OWNER": "lug00-marl", - "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-in.de": { - "DOM_OWNER": "lug00-in", + "DOM_OWNER": "lug00-wla.2", "TTL": 21600, "auto-A-RR": true, "auto-AAAA-RR": false, @@ -184,7 +165,7 @@ "user-RR": [] }, "lug-mars.de": { - "DOM_OWNER": "lug00-marl", + "DOM_OWNER": "lug00-wla.2", "TTL": 14400, "auto-A-RR": true, "auto-AAAA-RR": false, @@ -253,7 +234,7 @@ ] }, "waera.de": { - "DOM_OWNER": "mih00", + "DOM_OWNER": "mim00", "TTL": 21600, "auto-A-RR": true, "auto-AAAA-RR": false, @@ -272,7 +253,7 @@ "user-RR": [] }, "xn--wra-qla.de": { - "DOM_OWNER": "mih00", + "DOM_OWNER": "mim00", "TTL": 21600, "auto-A-RR": true, "auto-AAAA-RR": false, diff --git a/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1093.json b/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1093.json index 432857fc..73416ba2 100644 --- a/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1093.json +++ b/src/test/resources/migration/hosting/zonefiles/zonefiles-vm1093.json @@ -32,5 +32,58 @@ "\"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": [] } }