HostingAsset-Hierarchie spec in enum HsHostingAssetType and generates PlantUML #72
199
doc/hs-hosting-asset-type-structure.md
Normal file
199
doc/hs-hosting-asset-type-structure.md
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
## HostingAsset Type Structure
|
||||||
|
|
||||||
|
### Domain
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
left to right direction
|
||||||
|
|
||||||
|
package Booking #feb28c {
|
||||||
|
entity BI_PRIVATE_CLOUD
|
||||||
|
entity BI_CLOUD_SERVER
|
||||||
|
entity BI_MANAGED_SERVER
|
||||||
|
entity BI_MANAGED_WEBSPACE
|
||||||
|
entity BI_DOMAIN_DNS_SETUP
|
||||||
|
entity BI_DOMAIN_EMAIL_SUBMISSION_SETUP
|
||||||
|
}
|
||||||
|
|
||||||
|
package Hosting #feb28c{
|
||||||
|
package Domain #99bcdb {
|
||||||
|
entity HA_DOMAIN_SETUP
|
||||||
|
entity HA_DOMAIN_DNS_SETUP
|
||||||
|
entity HA_DOMAIN_HTTP_SETUP
|
||||||
|
entity HA_DOMAIN_EMAIL_SUBMISSION_SETUP
|
||||||
|
entity HA_DOMAIN_EMAIL_MAILBOX_SETUP
|
||||||
|
entity HA_EMAIL_ADDRESS
|
||||||
|
}
|
||||||
|
|
||||||
|
package Server #99bcdb {
|
||||||
|
entity HA_CLOUD_SERVER
|
||||||
|
entity HA_MANAGED_SERVER
|
||||||
|
entity HA_IP_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
package Webspace #99bcdb {
|
||||||
|
entity HA_MANAGED_WEBSPACE
|
||||||
|
entity HA_UNIX_USER
|
||||||
|
entity HA_EMAIL_ALIAS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
|
||||||
|
|
||||||
|
HA_CLOUD_SERVER ==* BI_CLOUD_SERVER
|
||||||
|
HA_MANAGED_SERVER ==* BI_MANAGED_SERVER
|
||||||
|
HA_MANAGED_WEBSPACE ==* BI_MANAGED_WEBSPACE
|
||||||
|
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
|
||||||
|
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_HTTP_SETUP *==> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_HTTP_SETUP o..> HA_UNIX_USER
|
||||||
|
HA_DOMAIN_EMAIL_SUBMISSION_SETUP *==> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_EMAIL_SUBMISSION_SETUP o..> HA_MANAGED_WEBSPACE
|
||||||
|
HA_DOMAIN_EMAIL_MAILBOX_SETUP *==> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_EMAIL_MAILBOX_SETUP o..> HA_MANAGED_WEBSPACE
|
||||||
|
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_EMAIL_ADDRESS *==> HA_DOMAIN_EMAIL_MAILBOX_SETUP
|
||||||
|
HA_IP_NUMBER o..> HA_CLOUD_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
|
||||||
|
|
||||||
|
package Legend #white {
|
||||||
|
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
|
||||||
|
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
|
||||||
|
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
|
||||||
|
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
|
||||||
|
}
|
||||||
|
Booking -down[hidden]->Legend
|
||||||
|
```
|
||||||
|
### MariaDB
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
left to right direction
|
||||||
|
|
||||||
|
package Booking #feb28c {
|
||||||
|
entity BI_PRIVATE_CLOUD
|
||||||
|
entity BI_CLOUD_SERVER
|
||||||
|
entity BI_MANAGED_SERVER
|
||||||
|
entity BI_MANAGED_WEBSPACE
|
||||||
|
entity BI_DOMAIN_DNS_SETUP
|
||||||
|
entity BI_DOMAIN_EMAIL_SUBMISSION_SETUP
|
||||||
|
}
|
||||||
|
|
||||||
|
package Hosting #feb28c{
|
||||||
|
package MariaDB #99bcdb {
|
||||||
|
entity HA_MARIADB_INSTANCE
|
||||||
|
entity HA_MARIADB_USER
|
||||||
|
entity HA_MARIADB_DATABASE
|
||||||
|
}
|
||||||
|
|
||||||
|
package Server #99bcdb {
|
||||||
|
entity HA_CLOUD_SERVER
|
||||||
|
entity HA_MANAGED_SERVER
|
||||||
|
entity HA_IP_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
package Webspace #99bcdb {
|
||||||
|
entity HA_MANAGED_WEBSPACE
|
||||||
|
entity HA_UNIX_USER
|
||||||
|
entity HA_EMAIL_ALIAS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
|
||||||
|
|
||||||
|
HA_CLOUD_SERVER ==* BI_CLOUD_SERVER
|
||||||
|
HA_MANAGED_SERVER ==* BI_MANAGED_SERVER
|
||||||
|
HA_MANAGED_WEBSPACE ==* BI_MANAGED_WEBSPACE
|
||||||
|
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
|
||||||
|
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_MARIADB_INSTANCE *==> HA_MANAGED_SERVER
|
||||||
|
HA_MARIADB_USER *==> HA_MARIADB_INSTANCE
|
||||||
|
HA_MARIADB_USER o..> HA_MANAGED_WEBSPACE
|
||||||
|
HA_MARIADB_DATABASE *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_MARIADB_DATABASE o..> HA_MARIADB_INSTANCE
|
||||||
|
HA_IP_NUMBER o..> HA_CLOUD_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
|
||||||
|
|
||||||
|
package Legend #white {
|
||||||
|
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
|
||||||
|
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
|
||||||
|
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
|
||||||
|
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
|
||||||
|
}
|
||||||
|
Booking -down[hidden]->Legend
|
||||||
|
```
|
||||||
|
### PostgreSQL
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
left to right direction
|
||||||
|
|
||||||
|
package Booking #feb28c {
|
||||||
|
entity BI_PRIVATE_CLOUD
|
||||||
|
entity BI_CLOUD_SERVER
|
||||||
|
entity BI_MANAGED_SERVER
|
||||||
|
entity BI_MANAGED_WEBSPACE
|
||||||
|
entity BI_DOMAIN_DNS_SETUP
|
||||||
|
entity BI_DOMAIN_EMAIL_SUBMISSION_SETUP
|
||||||
|
}
|
||||||
|
|
||||||
|
package Hosting #feb28c{
|
||||||
|
package PostgreSQL #99bcdb {
|
||||||
|
entity HA_PGSQL_INSTANCE
|
||||||
|
entity HA_PGSQL_USER
|
||||||
|
entity HA_PGSQL_DATABASE
|
||||||
|
}
|
||||||
|
|
||||||
|
package Server #99bcdb {
|
||||||
|
entity HA_CLOUD_SERVER
|
||||||
|
entity HA_MANAGED_SERVER
|
||||||
|
entity HA_IP_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
package Webspace #99bcdb {
|
||||||
|
entity HA_MANAGED_WEBSPACE
|
||||||
|
entity HA_UNIX_USER
|
||||||
|
entity HA_EMAIL_ALIAS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
|
||||||
|
|
||||||
|
HA_CLOUD_SERVER ==* BI_CLOUD_SERVER
|
||||||
|
HA_MANAGED_SERVER ==* BI_MANAGED_SERVER
|
||||||
|
HA_MANAGED_WEBSPACE ==* BI_MANAGED_WEBSPACE
|
||||||
|
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
|
||||||
|
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_PGSQL_INSTANCE *==> HA_MANAGED_SERVER
|
||||||
|
HA_PGSQL_USER *==> HA_PGSQL_INSTANCE
|
||||||
|
HA_PGSQL_USER o..> HA_MANAGED_WEBSPACE
|
||||||
|
HA_PGSQL_DATABASE *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_PGSQL_DATABASE o..> HA_PGSQL_INSTANCE
|
||||||
|
HA_IP_NUMBER o..> HA_CLOUD_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
|
||||||
|
|
||||||
|
package Legend #white {
|
||||||
|
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
|
||||||
|
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
|
||||||
|
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
|
||||||
|
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
|
||||||
|
}
|
||||||
|
Booking -down[hidden]->Legend
|
||||||
|
```
|
||||||
|
This code generated was by HsHostingAssetType.main, do not amend manually.
|
@ -1,8 +1,37 @@
|
|||||||
package net.hostsharing.hsadminng.hs.booking.item;
|
package net.hostsharing.hsadminng.hs.booking.item;
|
||||||
|
|
||||||
public enum HsBookingItemType {
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.Optional.ofNullable;
|
||||||
|
|
||||||
|
public enum HsBookingItemType implements Node {
|
||||||
PRIVATE_CLOUD,
|
PRIVATE_CLOUD,
|
||||||
CLOUD_SERVER,
|
CLOUD_SERVER(PRIVATE_CLOUD),
|
||||||
MANAGED_SERVER,
|
MANAGED_SERVER(PRIVATE_CLOUD),
|
||||||
MANAGED_WEBSPACE
|
MANAGED_WEBSPACE(MANAGED_SERVER),
|
||||||
|
DOMAIN_DNS_SETUP, // TODO.spec: experimental
|
||||||
|
DOMAIN_EMAIL_SUBMISSION_SETUP; // TODO.spec: experimental
|
||||||
|
|
||||||
|
private final HsBookingItemType parentItemType;
|
||||||
|
|
||||||
|
HsBookingItemType() {
|
||||||
|
this.parentItemType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HsBookingItemType(final HsBookingItemType parentItemType) {
|
||||||
|
this.parentItemType = parentItemType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> edges() {
|
||||||
|
return ofNullable(parentItemType)
|
||||||
|
.map(p -> (nodeName() + " *--> " + p.nodeName()))
|
||||||
|
.stream().toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String nodeName() {
|
||||||
|
return "BI_" + name();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.booking.item;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface Node {
|
||||||
|
|
||||||
|
String nodeName();
|
||||||
|
List<String> edges();
|
||||||
|
}
|
@ -8,7 +8,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Optional.ofNullable;
|
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_MAILBOX_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;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_USER;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MARIADB_USER;
|
||||||
@ -88,7 +88,7 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
|||||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
||||||
final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
|
final var unixUserCount = ofNullable(entity.getRelatedHostingAsset())
|
||||||
.map(ha -> ha.getSubHostingAssets().stream()
|
.map(ha -> ha.getSubHostingAssets().stream()
|
||||||
.filter(bi -> bi.getType() == DOMAIN_EMAIL_SETUP)
|
.filter(bi -> bi.getType() == DOMAIN_EMAIL_MAILBOX_SETUP)
|
||||||
hsh-michaelhoennig marked this conversation as resolved
|
|||||||
.flatMap(domainEMailSetup -> domainEMailSetup.getSubHostingAssets().stream()
|
.flatMap(domainEMailSetup -> domainEMailSetup.getSubHostingAssets().stream()
|
||||||
.filter(subAsset -> subAsset.getType()==EMAIL_ADDRESS))
|
.filter(subAsset -> subAsset.getType()==EMAIL_ADDRESS))
|
||||||
.count())
|
.count())
|
||||||
|
@ -50,6 +50,7 @@ import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.DELETE;
|
|||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.INSERT;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.SELECT;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.UPDATE;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Permission.UPDATE;
|
||||||
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.RbacUserReference.UserRole.CREATOR;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.ADMIN;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.AGENT;
|
||||||
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.GUEST;
|
import static net.hostsharing.hsadminng.rbac.rbacdef.RbacView.Role.GUEST;
|
||||||
@ -204,11 +205,12 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject, Properti
|
|||||||
.switchOnColumn("type",
|
.switchOnColumn("type",
|
||||||
inCaseOf("DOMAIN_SETUP", then -> {
|
inCaseOf("DOMAIN_SETUP", then -> {
|
||||||
then.toRole(GLOBAL, GUEST).grantPermission(INSERT);
|
then.toRole(GLOBAL, GUEST).grantPermission(INSERT);
|
||||||
then.toRole(GLOBAL, ADMIN).grantPermission(SELECT); // TODO.spec: replace by a proper solution
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
.createRole(OWNER, (with) -> {
|
.createRole(OWNER, (with) -> {
|
||||||
|
with.owningUser(CREATOR);
|
||||||
|
with.incomingSuperRole(GLOBAL, ADMIN).unassumed(); // TODO.spec: replace by a better solution
|
||||||
with.incomingSuperRole("bookingItem", ADMIN);
|
with.incomingSuperRole("bookingItem", ADMIN);
|
||||||
with.incomingSuperRole("parentAsset", ADMIN);
|
with.incomingSuperRole("parentAsset", ADMIN);
|
||||||
with.permission(DELETE);
|
with.permission(DELETE);
|
||||||
|
@ -1,33 +1,204 @@
|
|||||||
package net.hostsharing.hsadminng.hs.hosting.asset;
|
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
||||||
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
|
||||||
|
import net.hostsharing.hsadminng.hs.booking.item.Node;
|
||||||
|
|
||||||
public enum HsHostingAssetType {
|
import javax.naming.NamingException;
|
||||||
CLOUD_SERVER, // named e.g. vm1234
|
import java.io.IOException;
|
||||||
MANAGED_SERVER, // named e.g. vm1234
|
import java.nio.file.Files;
|
||||||
MANAGED_WEBSPACE(MANAGED_SERVER), // named eg. xyz00
|
import java.nio.file.Path;
|
||||||
UNIX_USER(MANAGED_WEBSPACE), // named e.g. xyz00-abc
|
import java.nio.file.StandardOpenOption;
|
||||||
DOMAIN_SETUP, // named e.g. example.org
|
import java.util.Collection;
|
||||||
DOMAIN_DNS_SETUP(DOMAIN_SETUP), // named e.g. example.org
|
import java.util.List;
|
||||||
DOMAIN_HTTP_SETUP(DOMAIN_SETUP), // named e.g. example.org
|
import java.util.Set;
|
||||||
DOMAIN_EMAIL_SETUP(DOMAIN_SETUP), // named e.g. example.org
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static java.util.Arrays.stream;
|
||||||
|
import static java.util.stream.Collectors.joining;
|
||||||
|
import static java.util.stream.Collectors.toSet;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.*;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.OPTIONAL;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.REQUIRED;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.ASSIGNED_TO_ASSET;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.BOOKING_ITEM;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.PARENT_ASSET;
|
||||||
|
|
||||||
|
public enum HsHostingAssetType implements Node {
|
||||||
|
SAME_TYPE, // pseudo-type for recursive references
|
||||||
|
|
||||||
|
CLOUD_SERVER( // named e.g. vm1234
|
||||||
|
inGroup("Server"),
|
||||||
|
requires(HsBookingItemType.CLOUD_SERVER)),
|
||||||
|
|
||||||
|
MANAGED_SERVER( // named e.g. vm1234
|
||||||
|
inGroup("Server"),
|
||||||
|
requires(HsBookingItemType.MANAGED_SERVER)),
|
||||||
|
|
||||||
|
MANAGED_WEBSPACE( // named eg. xyz00
|
||||||
|
inGroup("Webspace"),
|
||||||
|
requires(HsBookingItemType.MANAGED_WEBSPACE),
|
||||||
|
optionalParent(MANAGED_SERVER)),
|
||||||
|
|
||||||
|
UNIX_USER( // named e.g. xyz00-abc
|
||||||
|
inGroup("Webspace"),
|
||||||
|
requiredParent(MANAGED_WEBSPACE)),
|
||||||
|
|
||||||
|
DOMAIN_SETUP( // named e.g. example.org
|
||||||
|
inGroup("Domain"),
|
||||||
|
optionalParent(SAME_TYPE)
|
||||||
|
),
|
||||||
|
|
||||||
|
DOMAIN_DNS_SETUP( // named e.g. example.org
|
||||||
|
inGroup("Domain"),
|
||||||
|
requiredParent(DOMAIN_SETUP)),
|
||||||
|
|
||||||
|
DOMAIN_HTTP_SETUP( // named e.g. example.org
|
||||||
|
inGroup("Domain"),
|
||||||
|
requiredParent(DOMAIN_SETUP),
|
||||||
|
assignedTo(UNIX_USER)),
|
||||||
|
|
||||||
|
DOMAIN_EMAIL_SUBMISSION_SETUP( // named e.g. example.org
|
||||||
|
inGroup("Domain"),
|
||||||
|
requiredParent(DOMAIN_SETUP),
|
||||||
|
assignedTo(MANAGED_WEBSPACE)),
|
||||||
|
|
||||||
|
DOMAIN_EMAIL_MAILBOX_SETUP( // named e.g. example.org
|
||||||
|
inGroup("Domain"),
|
||||||
|
requiredParent(DOMAIN_SETUP),
|
||||||
|
assignedTo(MANAGED_WEBSPACE)),
|
||||||
|
|
||||||
// TODO.spec: SECURE_MX
|
// TODO.spec: SECURE_MX
|
||||||
EMAIL_ALIAS(MANAGED_WEBSPACE), // named e.g. xyz00-abc
|
|
||||||
EMAIL_ADDRESS(DOMAIN_EMAIL_SETUP), // named e.g. sample@example.org
|
|
||||||
PGSQL_USER(MANAGED_WEBSPACE), // named e.g. xyz00_abc
|
|
||||||
PGSQL_DATABASE(MANAGED_WEBSPACE), // named e.g. xyz00_abc, TODO.spec: or PGSQL_USER?
|
|
||||||
MARIADB_USER(MANAGED_WEBSPACE), // named e.g. xyz00_abc
|
|
||||||
MARIADB_DATABASE(MANAGED_WEBSPACE); // named e.g. xyz00_abc, TODO.spec: or MARIADB_USER?
|
|
||||||
|
|
||||||
|
EMAIL_ALIAS( // named e.g. xyz00-abc
|
||||||
|
inGroup("Webspace"),
|
||||||
|
requiredParent(MANAGED_WEBSPACE)),
|
||||||
|
|
||||||
public final HsHostingAssetType parentAssetType;
|
EMAIL_ADDRESS( // named e.g. sample@example.org
|
||||||
|
inGroup("Domain"),
|
||||||
|
requiredParent(DOMAIN_EMAIL_MAILBOX_SETUP)),
|
||||||
|
|
||||||
HsHostingAssetType(final HsHostingAssetType parentAssetType) {
|
PGSQL_INSTANCE( // TODO.spec: identifier to be specified
|
||||||
this.parentAssetType = parentAssetType;
|
inGroup("PostgreSQL"),
|
||||||
|
requiredParent(MANAGED_SERVER)),
|
||||||
|
|
||||||
|
PGSQL_USER( // named e.g. xyz00_abc
|
||||||
|
inGroup("PostgreSQL"),
|
||||||
|
requiredParent(PGSQL_INSTANCE),
|
||||||
|
assignedTo(MANAGED_WEBSPACE)),
|
||||||
|
|
||||||
|
PGSQL_DATABASE( // named e.g. xyz00_abc
|
||||||
|
inGroup("PostgreSQL"),
|
||||||
|
requiredParent(MANAGED_WEBSPACE), // TODO.spec: or PGSQL_USER?
|
||||||
|
assignedTo(PGSQL_INSTANCE)), // TODO.spec: or swapping parent+assignedTo?
|
||||||
|
|
||||||
|
MARIADB_INSTANCE( // TODO.spec: identifier to be specified
|
||||||
|
inGroup("MariaDB"),
|
||||||
|
requiredParent(MANAGED_SERVER)), // TODO.spec: or MANAGED_WEBSPACE?
|
||||||
|
|
||||||
|
MARIADB_USER( // named e.g. xyz00_abc
|
||||||
|
inGroup("MariaDB"),
|
||||||
|
requiredParent(MARIADB_INSTANCE),
|
||||||
|
assignedTo(MANAGED_WEBSPACE)),
|
||||||
|
|
||||||
|
MARIADB_DATABASE( // named e.g. xyz00_abc
|
||||||
|
inGroup("MariaDB"),
|
||||||
|
requiredParent(MANAGED_WEBSPACE), // TODO.spec: or MARIADB_USER?
|
||||||
|
assignedTo(MARIADB_INSTANCE)), // TODO.spec: or swapping parent+assignedTo?
|
||||||
|
|
||||||
|
IP_NUMBER(
|
||||||
|
inGroup("Server"),
|
||||||
|
assignedTo(CLOUD_SERVER),
|
||||||
|
assignedTo(MANAGED_SERVER),
|
||||||
|
assignedTo(MANAGED_WEBSPACE)
|
||||||
|
);
|
||||||
|
|
||||||
|
private final String groupName;
|
||||||
|
private final EntityTypeRelation<?, ?>[] relations;
|
||||||
|
|
||||||
|
HsHostingAssetType(
|
||||||
|
final String groupName,
|
||||||
|
final EntityTypeRelation<?, ?>... relations
|
||||||
|
) {
|
||||||
|
this.groupName = groupName;
|
||||||
|
this.relations = relations;
|
||||||
}
|
}
|
||||||
|
|
||||||
HsHostingAssetType() {
|
HsHostingAssetType() {
|
||||||
this(null);
|
this.groupName = null;
|
||||||
|
this.relations = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// just syntactic sugar
|
||||||
|
private static String inGroup(final String groupName) {
|
||||||
|
return groupName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO.refa: try to get rid of the following similar methods:
|
||||||
|
|
||||||
|
public RelationPolicy bookingItemPolicy() {
|
||||||
|
return stream(relations)
|
||||||
|
.filter(r -> r.relationType == BOOKING_ITEM)
|
||||||
|
.map(r -> r.relationPolicy)
|
||||||
|
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||||
|
.orElse(RelationPolicy.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HsBookingItemType bookingItemType() {
|
||||||
|
return stream(relations)
|
||||||
|
.filter(r -> r.relationType == BOOKING_ITEM)
|
||||||
|
.map(r -> HsBookingItemType.valueOf(r.relatedType(this).toString()))
|
||||||
|
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelationPolicy parentAssetPolicy() {
|
||||||
|
return stream(relations)
|
||||||
|
.filter(r -> r.relationType == PARENT_ASSET)
|
||||||
|
.map(r -> r.relationPolicy)
|
||||||
|
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||||
|
.orElse(RelationPolicy.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HsHostingAssetType parentAssetType() {
|
||||||
|
return stream(relations)
|
||||||
|
.filter(r -> r.relationType == PARENT_ASSET)
|
||||||
|
.map(r -> HsHostingAssetType.valueOf(r.relatedType(this).toString()))
|
||||||
|
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelationPolicy assignedToAssetPolicy() {
|
||||||
|
return stream(relations)
|
||||||
|
.filter(r -> r.relationType == ASSIGNED_TO_ASSET)
|
||||||
|
.map(r -> r.relationPolicy)
|
||||||
|
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||||
|
.orElse(RelationPolicy.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HsHostingAssetType assignedToAssetType() {
|
||||||
|
return stream(relations)
|
||||||
|
.filter(r -> r.relationType == ASSIGNED_TO_ASSET)
|
||||||
|
.map(r -> HsHostingAssetType.valueOf(r.relatedType(this).toString()))
|
||||||
|
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <X> X onlyASingleElementExpectedException(Object a, Object b) {
|
||||||
|
throw new IllegalStateException("Only a single element expected to match criteria.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> edges() {
|
||||||
|
return stream(relations)
|
||||||
|
.map(r -> nodeName() + r.edge + r.relatedType(this).nodeName())
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String nodeName() {
|
||||||
|
return "HA_" + name();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Enum<?>> HsHostingAssetType of(final T value) {
|
public static <T extends Enum<?>> HsHostingAssetType of(final T value) {
|
||||||
@ -37,4 +208,148 @@ public enum HsHostingAssetType {
|
|||||||
static String asString(final HsHostingAssetType type) {
|
static String asString(final HsHostingAssetType type) {
|
||||||
return type == null ? null : type.name();
|
return type == null ? null : type.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String renderAsPlantUML(final String caption, final Set<String> includedHostingGroups) {
|
||||||
|
final String bookingNodes = stream(HsBookingItemType.values())
|
||||||
|
.map(t -> " entity " + t.nodeName())
|
||||||
|
.collect(joining("\n"));
|
||||||
|
final String hostingGroups = includedHostingGroups.stream().sorted()
|
||||||
|
.map(HsHostingAssetType::generateGroup)
|
||||||
|
.collect(joining("\n"));
|
||||||
|
final String hostingAssetNodes = stream(HsHostingAssetType.values())
|
||||||
|
.filter(t -> t.isInGroups(includedHostingGroups))
|
||||||
|
.map(t -> "entity " + t.nodeName())
|
||||||
|
.collect(joining("\n"));
|
||||||
|
final String bookingItemEdges = stream(HsBookingItemType.values())
|
||||||
|
.map(HsBookingItemType::edges)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.collect(joining("\n"));
|
||||||
|
final String hostingAssetEdges = stream(HsHostingAssetType.values())
|
||||||
|
.filter(t -> t.isInGroups(includedHostingGroups))
|
||||||
|
.map(HsHostingAssetType::edges)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.collect(joining("\n"));
|
||||||
|
return """
|
||||||
|
|
||||||
|
### %{caption}
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
left to right direction
|
||||||
|
|
||||||
|
package Booking #feb28c {
|
||||||
|
%{bookingNodes}
|
||||||
|
}
|
||||||
|
|
||||||
|
package Hosting #feb28c{
|
||||||
|
%{hostingGroups}
|
||||||
|
}
|
||||||
|
|
||||||
|
%{bookingItemEdges}
|
||||||
|
|
||||||
|
%{hostingAssetEdges}
|
||||||
|
|
||||||
|
package Legend #white {
|
||||||
|
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
|
||||||
|
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
|
||||||
|
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
|
||||||
|
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
|
||||||
|
}
|
||||||
|
Booking -down[hidden]->Legend
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
.replace("%{caption}", caption)
|
||||||
|
.replace("%{bookingNodes}", bookingNodes)
|
||||||
|
.replace("%{hostingGroups}", hostingGroups)
|
||||||
|
.replace("%{hostingAssetNodeStyles}", hostingAssetNodes)
|
||||||
|
.replace("%{bookingItemEdges}", bookingItemEdges)
|
||||||
|
.replace("%{hostingAssetEdges}", hostingAssetEdges);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isInGroups(final Set<String> assetGroups) {
|
||||||
|
return groupName != null && assetGroups.contains(groupName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String generateGroup(final String group) {
|
||||||
|
return " package " + group + " #99bcdb {\n"
|
||||||
|
+ stream(HsHostingAssetType.values())
|
||||||
|
.filter(t -> group.equals(t.groupName))
|
||||||
|
.map(t -> " entity " + t.nodeName())
|
||||||
|
.collect(joining("\n"))
|
||||||
|
+ "\n }\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
static String renderAsEmbeddedPlantUml() {
|
||||||
|
|
||||||
|
final var markdown = new StringBuilder("""
|
||||||
|
## HostingAsset Type Structure
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
// rendering all types in a single diagram is currently ignored
|
||||||
|
renderAsPlantUML("Domain", stream(HsHostingAssetType.values())
|
||||||
|
.filter(t -> t.groupName != null)
|
||||||
|
.map(t -> t.groupName)
|
||||||
|
.collect(toSet()));
|
||||||
|
|
||||||
|
markdown.append(renderAsPlantUML("Domain", Set.of("Domain", "Webspace", "Server")))
|
||||||
|
.append(renderAsPlantUML("MariaDB", Set.of("MariaDB", "Webspace", "Server")))
|
||||||
|
.append(renderAsPlantUML("PostgreSQL", Set.of("PostgreSQL", "Webspace", "Server")));
|
||||||
|
|
||||||
|
markdown.append("""
|
||||||
|
|
||||||
|
This code generated was by %{this}.main, do not amend manually.
|
||||||
|
"""
|
||||||
|
.replace("%{this}", HsHostingAssetType.class.getSimpleName()));
|
||||||
|
|
||||||
|
return markdown.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(final String[] args) throws IOException, NamingException {
|
||||||
|
Files.writeString(
|
||||||
|
Path.of("doc/hs-hosting-asset-type-structure.md"),
|
||||||
|
renderAsEmbeddedPlantUml(),
|
||||||
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RelationPolicy {
|
||||||
|
FORBIDDEN, OPTIONAL, REQUIRED
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RelationType {
|
||||||
|
BOOKING_ITEM,
|
||||||
|
PARENT_ASSET,
|
||||||
|
ASSIGNED_TO_ASSET
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
class EntityTypeRelation<E, T extends Node> {
|
||||||
|
|
||||||
|
final HsHostingAssetType.RelationPolicy relationPolicy;
|
||||||
|
final HsHostingAssetType.RelationType relationType;
|
||||||
|
final Function<HsHostingAssetEntity, E> getter;
|
||||||
|
private final T relatedType;
|
||||||
|
final String edge;
|
||||||
|
|
||||||
|
public T relatedType(final HsHostingAssetType referringType) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return relatedType == HsHostingAssetType.SAME_TYPE ? (T) referringType : relatedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EntityTypeRelation<HsBookingItemEntity, HsBookingItemType> requires(final HsBookingItemType bookingItemType) {
|
||||||
|
return new EntityTypeRelation<>(REQUIRED, BOOKING_ITEM, HsHostingAssetEntity::getBookingItem, bookingItemType, " *==> ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> optionalParent(final HsHostingAssetType hostingAssetType) {
|
||||||
|
return new EntityTypeRelation<>(OPTIONAL, PARENT_ASSET, HsHostingAssetEntity::getParentAsset, hostingAssetType, " o..> ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> requiredParent(final HsHostingAssetType hostingAssetType) {
|
||||||
|
return new EntityTypeRelation<>(REQUIRED, PARENT_ASSET, HsHostingAssetEntity::getParentAsset, hostingAssetType, " *==> ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> assignedTo(final HsHostingAssetType hostingAssetType) {
|
||||||
|
return new EntityTypeRelation<>(REQUIRED, ASSIGNED_TO_ASSET, HsHostingAssetEntity::getAssignedToAsset, hostingAssetType, " o..> ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
|
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
||||||
|
|
||||||
class HsCloudServerHostingAssetValidator extends HsHostingAssetEntityValidator {
|
class HsCloudServerHostingAssetValidator extends HsHostingAssetEntityValidator {
|
||||||
|
|
||||||
HsCloudServerHostingAssetValidator() {
|
HsCloudServerHostingAssetValidator() {
|
||||||
super(
|
super(
|
||||||
BookingItem.mustBeOfType(HsBookingItemType.CLOUD_SERVER),
|
CLOUD_SERVER,
|
||||||
ParentAsset.mustBeNull(),
|
|
||||||
AssignedToAsset.mustBeNull(),
|
|
||||||
AlarmContact.isOptional(),
|
AlarmContact.isOptional(),
|
||||||
NO_EXTRA_PROPERTIES);
|
NO_EXTRA_PROPERTIES);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
|||||||
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
|
||||||
import net.hostsharing.hsadminng.system.SystemProcess;
|
import net.hostsharing.hsadminng.system.SystemProcess;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -10,6 +9,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import static java.util.Arrays.stream;
|
import static java.util.Arrays.stream;
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_DNS_SETUP;
|
||||||
import static net.hostsharing.hsadminng.hs.validation.ArrayProperty.arrayOf;
|
import static net.hostsharing.hsadminng.hs.validation.ArrayProperty.arrayOf;
|
||||||
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
|
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
|
||||||
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
|
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
|
||||||
@ -30,11 +30,11 @@ class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidato
|
|||||||
|
|
||||||
static final String RR_REGEX_IN_TTL =
|
static final String RR_REGEX_IN_TTL =
|
||||||
RR_REGEX_NAME + RR_REGEX_IN + RR_REGEX_TTL + RR_RECORD_TYPE + RR_RECORD_DATA + RR_COMMENT;
|
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() {
|
HsDomainDnsSetupHostingAssetValidator() {
|
||||||
super( BookingItem.mustBeNull(),
|
super(
|
||||||
ParentAsset.mustBeOfType(HsHostingAssetType.DOMAIN_SETUP),
|
DOMAIN_DNS_SETUP,
|
||||||
AssignedToAsset.mustBeNull(),
|
|
||||||
AlarmContact.isOptional(),
|
AlarmContact.isOptional(),
|
||||||
|
|
||||||
integerProperty("TTL").min(0).withDefault(21600),
|
integerProperty("TTL").min(0).withDefault(21600),
|
||||||
@ -60,14 +60,14 @@ class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidato
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||||
return Pattern.compile("^" + assetEntity.getParentAsset().getIdentifier() + "$");
|
return Pattern.compile("^" + assetEntity.getParentAsset().getIdentifier() + Pattern.quote(IDENTIFIER_SUFFIX) + "$");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preprocessEntity(final HsHostingAssetEntity entity) {
|
public void preprocessEntity(final HsHostingAssetEntity entity) {
|
||||||
super.preprocessEntity(entity);
|
super.preprocessEntity(entity);
|
||||||
if (entity.getIdentifier() == null) {
|
if (entity.getIdentifier() == null) {
|
||||||
ofNullable(entity.getParentAsset()).ifPresent(pa -> entity.setIdentifier(pa.getIdentifier()));
|
ofNullable(entity.getParentAsset()).ifPresent(pa -> entity.setIdentifier(pa.getIdentifier() + IDENTIFIER_SUFFIX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidato
|
|||||||
final var result = super.validateContext(assetEntity);
|
final var result = super.validateContext(assetEntity);
|
||||||
|
|
||||||
// TODO.spec: define which checks should get raised to error level
|
// TODO.spec: define which checks should get raised to error level
|
||||||
final var namedCheckZone = new SystemProcess("named-checkzone", assetEntity.getIdentifier());
|
final var namedCheckZone = new SystemProcess("named-checkzone", fqdn(assetEntity));
|
||||||
if (namedCheckZone.execute(toZonefileString(assetEntity)) != 0) {
|
if (namedCheckZone.execute(toZonefileString(assetEntity)) != 0) {
|
||||||
// yes, named-checkzone writes error messages to stdout
|
// yes, named-checkzone writes error messages to stdout
|
||||||
stream(namedCheckZone.getStdOut().split("\n"))
|
stream(namedCheckZone.getStdOut().split("\n"))
|
||||||
@ -99,8 +99,12 @@ class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidato
|
|||||||
|
|
||||||
{userRRs}
|
{userRRs}
|
||||||
"""
|
"""
|
||||||
.replace("{domain}", assetEntity.getIdentifier())
|
.replace("{domain}", fqdn(assetEntity))
|
||||||
.replace("{ttl}", getPropertyValue(assetEntity, "TTL"))
|
.replace("{ttl}", getPropertyValue(assetEntity, "TTL"))
|
||||||
.replace("{userRRs}", getPropertyValues(assetEntity, "user-RR") );
|
.replace("{userRRs}", getPropertyValues(assetEntity, "user-RR") );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String fqdn(final HsHostingAssetEntity assetEntity) {
|
||||||
|
return assetEntity.getIdentifier().substring(0, assetEntity.getIdentifier().length()-IDENTIFIER_SUFFIX.length());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,11 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
|||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
|
||||||
|
|
||||||
class HsDomainSetupHostingAssetValidator extends HsHostingAssetEntityValidator {
|
class HsDomainSetupHostingAssetValidator extends HsHostingAssetEntityValidator {
|
||||||
|
|
||||||
public static final String DOMAIN_NAME_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}";
|
public static final String DOMAIN_NAME_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}";
|
||||||
@ -11,15 +14,43 @@ class HsDomainSetupHostingAssetValidator extends HsHostingAssetEntityValidator {
|
|||||||
private final Pattern identifierPattern;
|
private final Pattern identifierPattern;
|
||||||
|
|
||||||
HsDomainSetupHostingAssetValidator() {
|
HsDomainSetupHostingAssetValidator() {
|
||||||
super( BookingItem.mustBeNull(),
|
super( DOMAIN_SETUP,
|
||||||
ParentAsset.mustBeNull(),
|
|
||||||
AssignedToAsset.mustBeNull(),
|
|
||||||
AlarmContact.isOptional(),
|
AlarmContact.isOptional(),
|
||||||
|
|
||||||
NO_EXTRA_PROPERTIES);
|
NO_EXTRA_PROPERTIES);
|
||||||
this.identifierPattern = Pattern.compile(DOMAIN_NAME_REGEX);
|
this.identifierPattern = Pattern.compile(DOMAIN_NAME_REGEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> validateEntity(final HsHostingAssetEntity assetEntity) {
|
||||||
|
// TODO.impl: for newly created entities, check the permission of setting up a domain
|
||||||
|
//
|
||||||
|
// reject, if the domain is any of these:
|
||||||
|
// hostsharing.com|net|org|coop, // just to be on the safe side
|
||||||
|
// [^.}+, // top-level-domain
|
||||||
|
// co.uk, org.uk, gov.uk, ac.uk, sch.uk,
|
||||||
|
// com.au, net.au, org.au, edu.au, gov.au, asn.au, id.au,
|
||||||
|
// co.jp, ne.jp, or.jp, ac.jp, go.jp,
|
||||||
|
// com.cn, net.cn, org.cn, gov.cn, edu.cn, ac.cn,
|
||||||
|
// com.br, net.br, org.br, gov.br, edu.br, mil.br, art.br,
|
||||||
|
// co.in, net.in, org.in, gen.in, firm.in, ind.in,
|
||||||
|
// com.mx, net.mx, org.mx, gob.mx, edu.mx,
|
||||||
|
// gov.it, edu.it,
|
||||||
|
// co.nz, net.nz, org.nz, govt.nz, ac.nz, school.nz, geek.nz, kiwi.nz,
|
||||||
|
// co.kr, ne.kr, or.kr, go.kr, re.kr, pe.kr
|
||||||
|
//
|
||||||
|
// allow if
|
||||||
|
// - user has Admin/Agent-role for all its sub-domains and the direct parent-Domain which are set up at at Hostsharing
|
||||||
|
// - domain has DNS zone with TXT record approval
|
||||||
|
// - parent-domain has DNS zone with TXT record approval
|
||||||
|
// - dom
|
||||||
|
//
|
||||||
|
// TXT-Record check:
|
||||||
|
// new InitialDirContext().getAttributes("dns:_netblocks.google.com", new String[] { "TXT"}).get("TXT").getAll();
|
||||||
|
|
||||||
|
return super.validateEntity(assetEntity);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||||
return identifierPattern;
|
return identifierPattern;
|
||||||
|
@ -15,9 +15,7 @@ class HsEMailAliasHostingAssetValidator extends HsHostingAssetEntityValidator {
|
|||||||
public static final int EMAIL_ADDRESS_MAX_LENGTH = 320; // according to RFC 5321 and RFC 5322
|
public static final int EMAIL_ADDRESS_MAX_LENGTH = 320; // according to RFC 5321 and RFC 5322
|
||||||
|
|
||||||
HsEMailAliasHostingAssetValidator() {
|
HsEMailAliasHostingAssetValidator() {
|
||||||
super( BookingItem.mustBeNull(),
|
super( HsHostingAssetType.EMAIL_ALIAS,
|
||||||
ParentAsset.mustBeOfType(HsHostingAssetType.MANAGED_WEBSPACE),
|
|
||||||
AssignedToAsset.mustBeNull(),
|
|
||||||
AlarmContact.isOptional(),
|
AlarmContact.isOptional(),
|
||||||
|
|
||||||
arrayOf(
|
arrayOf(
|
||||||
|
@ -9,7 +9,6 @@ import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
|||||||
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
|
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
|
||||||
import net.hostsharing.hsadminng.hs.validation.ValidatableProperty;
|
import net.hostsharing.hsadminng.hs.validation.ValidatableProperty;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -26,21 +25,31 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
|
|||||||
|
|
||||||
static final ValidatableProperty<?, ?>[] NO_EXTRA_PROPERTIES = new ValidatableProperty<?, ?>[0];
|
static final ValidatableProperty<?, ?>[] NO_EXTRA_PROPERTIES = new ValidatableProperty<?, ?>[0];
|
||||||
|
|
||||||
private final HsHostingAssetEntityValidator.BookingItem bookingItemValidation;
|
private final ReferenceValidator<HsBookingItemEntity, HsBookingItemType> bookingItemReferenceValidation;
|
||||||
private final HsHostingAssetEntityValidator.ParentAsset parentAssetValidation;
|
private final ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> parentAssetReferenceValidation;
|
||||||
private final HsHostingAssetEntityValidator.AssignedToAsset assignedToAssetValidation;
|
private final ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> assignedToAssetReferenceValidation;
|
||||||
private final HsHostingAssetEntityValidator.AlarmContact alarmContactValidation;
|
private final HsHostingAssetEntityValidator.AlarmContact alarmContactValidation;
|
||||||
|
|
||||||
HsHostingAssetEntityValidator(
|
HsHostingAssetEntityValidator(
|
||||||
@NotNull final BookingItem bookingItemValidation,
|
final HsHostingAssetType assetType,
|
||||||
@NotNull final ParentAsset parentAssetValidation,
|
final AlarmContact alarmContactValidation,
|
||||||
@NotNull final AssignedToAsset assignedToAssetValidation,
|
|
||||||
@NotNull final AlarmContact alarmContactValidation,
|
|
||||||
final ValidatableProperty<?, ?>... properties) {
|
final ValidatableProperty<?, ?>... properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
this.bookingItemValidation = bookingItemValidation;
|
this.bookingItemReferenceValidation = new ReferenceValidator<>(
|
||||||
this.parentAssetValidation = parentAssetValidation;
|
assetType.bookingItemPolicy(),
|
||||||
this.assignedToAssetValidation = assignedToAssetValidation;
|
assetType.bookingItemType(),
|
||||||
|
HsHostingAssetEntity::getBookingItem,
|
||||||
|
HsBookingItemEntity::getType);
|
||||||
|
this.parentAssetReferenceValidation = new ReferenceValidator<>(
|
||||||
|
assetType.parentAssetPolicy(),
|
||||||
|
assetType.parentAssetType(),
|
||||||
|
HsHostingAssetEntity::getParentAsset,
|
||||||
|
HsHostingAssetEntity::getType);
|
||||||
|
this.assignedToAssetReferenceValidation = new ReferenceValidator<>(
|
||||||
|
assetType.assignedToAssetPolicy(),
|
||||||
|
assetType.assignedToAssetType(),
|
||||||
|
HsHostingAssetEntity::getAssignedToAsset,
|
||||||
|
HsHostingAssetEntity::getType);
|
||||||
this.alarmContactValidation = alarmContactValidation;
|
this.alarmContactValidation = alarmContactValidation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,9 +72,9 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
|
|||||||
|
|
||||||
private List<String> validateEntityReferencesAndProperties(final HsHostingAssetEntity assetEntity) {
|
private List<String> validateEntityReferencesAndProperties(final HsHostingAssetEntity assetEntity) {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
validateReferencedEntity(assetEntity, "bookingItem", bookingItemValidation::validate),
|
validateReferencedEntity(assetEntity, "bookingItem", bookingItemReferenceValidation::validate),
|
||||||
validateReferencedEntity(assetEntity, "parentAsset", parentAssetValidation::validate),
|
validateReferencedEntity(assetEntity, "parentAsset", parentAssetReferenceValidation::validate),
|
||||||
validateReferencedEntity(assetEntity, "assignedToAsset", assignedToAssetValidation::validate),
|
validateReferencedEntity(assetEntity, "assignedToAsset", assignedToAssetReferenceValidation::validate),
|
||||||
validateReferencedEntity(assetEntity, "alarmContact", alarmContactValidation::validate),
|
validateReferencedEntity(assetEntity, "alarmContact", alarmContactValidation::validate),
|
||||||
validateProperties(assetEntity))
|
validateProperties(assetEntity))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
@ -87,20 +96,23 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
|
|||||||
|
|
||||||
private static List<String> optionallyValidate(final HsHostingAssetEntity assetEntity) {
|
private static List<String> optionallyValidate(final HsHostingAssetEntity assetEntity) {
|
||||||
return assetEntity != null
|
return assetEntity != null
|
||||||
? enrich(prefix(assetEntity.toShortString(), "parentAsset"),
|
? enrich(
|
||||||
|
prefix(assetEntity.toShortString(), "parentAsset"),
|
||||||
HsHostingAssetEntityValidatorRegistry.forType(assetEntity.getType()).validateContext(assetEntity))
|
HsHostingAssetEntityValidatorRegistry.forType(assetEntity.getType()).validateContext(assetEntity))
|
||||||
: emptyList();
|
: emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> optionallyValidate(final HsBookingItemEntity bookingItem) {
|
private static List<String> optionallyValidate(final HsBookingItemEntity bookingItem) {
|
||||||
return bookingItem != null
|
return bookingItem != null
|
||||||
? enrich(prefix(bookingItem.toShortString(), "bookingItem"),
|
? enrich(
|
||||||
|
prefix(bookingItem.toShortString(), "bookingItem"),
|
||||||
HsBookingItemEntityValidatorRegistry.forType(bookingItem.getType()).validateContext(bookingItem))
|
HsBookingItemEntityValidatorRegistry.forType(bookingItem.getType()).validateContext(bookingItem))
|
||||||
: emptyList();
|
: emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> validateAgainstSubEntities(final HsHostingAssetEntity assetEntity) {
|
protected List<String> validateAgainstSubEntities(final HsHostingAssetEntity assetEntity) {
|
||||||
return enrich(prefix(assetEntity.toShortString(), "config"),
|
return enrich(
|
||||||
|
prefix(assetEntity.toShortString(), "config"),
|
||||||
stream(propertyValidators)
|
stream(propertyValidators)
|
||||||
.filter(ValidatableProperty::isTotalsValidator)
|
.filter(ValidatableProperty::isTotalsValidator)
|
||||||
.map(prop -> validateMaxTotalValue(assetEntity, prop))
|
.map(prop -> validateMaxTotalValue(assetEntity, prop))
|
||||||
@ -130,114 +142,79 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
|
|||||||
final var expectedIdentifierPattern = identifierPattern(assetEntity);
|
final var expectedIdentifierPattern = identifierPattern(assetEntity);
|
||||||
if (assetEntity.getIdentifier() == null ||
|
if (assetEntity.getIdentifier() == null ||
|
||||||
!expectedIdentifierPattern.matcher(assetEntity.getIdentifier()).matches()) {
|
!expectedIdentifierPattern.matcher(assetEntity.getIdentifier()).matches()) {
|
||||||
return List.of("'identifier' expected to match '"+expectedIdentifierPattern+"', but is '" + assetEntity.getIdentifier() + "'");
|
return List.of(
|
||||||
|
"'identifier' expected to match '" + expectedIdentifierPattern + "', but is '" + assetEntity.getIdentifier()
|
||||||
|
+ "'");
|
||||||
}
|
}
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Pattern identifierPattern(HsHostingAssetEntity assetEntity);
|
protected abstract Pattern identifierPattern(HsHostingAssetEntity assetEntity);
|
||||||
|
|
||||||
static abstract class ReferenceValidator<S, T> {
|
static class ReferenceValidator<S, T> {
|
||||||
|
|
||||||
private final Policy policy;
|
private final HsHostingAssetType.RelationPolicy policy;
|
||||||
private final T subEntityType;
|
private final T referencedEntityType;
|
||||||
private final Function<HsHostingAssetEntity, S> subEntityGetter;
|
private final Function<HsHostingAssetEntity, S> referencedEntityGetter;
|
||||||
private final Function<S,T> subEntityTypeGetter;
|
private final Function<S, T> referencedEntityTypeGetter;
|
||||||
|
|
||||||
public ReferenceValidator(
|
public ReferenceValidator(
|
||||||
final Policy policy,
|
final HsHostingAssetType.RelationPolicy policy,
|
||||||
final T subEntityType,
|
final T subEntityType,
|
||||||
final Function<HsHostingAssetEntity, S> subEntityGetter,
|
final Function<HsHostingAssetEntity, S> referencedEntityGetter,
|
||||||
final Function<S, T> subEntityTypeGetter) {
|
final Function<S, T> referencedEntityTypeGetter) {
|
||||||
this.policy = policy;
|
this.policy = policy;
|
||||||
this.subEntityType = subEntityType;
|
this.referencedEntityType = subEntityType;
|
||||||
this.subEntityGetter = subEntityGetter;
|
this.referencedEntityGetter = referencedEntityGetter;
|
||||||
this.subEntityTypeGetter = subEntityTypeGetter;
|
this.referencedEntityTypeGetter = referencedEntityTypeGetter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReferenceValidator(
|
public ReferenceValidator(
|
||||||
final Policy policy,
|
final HsHostingAssetType.RelationPolicy policy,
|
||||||
final Function<HsHostingAssetEntity, S> subEntityGetter) {
|
final Function<HsHostingAssetEntity, S> referencedEntityGetter) {
|
||||||
this.policy = policy;
|
this.policy = policy;
|
||||||
this.subEntityType = null;
|
this.referencedEntityType = null;
|
||||||
this.subEntityGetter = subEntityGetter;
|
this.referencedEntityGetter = referencedEntityGetter;
|
||||||
this.subEntityTypeGetter = e -> null;
|
this.referencedEntityTypeGetter = e -> null;
|
||||||
}
|
|
||||||
|
|
||||||
enum Policy {
|
|
||||||
OPTIONAL, FORBIDDEN, REQUIRED
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> validate(final HsHostingAssetEntity assetEntity, final String referenceFieldName) {
|
List<String> validate(final HsHostingAssetEntity assetEntity, final String referenceFieldName) {
|
||||||
|
|
||||||
final var subEntity = subEntityGetter.apply(assetEntity);
|
final var actualEntity = referencedEntityGetter.apply(assetEntity);
|
||||||
if (policy == Policy.REQUIRED && subEntity == null) {
|
final var actualEntityType = actualEntity != null ? referencedEntityTypeGetter.apply(actualEntity) : null;
|
||||||
return List.of(referenceFieldName + "' must not be null but is null");
|
|
||||||
|
switch (policy) {
|
||||||
|
case REQUIRED:
|
||||||
|
if (actualEntityType != referencedEntityType) {
|
||||||
|
return List.of(actualEntityType == null
|
||||||
|
? referenceFieldName + "' must be of type " + referencedEntityType + " but is null"
|
||||||
|
: referenceFieldName + "' must be of type " + referencedEntityType + " but is of type " + actualEntityType);
|
||||||
}
|
}
|
||||||
if (policy == Policy.FORBIDDEN && subEntity != null) {
|
break;
|
||||||
return List.of(referenceFieldName + "' must be null but is set to "+ assetEntity.getBookingItem().toShortString());
|
case OPTIONAL:
|
||||||
|
if (actualEntityType != null && actualEntityType != referencedEntityType) {
|
||||||
|
return List.of(referenceFieldName + "' must be null or of type " + referencedEntityType + " but is of type "
|
||||||
|
+ actualEntityType);
|
||||||
}
|
}
|
||||||
final var subItemType = subEntity != null ? subEntityTypeGetter.apply(subEntity) : null;
|
break;
|
||||||
if (subEntityType != null && subItemType != subEntityType) {
|
case FORBIDDEN:
|
||||||
return List.of(referenceFieldName + "' must be of type " + subEntityType + " but is of type " + subItemType);
|
if (actualEntityType != null) {
|
||||||
|
return List.of(referenceFieldName + "' must be null but is of type " + actualEntityType);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class BookingItem extends ReferenceValidator<HsBookingItemEntity, HsBookingItemType> {
|
|
||||||
|
|
||||||
BookingItem(final Policy policy, final HsBookingItemType bookingItemType) {
|
|
||||||
super(policy, bookingItemType, HsHostingAssetEntity::getBookingItem, HsBookingItemEntity::getType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BookingItem mustBeNull() {
|
|
||||||
return new BookingItem(Policy.FORBIDDEN, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BookingItem mustBeOfType(final HsBookingItemType hsBookingItemType) {
|
|
||||||
return new BookingItem(Policy.REQUIRED, hsBookingItemType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ParentAsset extends ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> {
|
|
||||||
|
|
||||||
ParentAsset(final ReferenceValidator.Policy policy, final HsHostingAssetType parentAssetType) {
|
|
||||||
super(policy, parentAssetType, HsHostingAssetEntity::getParentAsset, HsHostingAssetEntity::getType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ParentAsset mustBeNull() {
|
|
||||||
return new ParentAsset(Policy.FORBIDDEN, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ParentAsset mustBeOfType(final HsHostingAssetType hostingAssetType) {
|
|
||||||
return new ParentAsset(Policy.REQUIRED, hostingAssetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ParentAsset mustBeNullOrOfType(final HsHostingAssetType hostingAssetType) {
|
|
||||||
return new ParentAsset(Policy.OPTIONAL, hostingAssetType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class AssignedToAsset extends ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> {
|
|
||||||
|
|
||||||
AssignedToAsset(final ReferenceValidator.Policy policy, final HsHostingAssetType assignedToAssetType) {
|
|
||||||
super(policy, assignedToAssetType, HsHostingAssetEntity::getAssignedToAsset, HsHostingAssetEntity::getType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static AssignedToAsset mustBeNull() {
|
|
||||||
return new AssignedToAsset(Policy.FORBIDDEN, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class AlarmContact extends ReferenceValidator<HsOfficeContactEntity, Enum<?>> {
|
static class AlarmContact extends ReferenceValidator<HsOfficeContactEntity, Enum<?>> {
|
||||||
|
|
||||||
AlarmContact(final ReferenceValidator.Policy policy) {
|
AlarmContact(final HsHostingAssetType.RelationPolicy policy) {
|
||||||
super(policy, HsHostingAssetEntity::getAlarmContact);
|
super(policy, HsHostingAssetEntity::getAlarmContact);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AlarmContact isOptional() {
|
static AlarmContact isOptional() {
|
||||||
return new AlarmContact(Policy.OPTIONAL);
|
return new AlarmContact(HsHostingAssetType.RelationPolicy.OPTIONAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
|
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
||||||
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
|
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.EnumerationProperty.enumerationProperty;
|
||||||
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
|
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
|
||||||
@ -13,9 +13,7 @@ class HsManagedServerHostingAssetValidator extends HsHostingAssetEntityValidator
|
|||||||
|
|
||||||
public HsManagedServerHostingAssetValidator() {
|
public HsManagedServerHostingAssetValidator() {
|
||||||
super(
|
super(
|
||||||
BookingItem.mustBeOfType(HsBookingItemType.MANAGED_SERVER),
|
MANAGED_SERVER,
|
||||||
ParentAsset.mustBeNull(), // until we introduce a hosting asset for 'HOST'
|
|
||||||
AssignedToAsset.mustBeNull(),
|
|
||||||
AlarmContact.isOptional(), // hostmaster alert address is implicitly added
|
AlarmContact.isOptional(), // hostmaster alert address is implicitly added
|
||||||
|
|
||||||
// monitoring
|
// monitoring
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
|
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
|
||||||
|
|
||||||
class HsManagedWebspaceHostingAssetValidator extends HsHostingAssetEntityValidator {
|
class HsManagedWebspaceHostingAssetValidator extends HsHostingAssetEntityValidator {
|
||||||
public HsManagedWebspaceHostingAssetValidator() {
|
public HsManagedWebspaceHostingAssetValidator() {
|
||||||
super(BookingItem.mustBeOfType(HsBookingItemType.MANAGED_WEBSPACE),
|
super(
|
||||||
ParentAsset.mustBeOfType(HsHostingAssetType.MANAGED_SERVER), // the (shared or private) ManagedServer
|
MANAGED_WEBSPACE,
|
||||||
AssignedToAsset.mustBeNull(),
|
|
||||||
AlarmContact.isOptional(), // hostmaster alert address is implicitly added
|
AlarmContact.isOptional(), // hostmaster alert address is implicitly added
|
||||||
NO_EXTRA_PROPERTIES);
|
NO_EXTRA_PROPERTIES);
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,8 @@ class HsUnixUserHostingAssetValidator extends HsHostingAssetEntityValidator {
|
|||||||
private static final int DASH_LENGTH = "-".length();
|
private static final int DASH_LENGTH = "-".length();
|
||||||
|
|
||||||
HsUnixUserHostingAssetValidator() {
|
HsUnixUserHostingAssetValidator() {
|
||||||
super( BookingItem.mustBeNull(),
|
super(
|
||||||
ParentAsset.mustBeOfType(HsHostingAssetType.MANAGED_WEBSPACE),
|
HsHostingAssetType.UNIX_USER,
|
||||||
AssignedToAsset.mustBeNull(),
|
|
||||||
AlarmContact.isOptional(),
|
AlarmContact.isOptional(),
|
||||||
|
|
||||||
integerProperty("SSD hard quota").unit("GB").maxFrom("SSD").optional(),
|
integerProperty("SSD hard quota").unit("GB").maxFrom("SSD").optional(),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.hostsharing.hsadminng.hs.validation;
|
package net.hostsharing.hsadminng.hs.validation;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -18,7 +19,7 @@ public abstract class HsEntityValidator<E extends PropertiesProvider> {
|
|||||||
|
|
||||||
public final ValidatableProperty<?, ?>[] propertyValidators;
|
public final ValidatableProperty<?, ?>[] propertyValidators;
|
||||||
|
|
||||||
public HsEntityValidator(final ValidatableProperty<?, ?>... validators) {
|
public <T extends Enum <T>> HsEntityValidator(final ValidatableProperty<?, ?>... validators) {
|
||||||
propertyValidators = validators;
|
propertyValidators = validators;
|
||||||
stream(propertyValidators).forEach(p -> p.deferredInit(propertyValidators));
|
stream(propertyValidators).forEach(p -> p.deferredInit(propertyValidators));
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ create or replace function cleanIdentifier(rawIdentifier varchar)
|
|||||||
declare
|
declare
|
||||||
cleanIdentifier varchar;
|
cleanIdentifier varchar;
|
||||||
begin
|
begin
|
||||||
cleanIdentifier := regexp_replace(rawIdentifier, '[^A-Za-z0-9\-._]+', '', 'g');
|
cleanIdentifier := regexp_replace(rawIdentifier, '[^A-Za-z0-9\-._|]+', '', 'g');
|
||||||
return cleanIdentifier;
|
return cleanIdentifier;
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
|
@ -36,9 +36,9 @@ subgraph asset["`**asset**`"]
|
|||||||
style asset:permissions fill:#dd4901,stroke:white
|
style asset:permissions fill:#dd4901,stroke:white
|
||||||
|
|
||||||
perm:asset:INSERT{{asset:INSERT}}
|
perm:asset:INSERT{{asset:INSERT}}
|
||||||
perm:asset:SELECT{{asset:SELECT}}
|
|
||||||
perm:asset:DELETE{{asset:DELETE}}
|
perm:asset:DELETE{{asset:DELETE}}
|
||||||
perm:asset:UPDATE{{asset:UPDATE}}
|
perm:asset:UPDATE{{asset:UPDATE}}
|
||||||
|
perm:asset:SELECT{{asset:SELECT}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -80,6 +80,9 @@ subgraph parentAsset["`**parentAsset**`"]
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
%% granting roles to users
|
||||||
|
user:creator ==> role:asset:OWNER
|
||||||
|
|
||||||
%% granting roles to roles
|
%% granting roles to roles
|
||||||
role:bookingItem:OWNER -.-> role:bookingItem:ADMIN
|
role:bookingItem:OWNER -.-> role:bookingItem:ADMIN
|
||||||
role:bookingItem:ADMIN -.-> role:bookingItem:AGENT
|
role:bookingItem:ADMIN -.-> role:bookingItem:AGENT
|
||||||
@ -87,6 +90,7 @@ role:bookingItem:AGENT -.-> role:bookingItem:TENANT
|
|||||||
role:global:ADMIN -.-> role:alarmContact:OWNER
|
role:global:ADMIN -.-> role:alarmContact:OWNER
|
||||||
role:alarmContact:OWNER -.-> role:alarmContact:ADMIN
|
role:alarmContact:OWNER -.-> role:alarmContact:ADMIN
|
||||||
role:alarmContact:ADMIN -.-> role:alarmContact:REFERRER
|
role:alarmContact:ADMIN -.-> role:alarmContact:REFERRER
|
||||||
|
role:global:ADMIN ==>|XX| role:asset:OWNER
|
||||||
role:bookingItem:ADMIN ==> role:asset:OWNER
|
role:bookingItem:ADMIN ==> role:asset:OWNER
|
||||||
role:parentAsset:ADMIN ==> role:asset:OWNER
|
role:parentAsset:ADMIN ==> role:asset:OWNER
|
||||||
role:asset:OWNER ==> role:asset:ADMIN
|
role:asset:OWNER ==> role:asset:ADMIN
|
||||||
@ -104,7 +108,6 @@ role:alarmContact:ADMIN ==> role:asset:TENANT
|
|||||||
role:global:ADMIN ==> perm:asset:INSERT
|
role:global:ADMIN ==> perm:asset:INSERT
|
||||||
role:parentAsset:ADMIN ==> perm:asset:INSERT
|
role:parentAsset:ADMIN ==> perm:asset:INSERT
|
||||||
role:global:GUEST ==> perm:asset:INSERT
|
role:global:GUEST ==> perm:asset:INSERT
|
||||||
role:global:ADMIN ==> perm:asset:SELECT
|
|
||||||
role:asset:OWNER ==> perm:asset:DELETE
|
role:asset:OWNER ==> perm:asset:DELETE
|
||||||
role:asset:ADMIN ==> perm:asset:UPDATE
|
role:asset:ADMIN ==> perm:asset:UPDATE
|
||||||
role:asset:TENANT ==> perm:asset:SELECT
|
role:asset:TENANT ==> perm:asset:SELECT
|
||||||
|
@ -50,8 +50,10 @@ begin
|
|||||||
hsHostingAssetOWNER(NEW),
|
hsHostingAssetOWNER(NEW),
|
||||||
permissions => array['DELETE'],
|
permissions => array['DELETE'],
|
||||||
incomingSuperRoles => array[
|
incomingSuperRoles => array[
|
||||||
|
globalADMIN(unassumed()),
|
||||||
hsBookingItemADMIN(newBookingItem),
|
hsBookingItemADMIN(newBookingItem),
|
||||||
hsHostingAssetADMIN(newParentAsset)]
|
hsHostingAssetADMIN(newParentAsset)],
|
||||||
|
userUuids => array[currentUserUuid()]
|
||||||
);
|
);
|
||||||
|
|
||||||
perform createRoleWithGrants(
|
perform createRoleWithGrants(
|
||||||
@ -85,10 +87,6 @@ begin
|
|||||||
IF NEW.type = 'DOMAIN_SETUP' THEN
|
IF NEW.type = 'DOMAIN_SETUP' THEN
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
call grantPermissionToRole(createPermission(NEW.uuid, 'SELECT'), globalAdmin());
|
|
||||||
|
|
||||||
call leaveTriggerForObjectUuid(NEW.uuid);
|
call leaveTriggerForObjectUuid(NEW.uuid);
|
||||||
end; $$;
|
end; $$;
|
||||||
|
|
||||||
|
@ -78,8 +78,8 @@ begin
|
|||||||
(uuid_generate_v4(), null, 'EMAIL_ALIAS', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some E-Mail-Alias', '{ "target": [ "office@example.org", "archive@example.com" ] }'::jsonb),
|
(uuid_generate_v4(), null, 'EMAIL_ALIAS', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some E-Mail-Alias', '{ "target": [ "office@example.org", "archive@example.com" ] }'::jsonb),
|
||||||
(webUnixUserUuid, null, 'UNIX_USER', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some UnixUser for Website', '{ "SSD-soft-quota": "128", "SSD-hard-quota": "256", "HDD-soft-quota": "512", "HDD-hard-quota": "1024"}'::jsonb),
|
(webUnixUserUuid, null, 'UNIX_USER', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some UnixUser for Website', '{ "SSD-soft-quota": "128", "SSD-hard-quota": "256", "HDD-soft-quota": "512", "HDD-hard-quota": "1024"}'::jsonb),
|
||||||
(domainSetupUuid, null, 'DOMAIN_SETUP', null, null, defaultPrefix || '.example.org', 'some Domain-Setup', '{}'::jsonb),
|
(domainSetupUuid, null, 'DOMAIN_SETUP', null, null, defaultPrefix || '.example.org', 'some Domain-Setup', '{}'::jsonb),
|
||||||
(uuid_generate_v4(), null, 'DOMAIN_DNS_SETUP', domainSetupUuid, null, defaultPrefix || '.example.org', 'some Domain-DNS-Setup', '{}'::jsonb),
|
(uuid_generate_v4(), null, 'DOMAIN_DNS_SETUP', domainSetupUuid, null, defaultPrefix || '.example.org|DNS', 'some Domain-DNS-Setup', '{}'::jsonb),
|
||||||
(uuid_generate_v4(), null, 'DOMAIN_HTTP_SETUP', domainSetupUuid, webUnixUserUuid, defaultPrefix || '.example.org', 'some Domain-HTTP-Setup', '{ "option-htdocsfallback": true, "use-fcgiphpbin": "/usr/lib/cgi-bin/php", "validsubdomainnames": "*"}'::jsonb);
|
(uuid_generate_v4(), null, 'DOMAIN_HTTP_SETUP', domainSetupUuid, webUnixUserUuid, defaultPrefix || '.example.org|HTTP', 'some Domain-HTTP-Setup', '{ "option-htdocsfallback": true, "use-fcgiphpbin": "/usr/lib/cgi-bin/php", "validsubdomainnames": "*"}'::jsonb);
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -40,8 +40,10 @@ public class ArchitectureTest {
|
|||||||
"..test.pac",
|
"..test.pac",
|
||||||
"..test.dom",
|
"..test.dom",
|
||||||
"..context",
|
"..context",
|
||||||
|
"..hash",
|
||||||
"..generated..",
|
"..generated..",
|
||||||
"..persistence..",
|
"..persistence..",
|
||||||
|
"..system..",
|
||||||
"..validation..",
|
"..validation..",
|
||||||
"..hs.office.bankaccount",
|
"..hs.office.bankaccount",
|
||||||
"..hs.office.contact",
|
"..hs.office.contact",
|
||||||
@ -110,6 +112,13 @@ public class ArchitectureTest {
|
|||||||
.should().onlyDependOnClassesThat()
|
.should().onlyDependOnClassesThat()
|
||||||
.resideOutsideOfPackage(NET_HOSTSHARING_HSADMINNG);
|
.resideOutsideOfPackage(NET_HOSTSHARING_HSADMINNG);
|
||||||
|
|
||||||
|
@ArchTest
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static final ArchRule hashPackageRule = classes()
|
||||||
|
.that().resideInAPackage("..hash..")
|
||||||
|
.should().onlyDependOnClassesThat()
|
||||||
|
.resideOutsideOfPackage(NET_HOSTSHARING_HSADMINNG);
|
||||||
|
|
||||||
@ArchTest
|
@ArchTest
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static final ArchRule errorsPackageRule = classes()
|
public static final ArchRule errorsPackageRule = classes()
|
||||||
@ -117,6 +126,13 @@ public class ArchitectureTest {
|
|||||||
.should().onlyDependOnClassesThat()
|
.should().onlyDependOnClassesThat()
|
||||||
.resideOutsideOfPackage(NET_HOSTSHARING_HSADMINNG);
|
.resideOutsideOfPackage(NET_HOSTSHARING_HSADMINNG);
|
||||||
|
|
||||||
|
@ArchTest
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public static final ArchRule systemPackageRule = classes()
|
||||||
|
.that().resideInAPackage("..system..")
|
||||||
|
.should().onlyDependOnClassesThat()
|
||||||
|
.resideOutsideOfPackage(NET_HOSTSHARING_HSADMINNG);
|
||||||
|
|
||||||
@ArchTest
|
@ArchTest
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static final ArchRule testPackagesRule = classes()
|
public static final ArchRule testPackagesRule = classes()
|
||||||
|
@ -152,7 +152,7 @@ class HsManagedServerBookingItemValidatorUnitTest {
|
|||||||
"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_MAILBOX_SETUP,
|
||||||
"%c%c.example.com",
|
"%c%c.example.com",
|
||||||
10, HsHostingAssetType.EMAIL_ADDRESS
|
10, HsHostingAssetType.EMAIL_ADDRESS
|
||||||
)
|
)
|
||||||
|
@ -235,6 +235,47 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
assertThat(newUserUuid).isNotNull();
|
assertThat(newUserUuid).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_canAddTopLevelAsset() {
|
||||||
|
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
|
||||||
|
final var location = RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("""
|
||||||
|
{
|
||||||
|
"type": "DOMAIN_SETUP",
|
||||||
|
"identifier": "example.com",
|
||||||
|
"caption": "some unrelated domain-setup",
|
||||||
|
"config": {}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.post("http://localhost/api/hs/hosting/assets")
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(201)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("", lenientlyEquals("""
|
||||||
|
{
|
||||||
|
"type": "DOMAIN_SETUP",
|
||||||
|
"identifier": "example.com",
|
||||||
|
"caption": "some unrelated domain-setup",
|
||||||
|
"config": {}
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.header("Location", matchesRegex("http://localhost:[1-9][0-9]*/api/hs/hosting/assets/[^/]*"))
|
||||||
|
.extract().header("Location"); // @formatter:on
|
||||||
|
|
||||||
|
// finally, the new asset can be accessed under the generated UUID
|
||||||
|
final var newWebspace = UUID.fromString(
|
||||||
|
location.substring(location.lastIndexOf('/') + 1));
|
||||||
|
assertThat(newWebspace).isNotNull();
|
||||||
|
toCleanup(HsHostingAssetEntity.class, newWebspace);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void propertyValidationsArePerformend_whenAddingAsset() {
|
void propertyValidationsArePerformend_whenAddingAsset() {
|
||||||
|
|
||||||
|
@ -131,9 +131,10 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
|||||||
initialGrantNames,
|
initialGrantNames,
|
||||||
|
|
||||||
// global-admin
|
// global-admin
|
||||||
"{ grant perm:hs_hosting_asset#fir00:SELECT to role:global#global:ADMIN by system and assume }", // workaround
|
"{ grant role:hs_hosting_asset#fir00:OWNER to role:global#global:ADMIN by system }", // workaround
|
||||||
|
|
||||||
// owner
|
// owner
|
||||||
|
"{ grant role:hs_hosting_asset#fir00:OWNER to user:superuser-alex@hostsharing.net by hs_hosting_asset#fir00:OWNER and assume }",
|
||||||
"{ grant role:hs_hosting_asset#fir00:OWNER to role:hs_booking_item#fir01:ADMIN by system and assume }",
|
"{ grant role:hs_hosting_asset#fir00:OWNER to role:hs_booking_item#fir01:ADMIN by system and assume }",
|
||||||
"{ grant role:hs_hosting_asset#fir00:OWNER to role:hs_hosting_asset#vm1011:ADMIN by system and assume }",
|
"{ grant role:hs_hosting_asset#fir00:OWNER to role:hs_hosting_asset#vm1011:ADMIN by system and assume }",
|
||||||
"{ grant perm:hs_hosting_asset#fir00:DELETE to role:hs_hosting_asset#fir00:OWNER by system and assume }",
|
"{ grant perm:hs_hosting_asset#fir00:DELETE to role:hs_hosting_asset#fir00:OWNER by system and assume }",
|
||||||
@ -158,37 +159,38 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void anyUser_canCreateNewDomainSetupAsset() {
|
public void anyUser_canCreateNewDomainSetupAsset() {
|
||||||
// given
|
|
||||||
context("superuser-alex@hostsharing.net");
|
|
||||||
final var assetCount = assetRepo.count();
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
context("person-SmithPeter@example.com");
|
context("person-SmithPeter@example.com");
|
||||||
final var result = attempt(em, () -> {
|
final var result = attempt(em, () -> {
|
||||||
final var newAsset = HsHostingAssetEntity.builder()
|
final var newAsset = HsHostingAssetEntity.builder()
|
||||||
.caption("some new domain setup")
|
|
||||||
.type(DOMAIN_SETUP)
|
.type(DOMAIN_SETUP)
|
||||||
.identifier("example.org")
|
.identifier("example.net")
|
||||||
|
.caption("some new domain setup")
|
||||||
.build();
|
.build();
|
||||||
return toCleanup(assetRepo.save(newAsset));
|
return assetRepo.save(newAsset);
|
||||||
});
|
});
|
||||||
|
|
||||||
// then
|
// then
|
||||||
|
// ... the domain setup was created and returned
|
||||||
result.assertSuccessful();
|
result.assertSuccessful();
|
||||||
assertThat(result.returnedValue()).isNotNull().extracting(HsHostingAssetEntity::getUuid).isNotNull();
|
assertThat(result.returnedValue()).isNotNull().extracting(HsHostingAssetEntity::getUuid).isNotNull();
|
||||||
assertThat(result.returnedValue().isLoaded()).isFalse();
|
assertThat(result.returnedValue().isLoaded()).isFalse();
|
||||||
context("superuser-alex@hostsharing.net");
|
|
||||||
|
// ... the creating user can read the new domain setup
|
||||||
|
context("person-SmithPeter@example.com");
|
||||||
|
assertThatAssetIsPersisted(result.returnedValue());
|
||||||
|
|
||||||
|
// ... a global admin can see the new domain setup as well if the domain OWNER role is assumed
|
||||||
|
context("superuser-alex@hostsharing.net", "hs_hosting_asset#example.net:OWNER"); // only works with the assumed role
|
||||||
assertThatAssetIsPersisted(result.returnedValue());
|
assertThatAssetIsPersisted(result.returnedValue());
|
||||||
assertThat(assetRepo.count()).isEqualTo(assetCount + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertThatAssetIsPersisted(final HsHostingAssetEntity saved) {
|
private void assertThatAssetIsPersisted(final HsHostingAssetEntity saved) {
|
||||||
final var context =
|
em.clear();
|
||||||
attempt(em, () -> {
|
attempt(em, () -> {
|
||||||
final var found = assetRepo.findByUuid(saved.getUuid());
|
final var found = assetRepo.findByUuid(saved.getUuid());
|
||||||
assertThat(found).isNotEmpty().map(HsHostingAssetEntity::toString).get().isEqualTo(saved.toString());
|
assertThat(found).isNotEmpty().map(HsHostingAssetEntity::toString).contains(saved.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,219 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class HsHostingAssetTypeUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generatedPlantUML() {
|
||||||
|
final var result = HsHostingAssetType.renderAsEmbeddedPlantUml();
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo("""
|
||||||
|
## HostingAsset Type Structure
|
||||||
|
|
||||||
|
|
||||||
|
### Domain
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
left to right direction
|
||||||
|
|
||||||
|
package Booking #feb28c {
|
||||||
|
entity BI_PRIVATE_CLOUD
|
||||||
|
entity BI_CLOUD_SERVER
|
||||||
|
entity BI_MANAGED_SERVER
|
||||||
|
entity BI_MANAGED_WEBSPACE
|
||||||
|
entity BI_DOMAIN_DNS_SETUP
|
||||||
|
entity BI_DOMAIN_EMAIL_SUBMISSION_SETUP
|
||||||
|
}
|
||||||
|
|
||||||
|
package Hosting #feb28c{
|
||||||
|
package Domain #99bcdb {
|
||||||
|
entity HA_DOMAIN_SETUP
|
||||||
|
entity HA_DOMAIN_DNS_SETUP
|
||||||
|
entity HA_DOMAIN_HTTP_SETUP
|
||||||
|
entity HA_DOMAIN_EMAIL_SUBMISSION_SETUP
|
||||||
|
entity HA_DOMAIN_EMAIL_MAILBOX_SETUP
|
||||||
|
entity HA_EMAIL_ADDRESS
|
||||||
|
}
|
||||||
|
|
||||||
|
package Server #99bcdb {
|
||||||
|
entity HA_CLOUD_SERVER
|
||||||
|
entity HA_MANAGED_SERVER
|
||||||
|
entity HA_IP_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
package Webspace #99bcdb {
|
||||||
|
entity HA_MANAGED_WEBSPACE
|
||||||
|
entity HA_UNIX_USER
|
||||||
|
entity HA_EMAIL_ALIAS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
|
||||||
|
|
||||||
|
HA_CLOUD_SERVER *==> BI_CLOUD_SERVER
|
||||||
|
HA_MANAGED_SERVER *==> BI_MANAGED_SERVER
|
||||||
|
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
|
||||||
|
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
|
||||||
|
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_DOMAIN_SETUP o..> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_DNS_SETUP *==> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_HTTP_SETUP *==> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_HTTP_SETUP o..> HA_UNIX_USER
|
||||||
|
HA_DOMAIN_EMAIL_SUBMISSION_SETUP *==> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_EMAIL_SUBMISSION_SETUP o..> HA_MANAGED_WEBSPACE
|
||||||
|
HA_DOMAIN_EMAIL_MAILBOX_SETUP *==> HA_DOMAIN_SETUP
|
||||||
|
HA_DOMAIN_EMAIL_MAILBOX_SETUP o..> HA_MANAGED_WEBSPACE
|
||||||
|
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_EMAIL_ADDRESS *==> HA_DOMAIN_EMAIL_MAILBOX_SETUP
|
||||||
|
HA_IP_NUMBER o..> HA_CLOUD_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
|
||||||
|
|
||||||
|
package Legend #white {
|
||||||
|
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
|
||||||
|
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
|
||||||
|
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
|
||||||
|
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
|
||||||
|
}
|
||||||
|
Booking -down[hidden]->Legend
|
||||||
|
```
|
||||||
|
|
||||||
|
### MariaDB
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
left to right direction
|
||||||
|
|
||||||
|
package Booking #feb28c {
|
||||||
|
entity BI_PRIVATE_CLOUD
|
||||||
|
entity BI_CLOUD_SERVER
|
||||||
|
entity BI_MANAGED_SERVER
|
||||||
|
entity BI_MANAGED_WEBSPACE
|
||||||
|
entity BI_DOMAIN_DNS_SETUP
|
||||||
|
entity BI_DOMAIN_EMAIL_SUBMISSION_SETUP
|
||||||
|
}
|
||||||
|
|
||||||
|
package Hosting #feb28c{
|
||||||
|
package MariaDB #99bcdb {
|
||||||
|
entity HA_MARIADB_INSTANCE
|
||||||
|
entity HA_MARIADB_USER
|
||||||
|
entity HA_MARIADB_DATABASE
|
||||||
|
}
|
||||||
|
|
||||||
|
package Server #99bcdb {
|
||||||
|
entity HA_CLOUD_SERVER
|
||||||
|
entity HA_MANAGED_SERVER
|
||||||
|
entity HA_IP_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
package Webspace #99bcdb {
|
||||||
|
entity HA_MANAGED_WEBSPACE
|
||||||
|
entity HA_UNIX_USER
|
||||||
|
entity HA_EMAIL_ALIAS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
|
||||||
|
|
||||||
|
HA_CLOUD_SERVER *==> BI_CLOUD_SERVER
|
||||||
|
HA_MANAGED_SERVER *==> BI_MANAGED_SERVER
|
||||||
|
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
|
||||||
|
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
|
||||||
|
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_MARIADB_INSTANCE *==> HA_MANAGED_SERVER
|
||||||
|
HA_MARIADB_USER *==> HA_MARIADB_INSTANCE
|
||||||
|
HA_MARIADB_USER o..> HA_MANAGED_WEBSPACE
|
||||||
|
HA_MARIADB_DATABASE *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_MARIADB_DATABASE o..> HA_MARIADB_INSTANCE
|
||||||
|
HA_IP_NUMBER o..> HA_CLOUD_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
|
||||||
|
|
||||||
|
package Legend #white {
|
||||||
|
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
|
||||||
|
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
|
||||||
|
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
|
||||||
|
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
|
||||||
|
}
|
||||||
|
Booking -down[hidden]->Legend
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL
|
||||||
|
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
left to right direction
|
||||||
|
|
||||||
|
package Booking #feb28c {
|
||||||
|
entity BI_PRIVATE_CLOUD
|
||||||
|
entity BI_CLOUD_SERVER
|
||||||
|
entity BI_MANAGED_SERVER
|
||||||
|
entity BI_MANAGED_WEBSPACE
|
||||||
|
entity BI_DOMAIN_DNS_SETUP
|
||||||
|
entity BI_DOMAIN_EMAIL_SUBMISSION_SETUP
|
||||||
|
}
|
||||||
|
|
||||||
|
package Hosting #feb28c{
|
||||||
|
package PostgreSQL #99bcdb {
|
||||||
|
entity HA_PGSQL_INSTANCE
|
||||||
|
entity HA_PGSQL_USER
|
||||||
|
entity HA_PGSQL_DATABASE
|
||||||
|
}
|
||||||
|
|
||||||
|
package Server #99bcdb {
|
||||||
|
entity HA_CLOUD_SERVER
|
||||||
|
entity HA_MANAGED_SERVER
|
||||||
|
entity HA_IP_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
package Webspace #99bcdb {
|
||||||
|
entity HA_MANAGED_WEBSPACE
|
||||||
|
entity HA_UNIX_USER
|
||||||
|
entity HA_EMAIL_ALIAS
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
|
||||||
|
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
|
||||||
|
|
||||||
|
HA_CLOUD_SERVER *==> BI_CLOUD_SERVER
|
||||||
|
HA_MANAGED_SERVER *==> BI_MANAGED_SERVER
|
||||||
|
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
|
||||||
|
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
|
||||||
|
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_PGSQL_INSTANCE *==> HA_MANAGED_SERVER
|
||||||
|
HA_PGSQL_USER *==> HA_PGSQL_INSTANCE
|
||||||
|
HA_PGSQL_USER o..> HA_MANAGED_WEBSPACE
|
||||||
|
HA_PGSQL_DATABASE *==> HA_MANAGED_WEBSPACE
|
||||||
|
HA_PGSQL_DATABASE o..> HA_PGSQL_INSTANCE
|
||||||
|
HA_IP_NUMBER o..> HA_CLOUD_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_SERVER
|
||||||
|
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
|
||||||
|
|
||||||
|
package Legend #white {
|
||||||
|
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
|
||||||
|
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
|
||||||
|
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
|
||||||
|
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
|
||||||
|
}
|
||||||
|
Booking -down[hidden]->Legend
|
||||||
|
```
|
||||||
|
|
||||||
|
This code generated was by HsHostingAssetType.main, do not amend manually.
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ class HsCloudServerHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrder(
|
assertThat(result).containsExactlyInAnyOrder(
|
||||||
"'CLOUD_SERVER:vm1234.bookingItem' must not be null but is null",
|
"'CLOUD_SERVER:vm1234.bookingItem' must be of type CLOUD_SERVER but is null",
|
||||||
"'CLOUD_SERVER:vm1234.config.RAM' is not expected but is set to '2000'");
|
"'CLOUD_SERVER:vm1234.config.RAM' is not expected but is set to '2000'");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,14 +84,14 @@ class HsCloudServerHostingAssetValidatorUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void validatesParentAndAssignedToAssetMustNotBeSet() {
|
void rejectsInvalidReferencedEntities() {
|
||||||
// given
|
// given
|
||||||
final var mangedServerHostingAssetEntity = HsHostingAssetEntity.builder()
|
final var mangedServerHostingAssetEntity = HsHostingAssetEntity.builder()
|
||||||
.type(CLOUD_SERVER)
|
.type(CLOUD_SERVER)
|
||||||
.identifier("xyz00")
|
.identifier("vm1234")
|
||||||
.parentAsset(HsHostingAssetEntity.builder().build())
|
|
||||||
.assignedToAsset(HsHostingAssetEntity.builder().build())
|
|
||||||
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
|
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
|
||||||
|
.parentAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build())
|
||||||
|
.assignedToAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build())
|
||||||
.build();
|
.build();
|
||||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ class HsCloudServerHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrder(
|
assertThat(result).containsExactlyInAnyOrder(
|
||||||
"'CLOUD_SERVER:xyz00.parentAsset' must be null but is set to D-???????-?:null",
|
"'CLOUD_SERVER:vm1234.parentAsset' must be null but is of type MANAGED_SERVER",
|
||||||
"'CLOUD_SERVER:xyz00.assignedToAsset' must be null but is set to D-???????-?:null");
|
"'CLOUD_SERVER:vm1234.assignedToAsset' must be null but is of type CLOUD_SERVER");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
|
|||||||
return HsHostingAssetEntity.builder()
|
return HsHostingAssetEntity.builder()
|
||||||
.type(DOMAIN_DNS_SETUP)
|
.type(DOMAIN_DNS_SETUP)
|
||||||
.parentAsset(validDomainSetupEntity)
|
.parentAsset(validDomainSetupEntity)
|
||||||
.identifier("example.org")
|
.identifier("example.org|DNS")
|
||||||
.config(Map.ofEntries(
|
.config(Map.ofEntries(
|
||||||
entry("user-RR", Array.of(
|
entry("user-RR", Array.of(
|
||||||
"@ 1814400 IN XXX example.org. root.example.org ( 1234 10800 900 604800 86400 )",
|
"@ 1814400 IN XXX example.org. root.example.org ( 1234 10800 900 604800 86400 )",
|
||||||
@ -74,19 +74,20 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
|
|||||||
void preprocessesTakesIdentifierFromParent() {
|
void preprocessesTakesIdentifierFromParent() {
|
||||||
// given
|
// given
|
||||||
final var givenEntity = validEntityBuilder().build();
|
final var givenEntity = validEntityBuilder().build();
|
||||||
|
assertThat(givenEntity.getParentAsset().getIdentifier()).as("preconditon failed").isEqualTo("example.org");
|
||||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
validator.preprocessEntity(givenEntity);
|
validator.preprocessEntity(givenEntity);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(givenEntity.getIdentifier()).isEqualTo(givenEntity.getParentAsset().getIdentifier());
|
assertThat(givenEntity.getIdentifier()).isEqualTo("example.org|DNS");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void rejectsInvalidIdentifier() {
|
void rejectsInvalidIdentifier() {
|
||||||
// given
|
// given
|
||||||
final var givenEntity = validEntityBuilder().identifier("wrong.org").build();
|
final var givenEntity = validEntityBuilder().identifier("example.org").build();
|
||||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -94,14 +95,14 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactly(
|
assertThat(result).containsExactly(
|
||||||
"'identifier' expected to match '^example.org$', but is 'wrong.org'"
|
"'identifier' expected to match '^example.org\\Q|DNS\\E$', but is 'example.org'"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void acceptsValidIdentifier() {
|
void acceptsValidIdentifier() {
|
||||||
// given
|
// given
|
||||||
final var givenEntity = validEntityBuilder().identifier(validDomainSetupEntity.getIdentifier()).build();
|
final var givenEntity = validEntityBuilder().identifier(validDomainSetupEntity.getIdentifier()+"|DNS").build();
|
||||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -112,12 +113,12 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void validatesReferencedEntities() {
|
void rejectsInvalidReferencedEntities() {
|
||||||
// given
|
// given
|
||||||
final var mangedServerHostingAssetEntity = validEntityBuilder()
|
final var mangedServerHostingAssetEntity = validEntityBuilder()
|
||||||
.parentAsset(HsHostingAssetEntity.builder().build())
|
|
||||||
.assignedToAsset(HsHostingAssetEntity.builder().build())
|
|
||||||
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
|
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
|
||||||
|
.parentAsset(null)
|
||||||
|
.assignedToAsset(HsHostingAssetEntity.builder().type(DOMAIN_SETUP).build())
|
||||||
.build();
|
.build();
|
||||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
||||||
|
|
||||||
@ -126,9 +127,9 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrder(
|
assertThat(result).containsExactlyInAnyOrder(
|
||||||
"'DOMAIN_DNS_SETUP:example.org.bookingItem' must be null but is set to D-???????-?:null",
|
"'DOMAIN_DNS_SETUP:example.org|DNS.bookingItem' must be null but is of type CLOUD_SERVER",
|
||||||
"'DOMAIN_DNS_SETUP:example.org.parentAsset' must be of type DOMAIN_SETUP but is of type null",
|
"'DOMAIN_DNS_SETUP:example.org|DNS.parentAsset' must be of type DOMAIN_SETUP but is null",
|
||||||
"'DOMAIN_DNS_SETUP:example.org.assignedToAsset' must be null but is set to D-???????-?:null");
|
"'DOMAIN_DNS_SETUP:example.org|DNS.assignedToAsset' must be null but is of type DOMAIN_SETUP");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -162,9 +163,9 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrder(
|
assertThat(result).containsExactlyInAnyOrder(
|
||||||
"'DOMAIN_DNS_SETUP:example.org.config.TTL' is expected to be of type class java.lang.Integer, but is of type 'String'",
|
"'DOMAIN_DNS_SETUP:example.org|DNS.config.TTL' is expected to be of type class java.lang.Integer, but is of type 'String'",
|
||||||
"'DOMAIN_DNS_SETUP:example.org.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 '@ 1814400 IN 1814400 BAD1 TTL only allowed once' does not match any",
|
||||||
"'DOMAIN_DNS_SETUP:example.org.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-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");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -12,6 +12,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
class HsDomainSetupHostingAssetValidatorUnitTest {
|
class HsDomainSetupHostingAssetValidatorUnitTest {
|
||||||
@ -93,8 +94,8 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
|
|||||||
void validatesReferencedEntities() {
|
void validatesReferencedEntities() {
|
||||||
// given
|
// given
|
||||||
final var mangedServerHostingAssetEntity = validEntityBuilder()
|
final var mangedServerHostingAssetEntity = validEntityBuilder()
|
||||||
.parentAsset(HsHostingAssetEntity.builder().build())
|
.parentAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build())
|
||||||
.assignedToAsset(HsHostingAssetEntity.builder().build())
|
.assignedToAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build())
|
||||||
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
|
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
|
||||||
.build();
|
.build();
|
||||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
||||||
@ -104,8 +105,8 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrder(
|
assertThat(result).containsExactlyInAnyOrder(
|
||||||
"'DOMAIN_SETUP:example.org.bookingItem' must be null but is set to D-???????-?:null",
|
"'DOMAIN_SETUP:example.org.bookingItem' must be null but is of type CLOUD_SERVER",
|
||||||
"'DOMAIN_SETUP:example.org.parentAsset' must be null but is set to D-???????-?:null",
|
"'DOMAIN_SETUP:example.org.parentAsset' must be null or of type DOMAIN_SETUP but is of type CLOUD_SERVER",
|
||||||
"'DOMAIN_SETUP:example.org.assignedToAsset' must be null but is set to D-???????-?:null");
|
"'DOMAIN_SETUP:example.org.assignedToAsset' must be null but is of type MANAGED_SERVER");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,8 +107,8 @@ class HsEMailAliasHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrder(
|
assertThat(result).containsExactlyInAnyOrder(
|
||||||
"'EMAIL_ALIAS:abc00-office.bookingItem' must be null but is set to D-1234500:test project:test project booking item",
|
"'EMAIL_ALIAS:abc00-office.bookingItem' must be null but is of type MANAGED_SERVER",
|
||||||
"'EMAIL_ALIAS:abc00-office.parentAsset' must be of type MANAGED_WEBSPACE but is of type MANAGED_SERVER",
|
"'EMAIL_ALIAS:abc00-office.parentAsset' must be of type MANAGED_WEBSPACE but is of type MANAGED_SERVER",
|
||||||
"'EMAIL_ALIAS:abc00-office.assignedToAsset' must be null but is set to D-1234500:test project:test project booking item");
|
"'EMAIL_ALIAS:abc00-office.assignedToAsset' must be null but is of type MANAGED_SERVER");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import java.util.Map;
|
|||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.TEST_CLOUD_SERVER_BOOKING_ITEM;
|
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.TEST_CLOUD_SERVER_BOOKING_ITEM;
|
||||||
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.TEST_MANAGED_SERVER_BOOKING_ITEM;
|
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.TEST_MANAGED_SERVER_BOOKING_ITEM;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@ -22,8 +23,8 @@ class HsManagedServerHostingAssetValidatorUnitTest {
|
|||||||
.type(MANAGED_SERVER)
|
.type(MANAGED_SERVER)
|
||||||
.identifier("vm1234")
|
.identifier("vm1234")
|
||||||
.bookingItem(TEST_MANAGED_SERVER_BOOKING_ITEM)
|
.bookingItem(TEST_MANAGED_SERVER_BOOKING_ITEM)
|
||||||
.parentAsset(HsHostingAssetEntity.builder().build())
|
.parentAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build())
|
||||||
.assignedToAsset(HsHostingAssetEntity.builder().build())
|
.assignedToAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build())
|
||||||
.config(Map.ofEntries(
|
.config(Map.ofEntries(
|
||||||
entry("monit_max_hdd_usage", "90"),
|
entry("monit_max_hdd_usage", "90"),
|
||||||
entry("monit_max_cpu_usage", 2),
|
entry("monit_max_cpu_usage", 2),
|
||||||
@ -37,8 +38,8 @@ class HsManagedServerHostingAssetValidatorUnitTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrder(
|
assertThat(result).containsExactlyInAnyOrder(
|
||||||
"'MANAGED_SERVER:vm1234.parentAsset' must be null but is set to D-1234500:test project:test project booking item",
|
"'MANAGED_SERVER:vm1234.parentAsset' must be null but is of type CLOUD_SERVER",
|
||||||
"'MANAGED_SERVER:vm1234.assignedToAsset' must be null but is set to D-1234500:test project:test project booking item",
|
"'MANAGED_SERVER:vm1234.assignedToAsset' must be null but is of type CLOUD_SERVER",
|
||||||
"'MANAGED_SERVER:vm1234.config.monit_max_cpu_usage' is expected to be at least 10 but is 2",
|
"'MANAGED_SERVER:vm1234.config.monit_max_cpu_usage' is expected to be at least 10 but is 2",
|
||||||
"'MANAGED_SERVER:vm1234.config.monit_max_ram_usage' is expected to be at most 100 but is 101",
|
"'MANAGED_SERVER:vm1234.config.monit_max_ram_usage' is expected to be at most 100 but is 101",
|
||||||
"'MANAGED_SERVER:vm1234.config.monit_max_hdd_usage' is expected to be of type class java.lang.Integer, but is of type 'String'");
|
"'MANAGED_SERVER:vm1234.config.monit_max_hdd_usage' is expected to be of type class java.lang.Integer, but is of type 'String'");
|
||||||
@ -63,14 +64,14 @@ class HsManagedServerHostingAssetValidatorUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void validatesParentAndAssignedToAssetMustNotBeSet() {
|
void rejectsInvalidReferencedEntities() {
|
||||||
// given
|
// given
|
||||||
final var mangedServerHostingAssetEntity = HsHostingAssetEntity.builder()
|
final var mangedServerHostingAssetEntity = HsHostingAssetEntity.builder()
|
||||||
.type(MANAGED_SERVER)
|
.type(MANAGED_SERVER)
|
||||||
.identifier("xyz00")
|
.identifier("xyz00")
|
||||||
.parentAsset(HsHostingAssetEntity.builder().build())
|
|
||||||
.assignedToAsset(HsHostingAssetEntity.builder().build())
|
|
||||||
.bookingItem(TEST_CLOUD_SERVER_BOOKING_ITEM)
|
.bookingItem(TEST_CLOUD_SERVER_BOOKING_ITEM)
|
||||||
|
.parentAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build())
|
||||||
|
.assignedToAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build())
|
||||||
.build();
|
.build();
|
||||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ class HsManagedServerHostingAssetValidatorUnitTest {
|
|||||||
// then
|
// then
|
||||||
assertThat(result).containsExactlyInAnyOrder(
|
assertThat(result).containsExactlyInAnyOrder(
|
||||||
"'MANAGED_SERVER:xyz00.bookingItem' must be of type MANAGED_SERVER but is of type CLOUD_SERVER",
|
"'MANAGED_SERVER:xyz00.bookingItem' must be of type MANAGED_SERVER but is of type CLOUD_SERVER",
|
||||||
"'MANAGED_SERVER:xyz00.parentAsset' must be null but is set to D-1234500:test project:test cloud server booking item",
|
"'MANAGED_SERVER:xyz00.parentAsset' must be null but is of type CLOUD_SERVER",
|
||||||
"'MANAGED_SERVER:xyz00.assignedToAsset' must be null but is set to D-1234500:test project:test cloud server booking item");
|
"'MANAGED_SERVER:xyz00.assignedToAsset' must be null but is of type MANAGED_SERVER");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import java.util.Map;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
||||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
|
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static net.hostsharing.hsadminng.hs.booking.project.TestHsBookingProject.TEST_PROJECT;
|
import static net.hostsharing.hsadminng.hs.booking.project.TestHsBookingProject.TEST_PROJECT;
|
||||||
@ -142,7 +143,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void validatesEntityReferences() {
|
void rejectsInvalidEntityReferences() {
|
||||||
// given
|
// given
|
||||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE);
|
final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE);
|
||||||
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
|
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
|
||||||
@ -153,7 +154,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
|
|||||||
.resources(Map.ofEntries(entry("SSD", 25), entry("Traffic", 250)))
|
.resources(Map.ofEntries(entry("SSD", 25), entry("Traffic", 250)))
|
||||||
.build())
|
.build())
|
||||||
.parentAsset(cloudServerAssetEntity)
|
.parentAsset(cloudServerAssetEntity)
|
||||||
.assignedToAsset(HsHostingAssetEntity.builder().build())
|
.assignedToAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build())
|
||||||
.identifier("abc00")
|
.identifier("abc00")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
|
|||||||
// then
|
// then
|
||||||
assertThat(result).containsExactly(
|
assertThat(result).containsExactly(
|
||||||
"'MANAGED_WEBSPACE:abc00.bookingItem' must be of type MANAGED_WEBSPACE but is of type MANAGED_SERVER",
|
"'MANAGED_WEBSPACE:abc00.bookingItem' must be of type MANAGED_WEBSPACE but is of type MANAGED_SERVER",
|
||||||
"'MANAGED_WEBSPACE:abc00.parentAsset' must be of type MANAGED_SERVER but is of type CLOUD_SERVER",
|
"'MANAGED_WEBSPACE:abc00.parentAsset' must be null or of type MANAGED_SERVER but is of type CLOUD_SERVER",
|
||||||
"'MANAGED_WEBSPACE:abc00.assignedToAsset' must be null but is set to D-???????-?:some ManagedServer");
|
"'MANAGED_WEBSPACE:abc00.assignedToAsset' must be null but is of type CLOUD_SERVER");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||||
import static org.junit.jupiter.api.condition.OS.LINUX;
|
import static org.junit.jupiter.api.condition.OS.LINUX;
|
||||||
|
|
||||||
class SystemProcessTest {
|
class SystemProcessUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@EnabledOnOs(LINUX)
|
@EnabledOnOs(LINUX)
|
Loading…
Reference in New Issue
Block a user
überprüfen: was soll das bedeuten?
Das ist die Validierung der Multi-Optionen. Also ganz richtig so.