From 9ee9e1e74bd6165778e0efe11ea7b80e19e17036 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Mon, 29 Jul 2024 09:15:15 +0200 Subject: [PATCH] import unixusers --- .../HsUnixUserHostingAssetValidator.java | 10 +- .../hs/migration/ImportHostingAssets.java | 114 +++++++++++++++--- .../resources/migration/hosting/unixuser.csv | 19 +++ 3 files changed, 126 insertions(+), 17 deletions(-) create mode 100644 src/test/resources/migration/hosting/unixuser.csv diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java index 7bcbb028..5b879c46 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsUnixUserHostingAssetValidator.java @@ -7,6 +7,7 @@ import net.hostsharing.hsadminng.hs.validation.PropertiesProvider; import java.util.regex.Pattern; +import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty; import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty; import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty; import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty; @@ -21,6 +22,9 @@ class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator { HsHostingAssetType.UNIX_USER, AlarmContact.isOptional(), + booleanProperty("locked").withDefault(false), + integerProperty("userid").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeUserId), + integerProperty("SSD hard quota").unit("GB").maxFrom("SSD").optional(), integerProperty("SSD soft quota").unit("GB").maxFrom("SSD hard quota").optional(), integerProperty("HDD hard quota").unit("GB").maxFrom("HDD").optional(), @@ -31,7 +35,7 @@ class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator { stringProperty("homedir").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeHomedir), stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).undisclosed().writeOnly().optional(), passwordProperty("password").minLength(8).maxLength(40).hashedUsing(HashGenerator.Algorithm.LINUX_SHA512).writeOnly()); - // TODO.spec: public SSH keys? + // TODO.spec: public SSH keys? (only if hsadmin-ng is only accessible with 2FA) } @Override @@ -46,4 +50,8 @@ class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator { return "/home/pacs/" + webspaceName + "/users/" + entity.getIdentifier().substring(webspaceName.length()+DASH_LENGTH); } + + private static Integer computeUserId(PropertiesProvider propertiesProvider) { + return 0; // FIXME: from a specific numeric rage and unique per hive? + } } 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 cda4c482..3d9bf71a 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportHostingAssets.java @@ -29,12 +29,14 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import static java.util.Arrays.stream; +import static java.util.Map.entry; import static java.util.Optional.ofNullable; import static java.util.stream.Collectors.toMap; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV4_NUMBER; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE; +import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.UNIX_USER; import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assumptions.assumeThat; @@ -91,6 +93,7 @@ public class ImportHostingAssets extends ImportOfficeData { static final Integer IP_NUMBER_ID_OFFSET = 1000000; static final Integer HIVE_ID_OFFSET = 2000000; static final Integer PACKET_ID_OFFSET = 3000000; + static final Integer UNIXUSER_ID_OFFSET = 4000000; record Hive(int hive_id, String hive_name, int inet_addr_id, AtomicReference serverRef) {} @@ -261,6 +264,45 @@ public class ImportHostingAssets extends ImportOfficeData { """); } + @Test + @Order(14010) + void importUnixUsers() { + try (Reader reader = resourceReader(MIGRATION_DATA_PATH + "/hosting/unixuser.csv")) { + final var lines = readAllLines(reader); + importUnixUsers(justHeader(lines), withoutHeader(lines)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + @Order(14019) + void verifyUnixUsers() { + assumeThatWeAreImportingControlledTestData(); + + // no contacts yet => mostly null values + assertThat(firstOfEachType(15, UNIX_USER)).isEqualToIgnoringWhitespace(""" + { + 4005803=HsHostingAssetEntity(UNIX_USER, lug00, LUGs, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/lug00", "locked": false, "shell": "/bin/bash", "userid": 102090}), + 4005805=HsHostingAssetEntity(UNIX_USER, lug00-wla.1, Paul Klemm, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/lug00/users/deaf", "locked": false, "shell": "/bin/bash", "userid": 102091}), + 4005809=HsHostingAssetEntity(UNIX_USER, lug00-wla.2, Walter Müller, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/lug00/users/marl", "locked": false, "shell": "/bin/bash", "userid": 102093}), + 4005811=HsHostingAssetEntity(UNIX_USER, lug00-ola.a, LUG OLA - POP a, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/lug00/users/marl.a", "locked": false, "shell": "/usr/bin/passwd", "userid": 102094}), + 4005813=HsHostingAssetEntity(UNIX_USER, lug00-ola.b, LUG OLA - POP b, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/lug00/users/marl.b", "locked": false, "shell": "/usr/bin/passwd", "userid": 102095}), + 4005835=HsHostingAssetEntity(UNIX_USER, lug00-test, Test, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/lug00/users/test", "locked": false, "shell": "/usr/bin/passwd", "userid": 102106}), + 4005964=HsHostingAssetEntity(UNIX_USER, mim00, Michael Mellis, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/mim00", "locked": false, "shell": "/bin/bash", "userid": 102147}), + 4005966=HsHostingAssetEntity(UNIX_USER, mim00-1981, Jahrgangstreffen 1981, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 256, "SDD soft quota": 128, "homedir": "/home/pacs/mim00/users/1981", "locked": false, "shell": "/bin/bash", "userid": 102148}), + 4005990=HsHostingAssetEntity(UNIX_USER, mim00-mail, Mailbox, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/mim00/users/mail", "locked": false, "shell": "/bin/bash", "userid": 102160}), + 4100705=HsHostingAssetEntity(UNIX_USER, hsh00-mim, Michael Mellis, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/hsh00/users/mi", "locked": false, "shell": "/bin/false", "userid": 10003}), + 4100824=HsHostingAssetEntity(UNIX_USER, hsh00, Hostsharing Paket, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/hsh00", "locked": false, "shell": "/bin/bash", "userid": 10000}), + 4167846=HsHostingAssetEntity(UNIX_USER, hsh00-dph, hsh00-uph, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/hsh00/users/uph", "locked": false, "shell": "/bin/false", "userid": 110568}), + 4169546=HsHostingAssetEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/dph00", "locked": false, "shell": "/bin/bash", "userid": 110593}), + 4169596=HsHostingAssetEntity(UNIX_USER, dph00-uph, Domain admin, MANAGED_WEBSPACE:dph00, { "HDD hard quota": 0, "HDD soft quota": 0, "SDD hard quota": 0, "SDD soft quota": 0, "homedir": "/home/pacs/dph00/users/uph", "locked": false, "shell": "/bin/bash", "userid": 110594}) + } + """); + } + + // -------------------------------------------------------------------------------------------- + @Test @Order(11400) void validateBookingItems() { @@ -287,6 +329,8 @@ public class ImportHostingAssets extends ImportOfficeData { }); } + // -------------------------------------------------------------------------------------------- + @Test @Order(19000) @Commit @@ -323,19 +367,21 @@ public class ImportHostingAssets extends ImportOfficeData { persist(key, HsBookingItemEntityValidatorRegistry.validated(bi)); } + // ============================================================================================ + private void persistHostingAssetsOfType(final HsHostingAssetType hsHostingAssetType) { jpaAttempt.transacted(() -> { context(rbacSuperuser); hostingAssets.forEach((key, ha) -> { - if (ha.getType() == hsHostingAssetType) { - new HostingAssetEntitySaveProcessor(ha) - .preprocessEntity() - .validateEntity() - .prepareForSave() - .saveUsing(entity -> persist(key, entity)) - .validateContext(); + if (ha.getType() == hsHostingAssetType) { + new HostingAssetEntitySaveProcessor(ha) + .preprocessEntity() + .validateEntity() + .prepareForSave() + .saveUsing(entity -> persist(key, entity)) + .validateContext(); + } } - } ); }).assertSuccessful(); } @@ -402,12 +448,17 @@ public class ImportHostingAssets extends ImportOfficeData { bookingItems.put(PACKET_ID_OFFSET + packet_id, bookingItem); final var haType = determineHaType(basepacket_code); - logError(() -> assertThat(!free || haType == MANAGED_WEBSPACE || bookingItem.getRelatedProject().getDebitor().getDefaultPrefix().equals("hsh")) - .as("packet.free only supported for Hostsharing-Assets and ManagedWebspace in customer-ManagedServer, but is set for " + packet_name) + logError(() -> assertThat(!free || haType == MANAGED_WEBSPACE || bookingItem.getRelatedProject() + .getDebitor() + .getDefaultPrefix() + .equals("hsh")) + .as("packet.free only supported for Hostsharing-Assets and ManagedWebspace in customer-ManagedServer, but is set for " + + packet_name) .isTrue()); final var asset = HsHostingAssetEntity.builder() - .isLoaded(haType == MANAGED_WEBSPACE) // this turns off identifier validation to accept former default prefixes + .isLoaded(haType + == MANAGED_WEBSPACE) // this turns off identifier validation to accept former default prefixes .type(haType) .identifier(packet_name) .bookingItem(bookingItem) @@ -461,9 +512,9 @@ public class ImportHostingAssets extends ImportOfficeData { case "DAEMON" -> "Daemons"; case "MULTI" -> "Multi"; case "CPU" -> "CPU"; - case "RAM" -> returning("RAM", convert = v -> v/1024); - case "QUOTA" -> returning("SSD", convert = v -> v/1024); - case "STORAGE" -> returning("HDD", convert = v -> v/1024); + case "RAM" -> returning("RAM", convert = v -> v / 1024); + case "QUOTA" -> returning("SSD", convert = v -> v / 1024); + case "STORAGE" -> returning("HDD", convert = v -> v / 1024); case "TRAFFIC" -> "Traffic"; case "OFFICE" -> returning("Online Office Server", convert = v -> v == 1); @@ -526,7 +577,7 @@ public class ImportHostingAssets extends ImportOfficeData { case "SLAPLAT8H" -> "EXT8H"; default -> throw new IllegalArgumentException("unknown basecomponent_code: " + basecomponent_code); }; - if ( ofNullable(asset.getBookingItem().getResources().get(name)).map("BASIC"::equals).orElse(true) ) { + if (ofNullable(asset.getBookingItem().getResources().get(name)).map("BASIC"::equals).orElse(true)) { asset.getBookingItem().getResources().put(name, slaValue); } } else if (name.startsWith("SLA")) { @@ -537,7 +588,38 @@ public class ImportHostingAssets extends ImportOfficeData { }); } - V returning(final V value, final Object... assignments) { + private void importUnixUsers(final String[] header, final List records) { + final var columns = new Columns(header); + records.stream() + .map(this::trimAll) + .map(row -> new Record(columns, row)) + .forEach(rec -> { + final var unixuser_id = rec.getInteger("unixuser_id"); + final var packet_id = rec.getInteger("packet_id"); + final var unixUserAsset = HsHostingAssetEntity.builder() + .type(UNIX_USER) + .parentAsset(hostingAssets.get(PACKET_ID_OFFSET+packet_id)) + .identifier(rec.getString("name")) + .caption(rec.getString("comment")) + .config(Map.ofEntries( + entry("shell", rec.getString("shell")), + entry("homedir", rec.getString("homedir")), + entry("locked", rec.getBoolean("locked")), + entry("userid", rec.getInteger("userid")), + entry("SDD soft quota", rec.getInteger("quota_softlimit")), + entry("SDD hard quota", rec.getInteger("quota_hardlimit")), + entry("HDD soft quota", rec.getInteger("storage_softlimit")), + entry("HDD hard quota", rec.getInteger("storage_hardlimit")) + )) + .build(); + hostingAssets.put(UNIXUSER_ID_OFFSET + unixuser_id, unixUserAsset); + }); + } + + V returning( + final V value, + @SuppressWarnings("unused") final Object... assignments // DSL-hack: just used for side effects on caller-side + ) { return value; } diff --git a/src/test/resources/migration/hosting/unixuser.csv b/src/test/resources/migration/hosting/unixuser.csv new file mode 100644 index 00000000..ee08e2f0 --- /dev/null +++ b/src/test/resources/migration/hosting/unixuser.csv @@ -0,0 +1,19 @@ +unixuser_id;name;comment;shell;homedir;locked;packet_id;userid;quota_softlimit;quota_hardlimit;storage_softlimit;storage_hardlimit +100824;hsh00;Hostsharing Paket;/bin/bash;/home/pacs/hsh00;0;630;10000;0;0;0;0 + +5803;lug00;LUGs;/bin/bash;/home/pacs/lug00;0;1094;102090;0;0;0;0 +5805;lug00-wla.1;Paul Klemm;/bin/bash;/home/pacs/lug00/users/deaf;0;1094;102091;0;0;0;0 +5809;lug00-wla.2;Walter Müller;/bin/bash;/home/pacs/lug00/users/marl;0;1094;102093;0;0;0;0 +5811;lug00-ola.a;LUG OLA - POP a;/usr/bin/passwd;/home/pacs/lug00/users/marl.a;1;1094;102094;0;0;0;0 +5813;lug00-ola.b;LUG OLA - POP b;/usr/bin/passwd;/home/pacs/lug00/users/marl.b;1;1094;102095;0;0;0;0 +5835;lug00-test;Test;/usr/bin/passwd;/home/pacs/lug00/users/test;0;1094;102106;0;0;0;0 + +100705;hsh00-mim;Michael Mellis;/bin/false;/home/pacs/hsh00/users/mi;0;630;10003;0;0;0;0 +5964;mim00;Michael Mellis;/bin/bash;/home/pacs/mim00;0;1112;102147;0;0;0;0 +5966;mim00-1981;Jahrgangstreffen 1981;/bin/bash;/home/pacs/mim00/users/1981;0;1112;102148;128;256;0;0 +5990;mim00-mail;Mailbox;/bin/bash;/home/pacs/mim00/users/mail;0;1112;102160;0;0;0;0 + +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 +