booking-item-to-related-hosting-asset-just-1-to-1 (#61)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: #61
Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
Michael Hoennig 2024-06-18 13:53:11 +02:00
parent cbadc6e2c7
commit 62867a4cac
4 changed files with 55 additions and 46 deletions

View File

@ -17,6 +17,8 @@ import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject; import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
import jakarta.persistence.CascadeType; import jakarta.persistence.CascadeType;
@ -30,6 +32,7 @@ import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany; import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.persistence.Transient; import jakarta.persistence.Transient;
import jakarta.persistence.Version; import jakarta.persistence.Version;
@ -113,9 +116,8 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject {
@JoinColumn(name="parentitemuuid", referencedColumnName="uuid") @JoinColumn(name="parentitemuuid", referencedColumnName="uuid")
private List<HsBookingItemEntity> subBookingItems; private List<HsBookingItemEntity> subBookingItems;
@OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true) @OneToOne(mappedBy="bookingItem")
@JoinColumn(name="bookingitemuuid", referencedColumnName="uuid") private HsHostingAssetEntity relatedHostingAsset;
private List<HsHostingAssetEntity> subHostingAssets;
@Transient @Transient
private PatchableMapWrapper<Object> resourcesWrapper; private PatchableMapWrapper<Object> resourcesWrapper;

View File

@ -7,6 +7,7 @@ import org.apache.commons.lang3.function.TriFunction;
import java.util.List; import java.util.List;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_EMAIL_SETUP; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_EMAIL_SETUP;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.EMAIL_ADDRESS; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.EMAIL_ADDRESS;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_DATABASE; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_DATABASE;
@ -38,10 +39,11 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> unixUsers() { private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> unixUsers() {
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> { return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
final var unixUserCount = entity.getSubHostingAssets().stream() final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
.flatMap(ha -> ha.getSubHostingAssets().stream()) .map(ha -> ha.getSubHostingAssets().stream()
.filter(ha -> ha.getType() == UNIX_USER) .filter(subAsset -> subAsset.getType() == UNIX_USER)
.count(); .count())
.orElse(0L);
final long limitingValue = prop.getValue(entity.getResources()); final long limitingValue = prop.getValue(entity.getResources());
if (unixUserCount > factor*limitingValue) { if (unixUserCount > factor*limitingValue) {
return List.of(prop.propertyName() + "=" + limitingValue + " allows at maximum " + limitingValue*factor + " unix users, but " + unixUserCount + " found"); return List.of(prop.propertyName() + "=" + limitingValue + " allows at maximum " + limitingValue*factor + " unix users, but " + unixUserCount + " found");
@ -52,13 +54,14 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> databaseUsers() { private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> databaseUsers() {
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> { return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
final var unixUserCount = entity.getSubHostingAssets().stream() final var dbUserCount = ofNullable(entity.getRelatedHostingAsset())
.flatMap(ha -> ha.getSubHostingAssets().stream()) .map(ha -> ha.getSubHostingAssets().stream()
.filter(bi -> bi.getType() == PGSQL_USER || bi.getType() == MARIADB_USER ) .filter(bi -> bi.getType() == PGSQL_USER || bi.getType() == MARIADB_USER )
.count(); .count())
.orElse(0L);
final long limitingValue = prop.getValue(entity.getResources()); final long limitingValue = prop.getValue(entity.getResources());
if (unixUserCount > factor*limitingValue) { if (dbUserCount > factor*limitingValue) {
return List.of(prop.propertyName() + "=" + limitingValue + " allows at maximum " + limitingValue*factor + " database users, but " + unixUserCount + " found"); return List.of(prop.propertyName() + "=" + limitingValue + " allows at maximum " + limitingValue*factor + " database users, but " + dbUserCount + " found");
} }
return emptyList(); return emptyList();
}; };
@ -66,12 +69,13 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> databases() { private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> databases() {
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> { return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
final var unixUserCount = entity.getSubHostingAssets().stream() final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
.flatMap(ha -> ha.getSubHostingAssets().stream()) .map(ha -> ha.getSubHostingAssets().stream()
.filter(bi -> bi.getType()==PGSQL_USER || bi.getType()==MARIADB_USER ) .filter(bi -> bi.getType()==PGSQL_USER || bi.getType()==MARIADB_USER )
.flatMap(domainEMailSetup -> domainEMailSetup.getSubHostingAssets().stream() .flatMap(domainEMailSetup -> domainEMailSetup.getSubHostingAssets().stream()
.filter(ha -> ha.getType()==PGSQL_DATABASE || ha.getType()==MARIADB_DATABASE)) .filter(subAsset -> subAsset.getType()==PGSQL_DATABASE || subAsset.getType()==MARIADB_DATABASE))
.count(); .count())
.orElse(0L);
final long limitingValue = prop.getValue(entity.getResources()); final long limitingValue = prop.getValue(entity.getResources());
if (unixUserCount > factor*limitingValue) { if (unixUserCount > factor*limitingValue) {
return List.of(prop.propertyName() + "=" + limitingValue + " allows at maximum " + limitingValue*factor + " databases, but " + unixUserCount + " found"); return List.of(prop.propertyName() + "=" + limitingValue + " allows at maximum " + limitingValue*factor + " databases, but " + unixUserCount + " found");
@ -82,12 +86,13 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> eMailAddresses() { private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> eMailAddresses() {
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> { return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
final var unixUserCount = entity.getSubHostingAssets().stream() final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
.flatMap(ha -> ha.getSubHostingAssets().stream()) .map(ha -> ha.getSubHostingAssets().stream()
.filter(bi -> bi.getType() == DOMAIN_EMAIL_SETUP) .filter(bi -> bi.getType() == DOMAIN_EMAIL_SETUP)
.flatMap(domainEMailSetup -> domainEMailSetup.getSubHostingAssets().stream() .flatMap(domainEMailSetup -> domainEMailSetup.getSubHostingAssets().stream()
.filter(ha -> ha.getType()==EMAIL_ADDRESS)) .filter(subAsset -> subAsset.getType()==EMAIL_ADDRESS))
.count(); .count())
.orElse(0L);
final long limitingValue = prop.getValue(entity.getResources()); final long limitingValue = prop.getValue(entity.getResources());
if (unixUserCount > factor*limitingValue) { if (unixUserCount > factor*limitingValue) {
return List.of(prop.propertyName() + "=" + limitingValue + " allows at maximum " + limitingValue*factor + " databases, but " + unixUserCount + " found"); return List.of(prop.propertyName() + "=" + limitingValue + " allows at maximum " + limitingValue*factor + " databases, but " + unixUserCount + " found");

View File

@ -177,6 +177,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), separate ManagedWebspace, { Daemons: 0, Multi: 1, SSD: 100, Traffic: 50 })", "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), separate ManagedWebspace, { Daemons: 0, Multi: 1, SSD: 100, Traffic: 50 })",
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 500, Traffic: 500 })", "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 500, Traffic: 500 })",
"HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 })"); "HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 })");
assertThat(result.stream().filter(bi -> bi.getRelatedHostingAsset()!=null).findAny())
.as("at least one relatedProject expected, but none found => fetching relatedProject does not work")
.isNotEmpty();
} }
@Test @Test

View File

@ -139,27 +139,26 @@ class HsManagedServerBookingItemValidatorUnitTest {
entry("Traffic", 1000), entry("Traffic", 1000),
entry("Multi", 1) entry("Multi", 1)
)) ))
.subHostingAssets(of( .relatedHostingAsset(HsHostingAssetEntity.builder()
HsHostingAssetEntity.builder() .type(HsHostingAssetType.MANAGED_WEBSPACE)
.type(HsHostingAssetType.MANAGED_WEBSPACE) .identifier("abc00")
.identifier("abc00") .subHostingAssets(concat(
.subHostingAssets(concat( generate(26, HsHostingAssetType.UNIX_USER, "xyz00-%c%c"),
generate(26, HsHostingAssetType.UNIX_USER, "xyz00-%c%c"), generateDbUsersWithDatabases(3, HsHostingAssetType.PGSQL_USER,
generateDbUsersWithDatabases(3, HsHostingAssetType.PGSQL_USER, "xyz00_%c%c",
"xyz00_%c%c", 1, HsHostingAssetType.PGSQL_DATABASE
1, HsHostingAssetType.PGSQL_DATABASE ),
), generateDbUsersWithDatabases(3, HsHostingAssetType.MARIADB_USER,
generateDbUsersWithDatabases(3, HsHostingAssetType.MARIADB_USER, "xyz00_%c%c",
"xyz00_%c%c", 2, HsHostingAssetType.MARIADB_DATABASE
2, HsHostingAssetType.MARIADB_DATABASE ),
), generateDomainEmailSetupsWithEMailAddresses(26, HsHostingAssetType.DOMAIN_EMAIL_SETUP,
generateDomainEmailSetupsWithEMailAddresses(26, HsHostingAssetType.DOMAIN_EMAIL_SETUP, "%c%c.example.com",
"%c%c.example.com", 10, HsHostingAssetType.EMAIL_ADDRESS
10, HsHostingAssetType.EMAIL_ADDRESS )
) ))
)) .build()
.build() )
))
.build(); .build();
// when // when